SHOW:
|
|
- or go back to the newest paste.
| 1 | <?php | |
| 2 | ||
| 3 | /** | |
| 4 | * The abstract class which every cron job class needs to be extending for it | |
| 5 | * to function properly. Nothing here needs to be changed, but if you feel it's | |
| 6 | * required to do so, please contact the author first. | |
| 7 | * | |
| 8 | * @author Stefan van Beusekom | |
| 9 | * @version 1.1 | |
| 10 | * @abstract | |
| 11 | */ | |
| 12 | abstract class Callcenter_Model_Cron_Abstract {
| |
| 13 | ||
| 14 | protected $_errorList = array(); | |
| 15 | protected $_handleExecList = false; | |
| 16 | protected $_lastExecuted = false; | |
| 17 | protected $_startScript = false; | |
| 18 | protected $_endScript = false; | |
| 19 | protected $_executionSuccessful = false; | |
| 20 | ||
| 21 | /** | |
| 22 | * Set the time limit for script execution | |
| 23 | * | |
| 24 | * @author Stefan van Beusekom | |
| 25 | * @since 1.1 | |
| 26 | */ | |
| 27 | protected function setTimelimit() {
| |
| 28 | $childClass = get_called_class(); | |
| 29 | set_time_limit(($childClass::CRON_TIMEOUT_MINUTES * 60) + $childClass::CRON_TIMEOUT_SECONDS); | |
| 30 | return $this; | |
| 31 | } | |
| 32 | ||
| 33 | /** | |
| 34 | * Set the date and time string of when this cronjob was started | |
| 35 | * | |
| 36 | * @author Stefan van Beusekom | |
| 37 | * @since 1.1 | |
| 38 | */ | |
| 39 | protected function setStartScript() {
| |
| 40 | $dateTime = new DateTime(); | |
| 41 | $this->_startScript = $dateTime->format("Y-m-d H:i:s");
| |
| 42 | return $this; | |
| 43 | } | |
| 44 | ||
| 45 | /** | |
| 46 | * Set the date and time string of when this cronjob ended | |
| 47 | * | |
| 48 | * @author Stefan van Beusekom | |
| 49 | * @since 1.1 | |
| 50 | */ | |
| 51 | protected function setEndScript() {
| |
| 52 | $dateTime = new DateTime(); | |
| 53 | $this->_endScript = $dateTime->format("Y-m-d H:i:s");
| |
| 54 | return $this; | |
| 55 | } | |
| 56 | ||
| 57 | /** | |
| 58 | * Get the path to the cronjob folder | |
| 59 | * | |
| 60 | * @author Stefan van Beusekom | |
| 61 | * @since 1.0 | |
| 62 | * @return string | |
| 63 | */ | |
| 64 | protected function getCronPath($file = null) {
| |
| 65 | return APPLICATION_PATH . "/../cron/" . $file; | |
| 66 | } | |
| 67 | ||
| 68 | /** | |
| 69 | * Add an error for the current cronjob | |
| 70 | * | |
| 71 | * @author Stefan van Beusekom | |
| 72 | * @since 1.0 | |
| 73 | * @param string $error Error message | |
| 74 | */ | |
| 75 | protected function addError($error) {
| |
| 76 | array_push($this->_errorList, $error); | |
| 77 | } | |
| 78 | ||
| 79 | /** | |
| 80 | * Return a list of errors for the current cronjob | |
| 81 | * | |
| 82 | * @author Stefan van Beusekom | |
| 83 | * @since 1.0 | |
| 84 | * @return array | |
| 85 | */ | |
| 86 | protected function getErrors() {
| |
| 87 | return $this->_errorList; | |
| 88 | } | |
| 89 | ||
| 90 | /** | |
| 91 | * Set the current timestamp of when this cronjob was last executed | |
| 92 | * | |
| 93 | * @author Stefan van Beusekom | |
| 94 | * @since 1.0 | |
| 95 | */ | |
| 96 | protected function setLastExecuted() {
| |
| 97 | $this->_handleExecList = fopen($this->getCronPath(get_called_class() . ".cron"), "w+"); | |
| 98 | $cronArray = fread($this->_handleExecList, filesize($this->getCronPath(get_called_class() . ".cron"))); | |
| 99 | if (($cronArray) == '') | |
| 100 | $cronArray = array(); | |
| 101 | else | |
| 102 | $cronArray = unserialize($cronArray); | |
| 103 | $this->_lastExecuted = time(); | |
| 104 | $cronArray[get_called_class()] = $this->_lastExecuted; | |
| 105 | fwrite($this->_handleExecList, serialize($cronArray)); | |
| 106 | fclose($this->_handleExecList); | |
| 107 | return $this; | |
| 108 | } | |
| 109 | ||
| 110 | /** | |
| 111 | * Get the timestamp of when this cronjob was last executed | |
| 112 | * | |
| 113 | * @author Stefan van Beusekom | |
| 114 | * @since 1.0 | |
| 115 | * @return int|boolean | |
| 116 | */ | |
| 117 | protected function getLastExecuted() {
| |
| 118 | if (!$this->_lastExecuted) {
| |
| 119 | if (file_exists($this->getCronPath(get_called_class() . ".cron"))) {
| |
| 120 | $this->_handleExecList = fopen($this->getCronPath(get_called_class() . ".cron"), "r"); | |
| 121 | $cronArray = fread($this->_handleExecList, filesize($this->getCronPath(get_called_class() . ".cron"))); | |
| 122 | if (!$cronArray) | |
| 123 | $cronArray = array(); | |
| 124 | else | |
| 125 | $cronArray = unserialize($cronArray); | |
| 126 | return (key_exists(get_called_class(), $cronArray)) ? $cronArray[get_called_class()] : 0; | |
| 127 | } else {
| |
| 128 | return 0; | |
| 129 | } | |
| 130 | } else {
| |
| 131 | return $this->_lastExecuted; | |
| 132 | } | |
| 133 | } | |
| 134 | ||
| 135 | /** | |
| 136 | * Return a true or false if the current cronjob is allowed to run based on | |
| 137 | * the timestamps. | |
| 138 | * | |
| 139 | * @author Stefan van Beusekom | |
| 140 | * @since 1.0 | |
| 141 | * @return boolean | |
| 142 | */ | |
| 143 | protected function allowExecute() {
| |
| 144 | $childClass = get_called_class(); | |
| 145 | $dateTimePre = new DateTime(); | |
| 146 | $dateTimePre->setTimestamp($this->getLastExecuted()); | |
| 147 | $dateTimePre->setTime($dateTimePre->format("H"), $dateTimePre->format("i"), 0);
| |
| 148 | ||
| 149 | if ($childClass::CRON_INTERVAL_HOURS != 0) | |
| 150 | $dateTimePre->setTime($dateTimePre->format("H"), 0, 0);
| |
| 151 | if ($childClass::CRON_INTERVAL_DAYS != 0) | |
| 152 | $dateTimePre->setTime(0, 0, 0); | |
| 153 | ||
| 154 | $currentSeconds = (time() - $dateTimePre->getTimestamp()); | |
| 155 | $intervalSeconds = ($childClass::CRON_INTERVAL_DAYS * 24 * 60 * 60) + ($childClass::CRON_INTERVAL_HOURS * 60 * 60) + ($childClass::CRON_INTERVAL_MINUTES * 60); | |
| 156 | ||
| 157 | $curDateObj = new DateTime(); | |
| 158 | $allDateObj = new DateTime($childClass::CRON_START_DATETIME); | |
| 159 | ||
| 160 | if ($curDateObj->getTimestamp() < $allDateObj->getTimestamp()) | |
| 161 | return false; | |
| 162 | ||
| 163 | if ($currentSeconds >= $intervalSeconds) | |
| 164 | return true; | |
| 165 | else | |
| 166 | return false; | |
| 167 | } | |
| 168 | ||
| 169 | /** | |
| 170 | * Append the log with data pertaining to the execution, or failure thereof | |
| 171 | * | |
| 172 | * @author Stefan van Beusekom | |
| 173 | * @since 1.0 | |
| 174 | */ | |
| 175 | protected function addLog() {
| |
| 176 | $fileHandle = fopen($this->getCronPath(get_called_class() . ".txt"), "a"); | |
| 177 | $dateObjectStart = new DateTime($this->_startScript); | |
| 178 | $dateObjectEnd = new DateTime($this->_endScript); | |
| 179 | $datePrefix = "[" . $dateObjectStart->format("d-m-Y H:i:s") . "][" . $dateObjectEnd->format("d-m-Y H:i:s") . "] ";
| |
| 180 | $logEntry = ""; | |
| 181 | if ($this->isSuccessful()) {
| |
| 182 | $logEntry .= $datePrefix . "Cronjob was completed successfully." . "\r\n"; | |
| 183 | } else {
| |
| 184 | $errorPrefix = str_pad("", strlen($datePrefix), " ", STR_PAD_LEFT);
| |
| 185 | - | $logEntry .= $datePrefix . "Cronjob could not be completed. The following errors occured:" . "\r\n"; |
| 185 | + | $logEntry .= $datePrefix . "Cronjob could not be completed. The following errors occurred:" . "\r\n"; |
| 186 | foreach ($this->getErrors() as $error) {
| |
| 187 | $logEntry .= $errorPrefix . $error . "\r\n"; | |
| 188 | } | |
| 189 | } | |
| 190 | fwrite($fileHandle, $logEntry); | |
| 191 | fclose($fileHandle); | |
| 192 | } | |
| 193 | ||
| 194 | /** | |
| 195 | * Return a true or false if the current cronjob has been successful | |
| 196 | * | |
| 197 | * @author Stefan van Beusekom | |
| 198 | * @since 1.0 | |
| 199 | * @return boolean | |
| 200 | */ | |
| 201 | protected function isSuccessful() {
| |
| 202 | return ((count($this->getErrors()) == 0) ? true : false); | |
| 203 | } | |
| 204 | ||
| 205 | /** | |
| 206 | * The on exit callback which will produce an error message despite an | |
| 207 | * uncatchable error being thrown. | |
| 208 | * | |
| 209 | * @author Stefan van Beusekom | |
| 210 | * @since 1.1 | |
| 211 | * @todo Although this method logs the error, nothing can be done about its | |
| 212 | * ability to continue running other cronjobs. Search for possible | |
| 213 | * solution to this problem. | |
| 214 | */ | |
| 215 | public function onExecute() {
| |
| 216 | if (!$this->_executionSuccessful) {
| |
| 217 | $errorMessage = "CRITICAL ERROR - Entire cron process was abruptly halted due to an uncatchable error. Please disable this class until the problem has been resolved. - No stack trace is available for debugging, but common errors are: faulty code, maximum execution time exceeded, or a server crash."; | |
| 218 | $this->addError($errorMessage); | |
| 219 | $this->addLog(); | |
| 220 | } | |
| 221 | } | |
| 222 | ||
| 223 | /** | |
| 224 | * Execute the cronjob | |
| 225 | * | |
| 226 | * @author Stefan van Beusekom | |
| 227 | * @since 1.0 | |
| 228 | * @return boolean | |
| 229 | */ | |
| 230 | public function execute() {
| |
| 231 | register_shutdown_function(array($this, "onExecute")); | |
| 232 | $this->setTimelimit(); | |
| 233 | if ($this->allowExecute()) {
| |
| 234 | $this->setStartScript(); | |
| 235 | try {
| |
| 236 | $this->task(); | |
| 237 | } catch (Exception $e) {
| |
| 238 | $this->addError("The current task generated an exception, message: " . $e->getMessage());
| |
| 239 | } | |
| 240 | if ($this->isSuccessful()) {
| |
| 241 | $this->addLog(); | |
| 242 | $this->setEndScript(); | |
| 243 | $this->setLastExecuted(); | |
| 244 | } else {
| |
| 245 | $this->addLog(); | |
| 246 | } | |
| 247 | $this->_executionSuccessful = true; | |
| 248 | return $this->isSuccessful(); | |
| 249 | } | |
| 250 | $this->_executionSuccessful = true; | |
| 251 | return false; | |
| 252 | } | |
| 253 | ||
| 254 | /** | |
| 255 | * Task to be executed | |
| 256 | * | |
| 257 | * @author Stefan van Beusekom | |
| 258 | * @since 1.0 | |
| 259 | */ | |
| 260 | protected abstract function task(); | |
| 261 | } | |
| 262 | ||
| 263 | ?> |