PageRenderTime 59ms CodeModel.GetById 29ms RepoModel.GetById 0ms app.codeStats 0ms

/instances/application/libraries/CronParser.php

https://github.com/kiirti/Ushahidi_MHI
PHP | 429 lines | 356 code | 37 blank | 36 comment | 98 complexity | f580d76aa58f698e26033a7be019fb5c MD5 | raw file
  1. <?php
  2. /**
  3. * CronParser library.
  4. * Reads Cron schedule from database
  5. * Determines if scheduled item has already been ran
  6. * Courtesy of Mick Sear (eCreate)
  7. *
  8. * @package Proximity
  9. * @author Ushahidi Team
  10. * @copyright (c) 2008 Ushahidi Team
  11. * @license http://www.ushahidi.com/license.html
  12. */
  13. class CronParser{
  14. var $bits = Array(); //exploded String like 0 1 * * *
  15. var $now= Array(); //Array of cron-style entries for time()
  16. var $lastRan; //Timestamp of last ran time.
  17. var $taken;
  18. var $debug;
  19. function CronParser($string){
  20. $tstart = microtime();
  21. $this->debug("<b>Working on cron schedule: $string</b>");
  22. $this->bits = @explode(" ", $string);
  23. $this->getNow();
  24. $this->calcLastRan();
  25. $tend = microtime();
  26. $this->taken = $tend-$tstart;
  27. $this->debug("Parsing $string taken ".$this->taken." seconds");
  28. }
  29. function getNow(){
  30. $t = strftime("%M,%H,%d,%m,%w,%Y", time()); //Get the values for now in a format we can use
  31. $this->now = explode(",", $t); //Make this an array
  32. //$this->debug($this->now);
  33. }
  34. function getLastRan(){
  35. return explode(",", strftime("%M,%H,%d,%m,%w,%Y", $this->lastRan)); //Get the values for now in a format we can use
  36. }
  37. function getDebug(){
  38. return $this->debug;
  39. }
  40. function debug($str){
  41. if (is_array($str)){
  42. $this->debug .= "\nArray: ";
  43. foreach($str as $k=>$v){
  44. $this->debug .= "$k=>$v, ";
  45. }
  46. } else {
  47. $this->debug .= "\n$str";
  48. }
  49. //echo nl2br($this->debug);
  50. }
  51. function getExtremeMonth($extreme){
  52. if ($extreme == "END"){
  53. $year = $this->now[5] - 1;
  54. } else {
  55. $year = $this->now[5];
  56. }
  57. //Now determine start or end month in the last year
  58. if ($this->bits[3] == "*" && $extreme == "END"){//Check month format
  59. $month = 12;
  60. } else if ($this->bits[3] == "*" && $extreme == "START"){
  61. $month = 1;
  62. } else {
  63. $months = $this->expand_ranges($this->bits[3]);
  64. if ($extreme == "END"){
  65. sort($months);
  66. } else {
  67. rsort($months);
  68. }
  69. $month = array_pop($months);
  70. }
  71. //Now determine the latest day in the specified month
  72. $day=$this->getExtremeOfMonth($month, $year, $extreme);
  73. $this->debug("Got day $day for $extreme of $month, $year");
  74. $hour = $this->getExtremeHour($extreme);
  75. $minute = $this->getExtremeMinute($extreme);
  76. return mktime($hour, $minute, 0, $month, $day, $year);
  77. }
  78. /**
  79. * Assumes that value is not *, and creates an array of valid numbers that
  80. * the string represents. Returns an array.
  81. */
  82. function expand_ranges($str){
  83. //$this->debug("Expanding $str");
  84. if (strstr($str, ",")){
  85. $tmp1 = explode(",", $str);
  86. //$this->debug($tmp1);
  87. $count = count($tmp1);
  88. for ($i=0;$i<$count;$i++){//Loop through each comma-separated value
  89. if (strstr($tmp1[$i], "-")){ //If there's a range in this place, expand that too
  90. $tmp2 = explode("-", $tmp1[$i]);
  91. //$this->debug("Range:");
  92. //$this->debug($tmp2);
  93. for ($j=$tmp2[0];$j<=$tmp2[1];$j++){
  94. $ret[] = $j;
  95. }
  96. } else {//Otherwise, just add the value
  97. $ret[] = $tmp1[$i];
  98. }
  99. }
  100. } else if (strstr($str, "-")){//There might only be a range, no comma sep values at all. Just loop these
  101. $range = explode("-", $str);
  102. for ($i=$range[0];$i<=$range[1];$i++){
  103. $ret[] = $i;
  104. }
  105. } else {//Otherwise, it's a single value
  106. $ret[] = $str;
  107. }
  108. //$this->debug($ret);
  109. return $ret;
  110. }
  111. /**
  112. * Given a string representation of a set of weekdays, returns an array of
  113. * possible dates.
  114. */
  115. function getWeekDays($str, $month, $year){
  116. $daysInMonth = $this->daysinmonth($month, $year);
  117. if (strstr($str, ",")){
  118. $tmp1 = explode(",", $str);
  119. $count = count($tmp1);
  120. for ($i=0;$i<$count;$i++){//Loop through each comma-separated value
  121. if (strstr($tmp1[$i], "-")){ //If there's a range in this place, expand that too
  122. $tmp2 = explode("-", $tmp1[$i]);
  123. for ($j=$start;$j<=$tmp2[1];$j++){
  124. for ($n=1;$n<=$daysInMonth;$n++){
  125. if ($j == jddayofweek(gregoriantojd ( $month, $n, $year),0)){
  126. $ret[] = $n;
  127. }
  128. }
  129. }
  130. } else {//Otherwise, just add the value
  131. for ($n=1;$n<=$daysInMonth;$n++){
  132. if ($tmp1[$i] == jddayofweek(gregoriantojd ( $month, $n, $year),0)){
  133. $ret[] = $n;
  134. }
  135. }
  136. }
  137. }
  138. } else if (strstr($str, "-")){//There might only be a range, no comma sep values at all. Just loop these
  139. $range = explode("-", $str);
  140. for ($i=$start;$i<=$range[1];$i++){
  141. for ($n=1;$n<=$daysInMonth;$n++){
  142. if ($i == jddayofweek(gregoriantojd ( $month, $n, $year),0)){
  143. $ret[] = $n;
  144. }
  145. }
  146. }
  147. } else {//Otherwise, it's a single value
  148. for ($n=1;$n<=$daysInMonth;$n++){
  149. if ($str == jddayofweek(gregoriantojd ( $month, $n, $year),0)){
  150. $ret[] = $n;
  151. }
  152. }
  153. }
  154. return $ret;
  155. }
  156. function daysinmonth($month, $year){
  157. if(checkdate($month, 31, $year)) return 31;
  158. if(checkdate($month, 30, $year)) return 30;
  159. if(checkdate($month, 29, $year)) return 29;
  160. if(checkdate($month, 28, $year)) return 28;
  161. return 0; // error
  162. }
  163. /**
  164. * Get the timestamp of the last ran time.
  165. */
  166. function calcLastRan(){
  167. $now = time();
  168. if ($now < $this->getExtremeMonth("START")){
  169. //The cron isn't due to have run this year yet. Getting latest last year
  170. $this->debug("Last ran last year");
  171. $tsLatestLastYear = $this->getExtremeMonth("END");
  172. $this->debug("Timestamp of latest scheduled time last year is ".$tsLatestLastYear);
  173. $this->lastRan = $tsLatestLastYear;
  174. $year = date("Y", $this->lastRan);
  175. $month = date("m", $this->lastRan);
  176. $day = date("d", $this->lastRan);
  177. $hour = date("h", $this->lastRan);
  178. $minute = date("i", $this->lastRan);
  179. } else { //Cron was due to run this year. Determine when it was last due
  180. $this->debug("Cron was due to run earlier this year");
  181. $year = $this->now[5];
  182. $arMonths = $this->expand_ranges($this->bits[3]);
  183. if (!in_array($this->now[3], $arMonths) && $this->bits[3] != "*"){//Not due to run this month. Get latest of last month
  184. $this->debug("Cron was not due to run this month at all. This month is ".$this->now[3]);
  185. $this->debug("Months array: ");
  186. $this->debug($arMonths);
  187. sort($arMonths);
  188. do{
  189. $month = array_pop($arMonths);
  190. } while($month > $this->now[3]);
  191. $day = $this->getExtremeOfMonth($month, $this->now[5], "END");
  192. $hour = $this->getExtremeHour("END");
  193. $minute = $this->getExtremeMinute("END");
  194. } else if ($now < $this->getExtremeOfMonth($this->now[3], $this->now[5], "START")){ //It's due in this month, but not yet.
  195. $this->debug("It's due in this month, but not yet.");
  196. sort($arMonths);
  197. do{
  198. $month = array_pop($arMonths);
  199. } while($month > $this->now[3]);
  200. $day = $this->getExtremeOfMonth($month, $this->now[5], "END");
  201. $hour = $this->getExtremeHour("END");
  202. $minute = $this->getExtremeMinute("END");
  203. } else {//It has been due this month already
  204. $this->debug("Cron has already been due to run this month (".$month = $this->now[3].")");
  205. $month = $this->now[3];
  206. $this->debug("Getting days array");
  207. $days = $this->getDaysArray($this->now[3]);
  208. if (!in_array($this->now[2], $days)){
  209. $this->debug("Today not in the schedule. Getting latest last due day");
  210. //No - Get latest last scheduled day
  211. sort($days);
  212. do{
  213. $day = array_pop($days);
  214. } while($day > $this->now[2]);
  215. $hour = $this->getExtremeHour("END");
  216. $minute = $this->getExtremeMinute("END");
  217. } else if($this->now[1] < $this->getExtremeHour("START")){//Not due to run today yet
  218. $this->debug("Cron due today, but not yet. Getting latest on last day");
  219. sort($days);
  220. do{
  221. $day = array_pop($days);
  222. } while($day >= $this->now[2]);
  223. $hour = $this->getExtremeHour("END");
  224. $minute = $this->getExtremeMinute("END");
  225. } else {
  226. $this->debug("Cron has already been due to run today");
  227. $day = $this->now[2];
  228. //Yes - Check if this hour is in the schedule?
  229. $arHours = $this->expand_ranges($this->bits[1]);
  230. if (!in_array($this->now[1], $arHours) && $this->bits[1] != "*"){
  231. $this->debug("Cron not due in this hour, getting latest in last scheduled hour");
  232. //No - Get latest last hour
  233. sort($arHours);
  234. do{
  235. $hour = array_pop($arHours);
  236. //$this->debug("hour is $hour, now is ".$this->now[1]);
  237. } while($hour > $this->now[1]);
  238. $minute = $this->getExtremeMinute("END");
  239. } else if ($now < $this->getExtremeMinute("START") && $this->bits[1] != "*"){ //Not due to run this hour yet
  240. sort($arHours);
  241. do{
  242. $hour = array_pop($arHours);
  243. } while($hour >= $this->now[1]);
  244. $minute = $this->getExtremeMinute("END");
  245. } else {
  246. //Yes, it is supposed to have run this hour already - Get last minute
  247. $hour = $this->now[1];
  248. if ($this->bits[0] != "*"){
  249. $arMinutes = $this->expand_ranges($this->bits[0]);
  250. $this->debug($arMinutes);
  251. do{
  252. $minute = array_pop($arMinutes);
  253. } while($minute >= $this->now[0]);
  254. //If the first time in the hour that the cron is due to run is later than now, return latest last hour
  255. if($minute > $this->now[1] || $minute == ""){
  256. $this->debug("Valid minute not set");
  257. $minute = $this->getExtremeMinute("END"); //The minute will always be the last valid minute in an hour
  258. //Get the last hour.
  259. if ($this->bits[1] == "*"){
  260. $hour = $this->now[1] - 1;
  261. } else {
  262. $arHours = $this->expand_ranges($this->bits[1]);
  263. $this->debug("Array of hours:");
  264. $this->debug($arHours);
  265. sort($arHours);
  266. do{
  267. $hour = array_pop($arHours);
  268. } while($hour >= $this->now[1]);
  269. }
  270. }
  271. } else {
  272. $minute = $this->now[0] -1;
  273. }
  274. }
  275. }
  276. }
  277. }
  278. $this->debug("LAST RAN: $hour:$minute on $day/$month/$year");
  279. $this->lastRan = mktime($hour, $minute, 0, $month, $day, $year);
  280. }
  281. function getExtremeOfMonth($month, $year, $extreme){
  282. $daysInMonth = $this->daysinmonth($month, $year);
  283. if ($this->bits[2] == "*"){
  284. if ($this->bits[4] == "*"){//Is there a day range?
  285. //$this->debug("There were $daysInMonth days in $month, $year");
  286. if ($extreme == "END"){
  287. $day = $daysInMonth;
  288. } else {
  289. $day=1;
  290. }
  291. } else {//There's a day range. Ignore the dateDay range and just get the list of possible weekday values.
  292. $days = $this->getWeekDays($this->bits[4],$month, $year);
  293. $this->debug($this->bits);
  294. $this->debug("Days array for ".$this->bits[4].", $month, $year:");
  295. $this->debug($days);
  296. if ($extreme == "END"){
  297. sort($days);
  298. } else {
  299. rsort($days);
  300. }
  301. $day = array_pop($days);
  302. }
  303. } else {
  304. $days = $this->expand_ranges($this->bits[2]);
  305. if ($extreme == "END"){
  306. sort($days);
  307. } else {
  308. rsort($days);
  309. }
  310. do {
  311. $day = array_pop($days);
  312. } while($day > $daysInMonth);
  313. }
  314. //$this->debug("$extreme day is $day");
  315. return $day;
  316. }
  317. function getDaysArray($month){
  318. $this->debug("Getting days for $month");
  319. $days = array();
  320. if ($this->bits[4] != "*"){
  321. $days = $this->getWeekDays($this->bits[4], $month, $this->now[5]);
  322. $this->debug("Weekdays:");
  323. $this->debug($days);
  324. }
  325. if ($this->bits[2] != "*" && $this->bits[4] == "*") {
  326. $days = $this->expand_ranges($this->bits[2]);
  327. }
  328. if ($this->bits[2] == "*" && $this->bits[4] == "*"){
  329. //Just return every day of the month
  330. $daysinmonth = $this->daysinmonth($month, $this->now[5]);
  331. $this->debug("Days in ".$month.", ".$this->now[5].": ".$daysinmonth);
  332. for($i = 1;$i<=$daysinmonth;$i++){
  333. $days[] = $i;
  334. }
  335. }
  336. $this->debug($days);
  337. return $days;
  338. }
  339. function getExtremeHour($extreme){
  340. if ($this->bits[1] == "*"){
  341. if ($extreme == "END"){
  342. $hour = 23;
  343. } else {
  344. $hour = 0;
  345. }
  346. } else {
  347. $hours = $this->expand_ranges($this->bits[1]);
  348. if ($extreme == "END"){
  349. sort($hours);
  350. } else {
  351. rsort($hours);
  352. }
  353. $hour = array_pop($hours);
  354. }
  355. //$this->debug("$extreme hour is $hour");
  356. return $hour;
  357. }
  358. function getExtremeMinute($extreme){
  359. if ($this->bits[0] == "*"){
  360. if ($extreme == "END"){
  361. $minute = 59;
  362. } else {
  363. $minute = 0;
  364. }
  365. } else {
  366. $minutes = $this->expand_ranges($this->bits[0]);
  367. if ($extreme == "END"){
  368. sort($minutes);
  369. } else {
  370. rsort($minutes);
  371. }
  372. $minute = array_pop($minutes);
  373. }
  374. //$this->debug("$extreme minute is $minute");
  375. return $minute;
  376. }
  377. }
  378. ?>