How to schedule tasks from PHP?

Need help installing PHP, configuring a script, or configuring a server? Then come on in and post your questions! We'll try to help the best we can!

Moderator: General Moderators

Post Reply
nikosb
Forum Newbie
Posts: 8
Joined: Sat Sep 23, 2006 5:46 pm

How to schedule tasks from PHP?

Post by nikosb »

Hello and happy holidays to all users. I have a situation in which I need to schedule a task from within a PHP file. Basically there is a file called at.php which does certain database transactions and at the end it schedules it self to run again in a randon time in the future. In order to implement the scheduling part of the at.php I decided to use the proc_open function and in there a execute the command:
at now + 2 days /usr/local/php4/bin/php /www/at.php

At this point I have 1 question and 1 problem:

Question: What are the dangers and security risks of trying to schedule a task thourgh PHP using proc_open or any other functions like exec, shell_exec, system (I use proc_open because it allows me to retrieve the jobid that the at command prints out to standard error)? The at.php script is located in a non public directory that has r-xr-xr-x so that it can be executed by user nobody but people cannot just type the address and execute it. Is there a better/safer way to schedule tasks from PHP and possibly avoiding the problem I describe below?

Problem: When I run the script from my web browser (Mozilla and Safari) the script runs OK the first time. It does the databas transactions and it also schedules to run itself in the future. However when the time comes for the script to run again nothing happens. When I run the script from my console, logged in as root or regular user or even sudo -u nobody the script runs OK the first time, schedules it self to run in the future and runs again when it is scheduled to run.
When I look at the /var/at/jobs for the at script created when at.php is called from the browser it looks like:

Code: Select all

#!/bin/sh
# atrun uid=-2 gid=-1
# mail george 1
umask 22
MANPATH=/sw/share/man:/usr/share/man:/usr/local/mysql/man:/usr/local/share/man:/usr/X11R6/man:/sw/lib/perl5/5.8.6/man; export MANPATH
TERM_PROGRAM=Apple_Terminal; export TERM_PROGRAM
SHELL=/bin/bash; export SHELL
TERM_PROGRAM_VERSION=133; export TERM_PROGRAM_VERSION
SGML_CATALOG_FILES=/sw/etc/sgml/catalog; export SGML_CATALOG_FILES
USER=root; export USER
SUDO_USER=george; export SUDO_USER
SUDO_UID=501; export SUDO_UID
__CF_USER_TEXT_ENCODING=0x0:0:0; export __CF_USER_TEXT_ENCODING
PATH=/sw/bin:/sw/sbin:/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/mysql/bin:/usr/X11R6/bin; export PATH
XML_CATALOG_FILES=/sw/etc/xml/catalog; export XML_CATALOG_FILES
PWD=/usr/local/apache2/htdocs/www; export PWD
SHLVL=3; export SHLVL
HOME=/Users/george; export HOME
SUDO_COMMAND=/usr/local/apache2/bin/apachectl\ start; export SUDO_COMMAND
LOGNAME=root; export LOGNAME
INFOPATH=/sw/share/info:/sw/info:/usr/share/info; export INFOPATH
SUDO_GID=501; export SUDO_GID
SECURITYSESSIONID=a144f0; export SECURITYSESSIONID
cd /usr/local/apache2/htdocs/ideaworth || {
         echo 'Execution directory inaccessible' >&2
         exit 1
}
/usr/local/php4/bin/php /usr/local/apache2/htdocs/www/at.php 205 1
When I run it from the command line logged is george abd using sudo -u nobody the at script looks like:

Code: Select all

#!/bin/sh
# atrun uid=-2 gid=-2
# mail george 1
umask 22
MANPATH=/sw/share/man:/usr/share/man:/usr/local/mysql/man:/usr/local/share/man:/usr/X11R6/man:/sw/lib/perl5/5.8.6/man; export MANPATH
TERM_PROGRAM=Apple_Terminal; export TERM_PROGRAM
SHELL=/bin/sh; export SHELL
TERM_PROGRAM_VERSION=133; export TERM_PROGRAM_VERSION
SGML_CATALOG_FILES=/sw/etc/sgml/catalog; export SGML_CATALOG_FILES
USER=nobody; export USER
SUDO_USER=root; export SUDO_USER
SUDO_UID=0; export SUDO_UID
__CF_USER_TEXT_ENCODING=0xFFFFFFFE:0:0; export __CF_USER_TEXT_ENCODING
PATH=/sw/bin:/sw/sbin:/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/mysql/bin:/usr/X11R6/bin; export PATH
XML_CATALOG_FILES=/sw/etc/xml/catalog; export XML_CATALOG_FILES
PWD=/var/mail; export PWD
SUDO_COMMAND=/usr/local/php4/bin/php\ /usr/local/apache2/htdocs/www/at.php\ 205; export SUDO_COMMAND
SHLVL=3; export SHLVL
HOME=/var/root; export HOME
LOGNAME=nobody; export LOGNAME
INFOPATH=/sw/share/info:/sw/info:/usr/share/info; export INFOPATH
SUDO_GID=0; export SUDO_GID
SECURITYSESSIONID=a144f0; export SECURITYSESSIONID
cd /private/var/mail || {
         echo 'Execution directory inaccessible' >&2
         exit 1
}
/usr/local/php4/bin/php /usr/local/apache2/htdocs/www/at.php 205 1
I spent a lot of time trying to understand why this happens but I could not figure it out. Any advice would be greatly appreciated it.

Thanks,

Nikolaos

P.S. I am testing this locally on my MacOS but I am also experiencing the same issue on the server that runs Linux.
User avatar
yacahuma
Forum Regular
Posts: 870
Joined: Sun Jul 01, 2007 7:11 am

cron every minute

Post by yacahuma »

Why dont you have a cron that run every minute an check a flag on a database and if is what you expect , run the necessary script.
nikosb
Forum Newbie
Posts: 8
Joined: Sat Sep 23, 2006 5:46 pm

Post by nikosb »

Thanks for the reply. In the case I cannot figure out why I am having this sort of problem with the at command I could use the cron alternative as you mentioned. I was also thinking of calling the program and having it go to sleep/wait for the necessary amount but I think the cron job would be the simplest. Would it slow down the server if it has to run the program and connect to the database every minute?
I am still curious though as to why I can not use the at command when executed from the browser. I guess this is more a Linux question rather than php. Any ideas where I can get the anwer to this issue?
User avatar
John Cartwright
Site Admin
Posts: 11470
Joined: Tue Dec 23, 2003 2:10 am
Location: Toronto
Contact:

Post by John Cartwright »

My guess is the user does not have permission. Is php running as nobody as well?

P.S. Linux is not my cup of tea, unfortunantly.

Moved to Installation and Configuration.
nikosb
Forum Newbie
Posts: 8
Joined: Sat Sep 23, 2006 5:46 pm

Post by nikosb »

PHP has r-xr-xr-x permissions so it can be run as nobody. When I execute the command sudo -u nobody and the program works I believe it is running as nobody. I include a PHP sample program that when it is executed writes to a file and schedules itself for execution in 1 minute. The problem is that when I execute from the browser, the program schedules it self but never runs in the future. When I execute it manually from the console it works OK. Let me know if you experience the same problem.

Code: Select all

<?php

function scheduletask($cmd, $time)
{
  $jobid = -1;

  $descriptorspec = array(
   0 => array("pipe", "r"),
   1 => array("pipe", "w"),
   2 => array("pipe", "w")
  );

  $atcmd = "at -m now"; 
  print "at=".$atcmd."<BR>\n";
  $process = proc_open($atcmd, $descriptorspec, $pipes);
  if (is_resource($process))
  {
    print "Inside process, cmd=$cmd<BR>\n";
    fwrite($pipes[0], $cmd);    // send start
    fclose($pipes[0]);
    $output = fgets($pipes[2]);
    print $output."<BR>\n";
    fclose($pipes[1]);
    fclose($pipes[2]);
    if(preg_match('/job\s+?(\d+)?/',$output,$match))
      $jobid = $match[1];
    $return_value = proc_close($process);  //stop test_gen.php
  }

  return $jobid;
}


 //--- Main program

//---Define working directories.
$nonpubdir = "/usr/local/apache2/htdocs/www/";
$phpdir = "/usr/local/php4/bin/";
$cwd = getcwd();


$fdt = "Y-m-d H:i:s";
$today = date($fdt);


$iwrite=1;
if($iwrite)
{
  $fileout = $cwd."/at.txt";
  if(is_writeable($fileout))
  {
    if($fid = fopen($fileout,"a"))
    {
      fwrite($fid,"Program called on $today\n");
    }
    else
      $iwrite=0;
  }
  else
    $iwrite=0;
}

$exectime = "now +1 minute";
$cmd = $phpdir."php ".$cwd. "/at.php";
$jobid = scheduletask1($cmd, $exectime);
if($iwrite) fwrite($fid,"Scheduled $jobid\n\n");
if($iwrite) fclose($fid);
exit;

?>
Post Reply