Warning: file_get_contents(/data/phpspider/zhask/data//catemap/1/php/259.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Php 如何使用cron作业调度动态功能?_Php_Mysql_Cron_Cron Task - Fatal编程技术网

Php 如何使用cron作业调度动态功能?

Php 如何使用cron作业调度动态功能?,php,mysql,cron,cron-task,Php,Mysql,Cron,Cron Task,我想知道我如何安排一个动态(自动填充数据)功能每天以节省的时间自动运行 假设我有一个表单,单击按钮后,它会将数据发送到函数,函数会发布数据。我只是想让它自动化,这样我就不必按下按钮了 <ul> <?php foreach($Class->retrieveData as $data) { <form method="post" action=""> <li>

我想知道我如何安排一个动态(自动填充数据)功能每天以节省的时间自动运行

假设我有一个表单,单击按钮后,它会将数据发送到函数,函数会发布数据。我只是想让它自动化,这样我就不必按下按钮了

<ul>
    <?php 
    foreach($Class->retrieveData as $data)
    {
        <form method="post" action="">
            <li>
                <input type="hidden" name="name">'.$data['name'].'<br/>
                <input type="hidden" name="description">'.$data['description'].'<br/>
                <input type="submit" name="post_data"  value="Post">
            </li>
        </form>
    }
    ?>
</ul>
我尝试了以下操作,但问题是Cron作业只能运行整个.php文件,我正在从MySQL检索节省下来的运行时间

foreach($Class->getTime() as $timeData)
{
    $timeHour    = $timeData['timeHour'];
    $timeMinute = $timeData['timeMinute'];

    $hourMin    = date('H:i');
    $timeData   = ''.$timeHour.':'.$timeMinute.'';

    if($hourMin == $timeData)
    {
        run myFunction.
    }
}
$hourMin
是当前小时:分钟,它与从Mysql自动运行所节省的时间相匹配。因此,如果
$hourMin==$timeData
,则函数将运行

如果
$hourMin
等于
$timeData
,如何运行Cron作业以自动运行
myFunction()

所以

10am、12pm、2pm
是从MySQL检索的基于每个列表id的
$timeHour
$timeMinute

编辑 @randomSeed,

1) I can schedule cron jobs.
2) $name and $description will all be arrays, so the following is what I am trying to accomplish.

$name = array(
    'Jon',
    'Steven',
    'Carter'
);

$description = array(
    'Jon is a great person.',
    'Steven has an outgoing character.',
    'Carter is a horrible person.'
);
如果计划的时间正确,我想从$name和$description解析第一个数组

在数据库中,我有以下内容

postDataTime table

+----+---------+----------+------------+--------+
| iD | timeDay | timeHour | timeMinute | postiD |
+--------------------------------------+--------+
| 1  | *       | 9        | 0          | 21     |
|----|---------|----------|------------|--------|
| 2  | *       | 10       | 30         | 22     |
|----|---------|----------|------------|--------|
| 3  | *       | 11       | 0          | 23     |
+----|---------+----------+------------+--------+

iD         = auto incremented on upload.
timeDay    = * is everyday (cron job style)
timeHour   = Hour of the day to run the script
timeMinute = minute of the hour to run script
postiD     = this is the id of the post that is located in another table (n+1 relationship)
如果很难理解

我只是想根据保存到MySQL的时间安排一切,正如我在最上面(postDataTime表)所示。(我会展示我已经尝试过的东西,但我已经花了无数个小时寻找我正在尝试完成的事情的例子,但我找不到任何东西,我尝试过的东西也不起作用。)

我想我可以使用exec()函数,但从它看来不允许我运行函数,否则我将执行以下操作

$time = '10:30';
if($time == time())
{
    exec(myFunction());
}

如果我理解正确,我认为这样的方法可能适合您,使用小时数作为要运行的函数的键,在cron集合中每两小时运行一次:

$listArray = Array(8=>"list1_function",10=>"list2_function");//etc...
$hour = Date("G");

if(array_key_exists($hour,$listArray))
{
    $listArray[$hour]();
}

function list1_function()
{
     echo "do list 1 stuff";
}

function list2_function()
{
     echo "do list 2 stuff";
 }

Cron任务需要您预先设置它们运行的时间,但它们不能(是的,您可以通过使用编辑crontab的脚本来解决这个问题,但我不认为这是一个非常好的主意)动态地确定它们的运行时间。这意味着您基本上有两种选择:

1) 将cronjob设置为每分钟运行一次,并使用您触摸的临时文件告知上次运行计划任务的时间,每次运行时检查临时文件的最后时间戳和当前时间之间是否有要运行的任务,以及是否有要运行的任务。这是一个粗略但简单的解决方案


2) 不要使用cron。创建一个守护进程,检查任务需要运行的时间,并将它们放入优先级队列,然后弹出最早的元素并休眠,直到运行该任务为止。它运行任务并重新插入,以便在未来24小时内运行并重复。这个解决方案要优雅得多,但也需要更多的工作。

可以设置一个每分钟运行一次的cron作业,并在触发时检查该时刻安排了哪些作业

这是一个简单的想法,如果您需要,可以很容易地进行修改,以推送特定脚本的运行时详细信息:-

<?php

include '/core/config.php');

// Test script to allow jobs to be set up (cron style) on a database, but with the addition that jobs can be made
// dependent on other jobs completing first.
// Currently does not support jobs being dependent on more than one parent job.
// It uses a database of 2 tables. One for servers and the other for jobs.
// The server is selected as the one that matches the value of php_uname('n') (hence this can be run on many servers accessing a single database and only executing jobs for the particular server an instance is running on)
// Time ranges are specified in the same way as on CRON jobs:-
//  *   = no restriction based on that field
//  x   = when the value of that time parameter matches x
//  /x  = every x of that field (ie, mod current of that field by x and match if result is 0)
//  x-y = when the value of that time parameter is between x and y
//  x,y = when the value of the time parameter matches x or y (or z, etc)
// The script field on the scheduling table contains the script / command to be executed. For example if a php script then it might be 'php /usr/webdata/cron_scripts/some_script.php
// Parentid is the id of a job that must have finished before the job is executed.

class scheduling extends core_class
{

    public $connections;
    private $db;

    private $year;
    private $month;
    private $day;
    private $hour;
    private $minute;
    private $second;
    private $day_of_week;
    private $background_kick_off = true;

    private $completed_jobs = array();

    function __construct($connections, $background_kick_off = true) 
    {
        parent::__construct($connections);

        $this->background_kick_off = $background_kick_off;

        $this->debug_time_start();

        $this->connections = $connections;
        $this->db = new database($connections['EO'], 'em_scheduling');
        if (!$this->db->no_error)
            $this->error('E_ERROR', $this->db->error());

        $run_date = date('Y/m/d H:i:s w');

        list($date_part, $time_part, $this->day_of_week) = explode(' ', $run_date);
        list($this->year, $this->month, $this->day) = explode('/', $date_part);
        list($this->hour, $this->minute, $this->second) = explode(':', $time_part);     

        $this->find_jobs(0);
    }

    function find_jobs($parent_id)
    {
        $sql = "SELECT a.id, a.script, a.parent_id, a.minutes, a.hours, a.day_of_month, a.months, a.day_of_week, a.script_description, COUNT(DISTINCT b.id) AS child_count
                FROM scheduling a
                ON s.id = a.server_id
                LEFT OUTER JOIN scheduling b
                ON a.id = b.parent_id
                AND b.enabled = 1
                AND (b.minutes = '*' OR FIND_IN_SET('".$this->minute."', b.minutes) OR (SUBSTR(b.minutes, 1, 1) = '/' AND (".$this->minute." % CAST(SUBSTR(b.minutes, 2) AS UNSIGNED)) = 0) OR (b.minutes LIKE '%-%' AND ".$this->minute." BETWEEN CAST(SUBSTRING_INDEX(b.minutes, '-', 1) AS UNSIGNED) AND CAST(SUBSTRING_INDEX(b.minutes, '-', -1) AS UNSIGNED)))
                AND (b.hours = '*' OR FIND_IN_SET('".$this->hour."', b.hours) OR (SUBSTR(b.hours, 1, 1) = '/' AND (".$this->hour." % CAST(SUBSTR(b.hours, 2) AS UNSIGNED)) = 0) OR (b.hours LIKE '%-%' AND ".$this->hour." BETWEEN CAST(SUBSTRING_INDEX(b.hours, '-', 1) AS UNSIGNED) AND CAST(SUBSTRING_INDEX(b.hours, '-', -1) AS UNSIGNED)))
                AND (b.months = '*' OR FIND_IN_SET('".$this->month."', b.months) OR (SUBSTR(b.months, 1, 1) = '/' AND (".$this->month." % CAST(SUBSTR(b.months, 2) AS UNSIGNED)) = 0) OR (b.months LIKE '%-%' AND ".$this->month." BETWEEN CAST(SUBSTRING_INDEX(b.months, '-', 1) AS UNSIGNED) AND CAST(SUBSTRING_INDEX(b.months, '-', -1) AS UNSIGNED)))
                AND ((b.day_of_month = '*' OR FIND_IN_SET('".$this->day."', b.day_of_month) OR (SUBSTR(b.day_of_month, 1, 1) = '/' AND (".$this->day." % CAST(SUBSTR(b.day_of_month, 2) AS UNSIGNED)) = 0) OR (b.day_of_month LIKE '%-%' AND ".$this->day." BETWEEN CAST(SUBSTRING_INDEX(b.day_of_month, '-', 1) AS UNSIGNED) AND CAST(SUBSTRING_INDEX(b.day_of_month, '-', -1) AS UNSIGNED)))
                OR (b.day_of_week = '*' OR FIND_IN_SET('".$this->day_of_week."', b.day_of_week) OR (SUBSTR(b.day_of_week, 1, 1) = '/' AND (".$this->day_of_week." % CAST(SUBSTR(b.day_of_week, 2) AS UNSIGNED)) = 0) OR (b.day_of_week LIKE '%-%' AND ".$this->day_of_week." BETWEEN CAST(SUBSTRING_INDEX(b.day_of_week, '-', 1) AS UNSIGNED) AND CAST(SUBSTRING_INDEX(b.day_of_week, '-', -1) AS UNSIGNED))))
                WHERE a.parent_id = ".(int)$parent_id."
                AND a.enabled = 1
                AND (a.minutes = '*' OR FIND_IN_SET('".$this->minute."', a.minutes) OR (SUBSTR(a.minutes, 1, 1) = '/' AND (".$this->minute." % CAST(SUBSTR(a.minutes, 2) AS UNSIGNED)) = 0) OR (a.minutes LIKE '%-%' AND ".$this->minute." BETWEEN CAST(SUBSTRING_INDEX(a.minutes, '-', 1) AS UNSIGNED) AND CAST(SUBSTRING_INDEX(a.minutes, '-', -1) AS UNSIGNED)))
                AND (a.hours = '*' OR FIND_IN_SET('".$this->hour."', a.hours) OR (SUBSTR(a.hours, 1, 1) = '/' AND (".$this->hour." % CAST(SUBSTR(a.hours, 2) AS UNSIGNED)) = 0) OR (a.hours LIKE '%-%' AND ".$this->hour." BETWEEN CAST(SUBSTRING_INDEX(a.hours, '-', 1) AS UNSIGNED) AND CAST(SUBSTRING_INDEX(a.hours, '-', -1) AS UNSIGNED)))
                AND (a.months = '*' OR FIND_IN_SET('".$this->month."', a.months) OR (SUBSTR(a.months, 1, 1) = '/' AND (".$this->month." % CAST(SUBSTR(a.months, 2) AS UNSIGNED)) = 0) OR (a.months LIKE '%-%' AND ".$this->month." BETWEEN CAST(SUBSTRING_INDEX(a.months, '-', 1) AS UNSIGNED) AND CAST(SUBSTRING_INDEX(a.months, '-', -1) AS UNSIGNED)))
                AND ((a.day_of_month = '*' OR FIND_IN_SET('".$this->day."', a.day_of_month) OR (SUBSTR(a.day_of_month, 1, 1) = '/' AND (".$this->day." % CAST(SUBSTR(a.day_of_month, 2) AS UNSIGNED)) = 0) OR (a.day_of_month LIKE '%-%' AND ".$this->day." BETWEEN CAST(SUBSTRING_INDEX(a.day_of_month, '-', 1) AS UNSIGNED) AND CAST(SUBSTRING_INDEX(a.day_of_month, '-', -1) AS UNSIGNED)))
                OR (a.day_of_week = '*' OR FIND_IN_SET('".$this->day_of_week."', a.day_of_week) OR (SUBSTR(a.day_of_week, 1, 1) = '/' AND (".$this->day_of_week." % CAST(SUBSTR(a.day_of_week, 2) AS UNSIGNED)) = 0) OR (a.day_of_week LIKE '%-%' AND ".$this->day_of_week." BETWEEN CAST(SUBSTRING_INDEX(a.day_of_week, '-', 1) AS UNSIGNED) AND CAST(SUBSTRING_INDEX(a.day_of_week, '-', -1) AS UNSIGNED))))
                GROUP BY a.id, a.script, a.parent_id, a.minutes, a.hours, a.day_of_month, a.months, a.day_of_week
                ORDER BY child_count
                ";

        //echo "\r\n $sql \r\n";

        $this->db->query($sql) or die($this->db->error());

        $process_array = array();

        while ($row = $this->db->fetch_assoc())
        {
            $process_array[] = $row;
        }   

        foreach($process_array as $aProcess)
        {
            if ($this->background_kick_off and $aProcess['child_count'] == 0)
            {
                // No jobs to follow so just kick them off as a background task
                $this->launchBackgroundProcess($aProcess['script']);
                $completed_jobs[$aProcess['id']] = $aProcess['script_description'];
            }
            else
            {
                passthru($aProcess['script'].'', $return_var);
                if ($return_var == 0)
                {
                    $completed_jobs[$aProcess['id']] = $aProcess['script_description'];
                    $this->find_jobs($aProcess['id']);
                }
            }
        }
    }

    private function launchBackgroundProcess($call) 
    {

        // Windows
        if($this->is_windows())
        {
            pclose(popen('start /b '.$call, 'r'));
        }

        // Some sort of UNIX
        else 
        {
            pclose(popen($call.' /dev/null &', 'r'));
        }
        return true;
    }

    private function is_windows()
    {
        if(PHP_OS == 'WINNT' || PHP_OS == 'WIN32')
        {
            return true;
        }
        return false;
    }
}

$Scheduling = new scheduling($connections, true);

?>

我建议您通过一个包装器脚本动态创建Cron条目,该脚本将Cron条目配置为在实际需要时运行特定函数

对于您的具体情况,我建议如下:

  • 创建一个包装器脚本,并在Cron中安排它每秒运行一次
  • 这个包装器脚本将与MySQL对话并获取特定函数运行的时间
  • 然后,它将动态创建一个Cron条目,以在特定的检索时间戳运行该函数。您可以使用shell脚本动态添加和删除Cron条目。详情请参见下面的参考资料
  • 函数完成后,应该会有一些指示,比如存储在数据库或文件中的状态,以便包装器可以获取/了解状态并删除相应的cron条目
  • 参考资料
    1.
    crontab-l{cat;echo“0一些条目”}
    
    2.
    crontab-l-u | grep-v | crontab-

    你有两种方法,尽管只有一种方法能完全满足你的需求

    • 第1种方式要求您具有更改cron作业服务器端的访问权限和特权(例如通过PHP或其他方式)。取决于有哪些操作系统教程:

    • 第二种方式将做一些接近您想要做的事情,但是如果没有分钟精度,您将在每个循环中最多放松2分钟。(见下面的解释)

    第一路完美之路
    • 一旦用户点击表单,就使用所需的数据时间为该用户创建一个唯一的cron任务
    如果您没有这些特权,您可以使用3d零件服务,如 他们还提供了一个免费的版本,但有一定的限制 查询它们还提供了一种管理(原油)的方法 cron任务

    第二条路不完美的路
    • 添加一个新的
      VARCHAR
      列,我今天称它为
    -

    • 然后创建一个php文件,我称之为
      crontask.php
      ,我们将每5分钟调用一次

    • 将此添加到您的cronjob面板:

    • 0,5****/usr/bin/php/www/virtual/username/crontask.php>/dev/null 2>&1

    • crontask.php
      文件中

    -

    当脚本检查这些时间时,它将按如下方式运行:

    at 20:05 -> run 20:05 Jonh, 20:06 Jimmy
    at 20:10 -> run null
    at 20:15 -> run 20:16 Eddy
    at 20:20 -> run null
    and so on....
    

    正如您所见,在最坏的情况下,您每次都会放松2分钟。我认为这很公平!;)

    使用nodeJS,使用
    节点调度
    解决了问题:

    启动自定义作业:

      const campaignId = "MY_CUSTOM_ID"
      let job = schedule.scheduleJob(campaignId, '* * * * * *', function () {
        console.log('running campaign: ' + campaignId)
      })
    
      const campaignId = "MY_CUSTOM_ID"
      let current_job = schedule.scheduledJobs[campaignId]
      current_job.cancel()
    
    停止自定义作业:

      const campaignId = "MY_CUSTOM_ID"
      let job = schedule.scheduleJob(campaignId, '* * * * * *', function () {
        console.log('running campaign: ' + campaignId)
      })
    
      const campaignId = "MY_CUSTOM_ID"
      let current_job = schedule.scheduledJobs[campaignId]
      current_job.cancel()
    

    为了让某些东西每天运行并依靠PHP和/或SQL来执行此操作,需要运行CRON
    <?php
    // include() Database Config file here with mysql_connect etc...
    // include() the required files ex. the file where myFunction reside...
    
    $cron_cycle = 5; // set it equal to what used in cron command-line
    $today = date('Y-m-d');
    if($result = mysql_query("SELECT * FROM postDataTime WHERE today != '{$today}'")){
        while ($row = mysql_fetch_array($result, MYSQL_ASSOC)) { 
            $postID = $row['postID'];
            $timeHour = (int) $row['timeHour'];
            $current_hours = (int) date('H'); // current hours
            $current_minutes = (int) date('i'); // current minutes
            $timeMinute = (int) $row['timeMinute'];
            // force to run at the closest cycle
            $timeMinute = ($timeMinute % $cycle === 0) ? $timeMinute : toCloser($timeMinute, $cron_cycle); 
            if( $current_hours === $timeHour && $current_minutes === $timeMinute ){
                // ensure that we have already runned a cron for this user...
                mysql_query("UPDATE postDataTime SET today = '{$today}' WHERE postID = '{$postID}'");
                myFunction($postID);
            }
        }
    }
    function toCloser($n,$x=5) {
        $j = (round($n)%$x === 0) ? round($n) : (round(($n+$x/2)/$x)*$x);
        return ($j-$n) >= round($x/2) ? ($j-$x) : $j;
    }
    
    ?>
    
    Jonh  : 20:05, 
    Mario : 20:32, 
    luke  : 20:48, 
    David : 20:57, 
    Jimmy : 20:06, 
    Eddy  : 20:16
    
    at 20:05 -> run 20:05 Jonh, 20:06 Jimmy
    at 20:10 -> run null
    at 20:15 -> run 20:16 Eddy
    at 20:20 -> run null
    and so on....
    
      const campaignId = "MY_CUSTOM_ID"
      let job = schedule.scheduleJob(campaignId, '* * * * * *', function () {
        console.log('running campaign: ' + campaignId)
      })
    
      const campaignId = "MY_CUSTOM_ID"
      let current_job = schedule.scheduledJobs[campaignId]
      current_job.cancel()