php - script - ¿Cómo programar la función dinámica con el trabajo cron?
cómo ejecutar el cron glpi (5)
Quiero saber cómo puedo programar una función dinámica (datos poblados automáticamente) para que se ejecute automáticamente todos los días a la hora guardada.
Digamos que tengo un formulario que una vez que se hace clic en el botón envía los datos a la función, que los mensajes de los datos. Simplemente quiero automatizar eso para no tener que presionar el botón.
<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>
Ahora, el formulario pasará los datos a la función.
if(isset($_POST[''post_data''])) // if post_data button is clicked then it runs myFunction()
{
myFunction();
}
myFunction()
{
$name = $_POST[''name''];
$description = $_POST[''description''];
}
Intenté hacer lo siguiente, pero el problema es que Cron Job solo puede ejecutar todo el archivo .php, y estoy recuperando el tiempo guardado para ejecutarlo desde 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
es la hora actual: minuto que se $hourMin
con un tiempo guardado para ejecutarse automáticamente desde Mysql. Entonces, si $hourMin == $timeData
, la función se ejecutará.
¿Cómo puedo ejecutar Cron Job para ejecutar automáticamente myFunction()
si $hourMin
equivale a $timeData
?
Asi que...
List 1 = is to be runned at 10am
List 2 = is to be runned at 12pm
List 3 = is to be runned at 2pm
Las 10am, 12pm, 2pm
las $timeHour
10am, 12pm, 2pm
$timeHour
son los $timeHour
y $timeMinute
que se recuperan de MySQL, pero se basan en las identificaciones de cada lista.
EDITAR
@Semilla aleatoria,
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.''
);
Quiero analizar las primeras matrices de $ nombre y $ descripción si la hora programada es correcta.
En la base de datos tengo lo siguiente
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)
Si es difícil de entender ... ¿qué es la quinua?
if(time() == 10:30(time from MySQL postiD = 22))
{
// run myFunction with the data that is retrieved for that time ex:
$postiD = ''22'';
$name = ''Steven'';
$description = ''Steven has an outgoing character.'';
// the above is what will be in the $_POST from the form and will be
// sent to the myFunction()
}
Simplemente quiero programar todo de acuerdo con el tiempo que se guarda en MySQL, como mostré en la parte superior (tabla de PostDataTime). (Mostraría lo que probé, pero he buscado incontables horas para dar un ejemplo de lo que intento lograr, pero no encuentro nada y lo que probé no funciona).
Pensé que podría usar la función exec () pero de lo que parece que no me permite ejecutar funciones, de lo contrario haría lo siguiente ...
$time = ''10:30'';
if($time == time())
{
exec(myFunction());
}
Si entiendo correctamente, creo que algo como esto puede funcionar para usted, utilizando las horas como claves para la función que desea ejecutar, en un cron configurado para ejecutarse cada dos horas:
$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";
}
Las tareas de cron requieren que establezcas los tiempos en que se ejecutan, no pueden (sí, puedes piratear esto teniendo un script que edita tu crontab, pero no diría que es una muy buena idea) tener su tiempo para correr decidido dinámicamente. Esto significa que esencialmente tienes dos opciones:
1) Configure un cronjob para que se ejecute cada minuto y use un archivo temporal que toque para indicar la última vez que ejecutó una de las tareas programadas. Cada vez que se ejecuta, comprueba si hubo una tarea para ejecutar entre la última marca de tiempo de su archivo temporal y la hora actual, y si lo hay, ejecuta la tarea. Esta es una solución burda pero simple.
2) No use cron. Cree un daemon que compruebe en qué tiempos se deben ejecutar las tareas y las coloca en una cola de prioridad, luego muestra el elemento más antiguo y duerme hasta que sea el momento de ejecutar esa tarea. Ejecuta la tarea y la reinserta para que se ejecute 24 horas en el futuro y se repita. Esta solución es mucho más elegante, pero también requiere más trabajo.
Es posible configurar un trabajo cron que se ejecute cada minuto y cuando se active, comprueba qué tareas están programadas para ese momento.
Como una idea simple que podría modificarse fácilmente para avanzar por los detalles del tiempo de ejecución para un script en particular si usted quisiera: -
<?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);
?>
Tablas como esta:
CREATE TABLE IF NOT EXISTS `scheduling` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`enabled` tinyint(1) NOT NULL DEFAULT ''1'',
`script` varchar(255) DEFAULT NULL,
`parent_id` int(11) DEFAULT NULL,
`minutes` varchar(5) DEFAULT NULL,
`hours` varchar(5) DEFAULT NULL,
`day_of_month` varchar(5) DEFAULT NULL,
`months` varchar(5) DEFAULT NULL,
`day_of_week` varchar(5) DEFAULT NULL,
`script_description` varchar(255) DEFAULT NULL,
PRIMARY KEY (`id`),
KEY `parent_id` (`server_id`,`parent_id`,`enabled`)
) ENGINE=MyISAM DEFAULT CHARSET=latin1 AUTO_INCREMENT=15 ;
--
-- Dumping data for table `scheduling`
--
INSERT INTO `scheduling` (`id`, `enabled`, `script`, `parent_id`, `minutes`, `hours`, `day_of_month`, `months`, `day_of_week`, `script_description`) VALUES
(1, 1, ''php download.php'', 0, ''*'', ''*'', ''*'', ''*'', ''*'', ''Download files''),
(2, 1, ''php load_data.php'', 1, ''*'', ''*'', ''*'', ''*'', ''*'', ''Load files to database''),
(3, 1, ''php file_test.php'', 1, ''*'', ''*'', ''*'', ''*'', ''*'', NULL),
(4, 1, ''php file_test.php'', 1, ''*'', ''*'', ''*'', ''*'', ''*'', NULL),
(5, 1, ''php file_test.php'', 1, ''*'', ''*'', ''*'', ''*'', ''*'', NULL),
(6, 1, ''php file_test.php'', 1, ''*'', ''*'', ''*'', ''*'', ''*'', NULL),
(7, 1, ''php file_test.php'', 1, ''*'', ''*'', ''*'', ''*'', ''*'', NULL),
(8, 1, ''php file_test.php'', 1, ''*'', ''*'', ''*'', ''*'', ''*'', NULL),
(9, 1, ''php file_test.php'', 1, ''*'', ''*'', ''*'', ''*'', ''*'', NULL),
(10, 1, ''php file_test.php'', 1, ''*'', ''*'', ''*'', ''*'', ''*'', NULL),
(11, 1, ''php file_test.php'', 1, ''*'', ''*'', ''*'', ''*'', ''*'', NULL),
(12, 1, ''php file_test.php'', 1, ''*'', ''*'', ''*'', ''*'', ''*'', NULL),
(13, 1, ''php file_test.php'', 1, ''*'', ''*'', ''*'', ''*'', ''*'', NULL),
(14, 1, ''php file_test.php'', 1, ''*'', ''*'', ''*'', ''*'', ''*'', NULL);
Sugiero que cree Cron Entries dinámicamente a través de un script de contenedor que configure la entrada de cron para ejecutar su función particular cuando realmente desea que se ejecute.
Para su caso específico aquí A continuación está lo que sugeriría:
- Cree una secuencia de comandos de envoltura y programe en Cron para que se ejecute cada segundo.
- Este script de envoltura se comunicará con MySQL y buscará la hora a la que se ejecutará una función específica.
- A continuación, creará dinámicamente una entrada de cron para ejecutar esa función en esa marca de tiempo recuperada específica. Puede agregar y eliminar dinámicamente la entrada de Cron utilizando el script de shell. Por favor, consulte las referencias a continuación para más detalles.
- Una vez que se completa su función, debe haber alguna indicación, como el estado almacenado en algún lugar, tal vez en su base de datos, o algún archivo, para que el contenedor pueda obtener / conocer el estado y eliminar la entrada cron respectiva.
Referencias
1. Crea Cron usando Bash
crontab -l | { cat; echo "0 0 0 0 0 some entry"; } | crontab -
2. Eliminar / Automatizar Cron
crontab -l -u | grep -v <unique command> | crontab -
tienes 2 formas , aunque solo una hará exactamente lo que quieres hacer;
La primera forma requiere que tengas acceso y privilegios para cambiar el lado del servidor de cron-jobs (ejemplo a través de PHP u otro). Dependiendo de qué sistema operativo hay tutoriales: Win , Nix
La 2ª manera hará algo parecido a lo que quieras, pero sin la precisión de los minutos , perderás un máximo de 2 minutos en cada ciclo. (vea la explicación a continuación).
1st Way forma perfecta
- Tan pronto como el usuario pulse el formulario, cree una cron-task única para ese usuario utilizando el datatime deseado.
Si no tiene esos privilegios, puede usar el servicio de parte 3D como www.easycron.com , también ofrecen una versión gratuita con consulta limitada. también proporcionan un método REST API para administrar (CRUDO) cron-tasks.
Manera imperfecta de la 2da Manera
- agregue una nueva columna
VARCHAR
, la llamétoday
con esto nos aseguraremos de que la tarea se ejecute solo una vez por día.
-
+----+---------+----------+------------+--------+----------+
| iD | timeDay | timeHour | timeMinute | postiD | today |
+--------------------------------------+--------+----------+
| 1 | * | 9 | 0 | 21 | 30-05-04 |
|----|---------|----------|------------|--------|----------+
| 2 | * | 10 | 30 | 22 | |
|----|---------|----------|------------|--------|----------+
| 3 | * | 11 | 0 | 23 | |
+----|---------+----------+------------+--------+----------+
Después de eso crear un archivo php lo
crontask.php
lo llamaremos cada 5 minutosagregue esto a su panel cronjob:
0,5 * * * * /usr/bin/php /www/virtual/username/crontask.php > /dev/null 2>&1
en el archivo
crontask.php
-
<?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;
}
?>
Explicación de la función:
Suponiendo que el horario de cron se ejecuta cada 5 minutos, el lat dice que estamos a las 20:00 en punto, ahora el cron se ejecutará a las 20:05, 20:10, 20:15, 20:20 y así sucesivamente ...
luego asumiendo en nuestro DB tenemos ese momento
Jonh : 20:05,
Mario : 20:32,
luke : 20:48,
David : 20:57,
Jimmy : 20:06,
Eddy : 20:16
cuando el script comprueba contra esos tiempos, se ejecutará de la siguiente manera:
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....
Como ve, perdería en el peor de los casos 2 minutos cada vez. ¡Creo que es justo! ;)