CrontabServer.class.php 3.4 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283
  1. <?php
  2. /**
  3. * 计划任务
  4. */
  5. namespace Common\Server;
  6. class CrontabServer {
  7. /**
  8. * Finds next execution time(stamp) parsin crontab syntax,
  9. * after given starting timestamp (or current time if ommited)
  10. *
  11. * @param string $_cron_string:
  12. *
  13. * 0 1 2 3 4
  14. * * * * * *
  15. * - - - - -
  16. * | | | | |
  17. * | | | | +----- day of week (0 - 6) (Sunday=0)
  18. * | | | +------- month (1 - 12)
  19. * | | +--------- day of month (1 - 31)
  20. * | +----------- hour (0 - 23)
  21. * +------------- min (0 - 59)
  22. * @param int $_after_timestamp timestamp [default=current timestamp]
  23. * @return int unix timestamp - next execution time will be greater
  24. * than given timestamp (defaults to the current timestamp)
  25. * @throws InvalidArgumentException
  26. */
  27. public static function parse($_cron_string,$_after_timestamp=null)
  28. {
  29. if(!preg_match('/^((\*(\/[0-9]+)?)|[0-9\-\,\/]+)\s+((\*(\/[0-9]+)?)|[0-9\-\,\/]+)\s+((\*(\/[0-9]+)?)|[0-9\-\,\/]+)\s+((\*(\/[0-9]+)?)|[0-9\-\,\/]+)\s+((\*(\/[0-9]+)?)|[0-9\-\,\/]+)$/i',trim($_cron_string))){
  30. return("Invalid cron string: ".$_cron_string);
  31. }
  32. if($_after_timestamp && !is_numeric($_after_timestamp)){
  33. return("\$_after_timestamp must be a valid unix timestamp ($_after_timestamp given)");
  34. }
  35. $cron = preg_split("/[\s]+/i",trim($_cron_string));
  36. $start = empty($_after_timestamp)?time():$_after_timestamp;
  37. $date = array( 'minutes' =>self::_parseCronNumbers($cron[0],0,59),
  38. 'hours' =>self::_parseCronNumbers($cron[1],0,23),
  39. 'dom' =>self::_parseCronNumbers($cron[2],1,31),
  40. 'month' =>self::_parseCronNumbers($cron[3],1,12),
  41. 'dow' =>self::_parseCronNumbers($cron[4],0,6),
  42. );
  43. // limited to time()+366 - no need to check more than 1year ahead
  44. for($i=0;$i<=60*60*24*366;$i+=60){
  45. if( in_array(intval(date('j',$start+$i)),$date['dom']) &&
  46. in_array(intval(date('n',$start+$i)),$date['month']) &&
  47. in_array(intval(date('w',$start+$i)),$date['dow']) &&
  48. in_array(intval(date('G',$start+$i)),$date['hours']) &&
  49. in_array(intval(date('i',$start+$i)),$date['minutes'])
  50. ){
  51. return $start+$i;
  52. }
  53. }
  54. return null;
  55. }
  56. /**
  57. * get a single cron style notation and parse it into numeric value
  58. *
  59. * @param string $s cron string element
  60. * @param int $min minimum possible value
  61. * @param int $max maximum possible value
  62. * @return int parsed number
  63. */
  64. protected static function _parseCronNumbers($s,$min,$max)
  65. {
  66. $result = array();
  67. $v = explode(',',$s);
  68. foreach($v as $vv){
  69. $vvv = explode('/',$vv);
  70. $step = empty($vvv[1])?1:$vvv[1];
  71. $vvvv = explode('-',$vvv[0]);
  72. $_min = count($vvvv)==2?$vvvv[0]:($vvv[0]=='*'?$min:$vvv[0]);
  73. $_max = count($vvvv)==2?$vvvv[1]:($vvv[0]=='*'?$max:$vvv[0]);
  74. for($i=$_min;$i<=$_max;$i+=$step){
  75. $result[$i]=intval($i);
  76. }
  77. }
  78. ksort($result);
  79. return $result;
  80. }
  81. }