XwCrontab.php 4.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135
  1. <?php
  2. namespace app\common\api;
  3. class XwCrontab {
  4. /**
  5. * 检查某时间($time)是否符合某个corntab时间计划($str_cron)
  6. *
  7. * @param int $time 时间戳
  8. * @param string $str_cron corntab的时间计划,如,"30 2 * * 1-5"
  9. *
  10. * @return bool/string 出错返回string(错误信息)
  11. */
  12. static public function check($time, $str_cron) {
  13. //完整的crontab表达式,去掉秒后再来判断
  14. $tmp = explode(" ", $str_cron);
  15. array_shift($tmp);
  16. $format_time = self::format_timestamp($time);
  17. $format_cron = self::format_crontab(implode(" ", $tmp));
  18. if (!is_array($format_cron)) {
  19. return $format_cron;
  20. }
  21. return self::format_check($format_time, $format_cron);
  22. }
  23. /**
  24. * 使用格式化的数据检查某时间($format_time)是否符合某个corntab时间计划($format_cron)
  25. *
  26. * @param array $format_time self::format_timestamp()格式化时间戳得到
  27. * @param array $format_cron self::format_crontab()格式化的时间计划
  28. *
  29. * @return bool
  30. */
  31. static public function format_check(array $format_time, array $format_cron) {
  32. return (!$format_cron[0] || in_array($format_time[0], $format_cron[0])) && (!$format_cron[1] || in_array($format_time[1], $format_cron[1])) && (!$format_cron[2] || in_array($format_time[2], $format_cron[2])) && (!$format_cron[3] || in_array($format_time[3], $format_cron[3])) && (!$format_cron[4] || in_array($format_time[4], $format_cron[4]))
  33. ;
  34. }
  35. /**
  36. * 格式化时间戳,以便比较
  37. *
  38. * @param int $time 时间戳
  39. *
  40. * @return array
  41. */
  42. static public function format_timestamp($time) {
  43. return explode('-', date('i-G-j-n-w', $time));
  44. }
  45. /**
  46. * 格式化crontab时间设置字符串,用于比较
  47. *
  48. * @param string $str_cron crontab的时间计划字符串,如"15 3 * * *"
  49. *
  50. * @return array/string 正确返回数组,出错返回字符串(错误信息)
  51. */
  52. static public function format_crontab($str_cron) {
  53. //格式检查
  54. $str_cron = trim($str_cron);
  55. $reg = '#^((\*(/\d+)?|((\d+(-\d+)?)(?3)?)(,(?4))*))( (?2)){4}$#';
  56. if (!preg_match($reg, $str_cron)) {
  57. return '格式错误';
  58. }
  59. try {
  60. //分别解析分、时、日、月、周
  61. $arr_cron = array();
  62. $parts = explode(' ', $str_cron);
  63. $arr_cron[0] = self::parse_cron_part($parts[0], 0, 59); //分
  64. $arr_cron[1] = self::parse_cron_part($parts[1], 0, 23); //时
  65. $arr_cron[2] = self::parse_cron_part($parts[2], 1, 31); //日
  66. $arr_cron[3] = self::parse_cron_part($parts[3], 1, 12); //月
  67. $arr_cron[4] = self::parse_cron_part($parts[4], 0, 6); //周(0周日)
  68. } catch (Exception $e) {
  69. return $e->getMessage();
  70. }
  71. return $arr_cron;
  72. }
  73. /**
  74. * 解析crontab时间计划里一个部分(分、时、日、月、周)的取值列表
  75. * @param string $part 时间计划里的一个部分,被空格分隔后的一个部分
  76. * @param int $f_min 此部分的最小取值
  77. * @param int $f_max 此部分的最大取值
  78. *
  79. * @return array 若为空数组则表示可任意取值
  80. * @throws Exception
  81. */
  82. static protected function parse_cron_part($part, $f_min, $f_max) {
  83. $list = array();
  84. //处理"," -- 列表
  85. if (false !== strpos($part, ',')) {
  86. $arr = explode(',', $part);
  87. foreach ($arr as $v) {
  88. $tmp = self::parse_cron_part($v, $f_min, $f_max);
  89. $list = array_merge($list, $tmp);
  90. }
  91. return $list;
  92. }
  93. //处理"/" -- 间隔
  94. $tmp = explode('/', $part);
  95. $part = $tmp[0];
  96. $step = isset($tmp[1]) ? $tmp[1] : 1;
  97. //处理"-" -- 范围
  98. if (false !== strpos($part, '-')) {
  99. list($min, $max) = explode('-', $part);
  100. if ($min > $max) {
  101. throw new Exception('使用"-"设置范围时,左不能大于右');
  102. }
  103. } elseif ('*' == $part) {
  104. $min = $f_min;
  105. $max = $f_max;
  106. } else {//数字
  107. $min = $max = $part;
  108. }
  109. //空数组表示可以任意值
  110. if ($min == $f_min && $max == $f_max && $step == 1) {
  111. return $list;
  112. }
  113. //越界判断
  114. if ($min < $f_min || $max > $f_max) {
  115. throw new Exception('数值越界。应该:分0-59,时0-59,日1-31,月1-12,周0-6');
  116. }
  117. return $max - $min > $step ? range($min, $max, $step) : array((int) $min);
  118. }
  119. }