标签:
写一个cli的入口文件
cli.php
<?php define(‘MODE_NAME‘, ‘cli‘); // 检测PHP环境 if(version_compare(PHP_VERSION,‘5.3.0‘,‘<‘)) die(‘require PHP > 5.3.0 !‘); define(‘APP_DEBUG‘, true); // 定义应用目录 define(‘APP_PATH‘, __DIR__ . ‘/Application/‘); // 引入ThinkPHP入口文件 require __DIR__ . ‘/ThinkPHP/ThinkPHP.php‘;
写一个执行文件
cron.php
define(‘AUTO_CRON‘, true); include __DIR__ . ‘/cli.php‘;
数据库设计
DROP TABLE IF EXISTS `cron`; CREATE TABLE IF NOT EXISTS `cron` ( `cron_id` int(10) unsigned NOT NULL AUTO_INCREMENT, `name` varchar(255) COLLATE utf8_unicode_ci NOT NULL DEFAULT ‘‘, `expression` varchar(255) COLLATE utf8_unicode_ci NOT NULL DEFAULT ‘‘, `class` varchar(255) COLLATE utf8_unicode_ci NOT NULL DEFAULT ‘‘, `method` varchar(255) COLLATE utf8_unicode_ci NOT NULL DEFAULT ‘‘, `type` varchar(30) COLLATE utf8_unicode_ci NOT NULL DEFAULT ‘‘, `status` varchar(30) COLLATE utf8_unicode_ci NOT NULL DEFAULT ‘‘, `created_at` timestamp NOT NULL DEFAULT ‘0000-00-00 00:00:00‘, `updated_at` timestamp NOT NULL DEFAULT ‘0000-00-00 00:00:00‘, `run_at` timestamp NULL DEFAULT NULL, `ms` int(10) unsigned NOT NULL DEFAULT ‘0‘, `error` text COLLATE utf8_unicode_ci NOT NULL, PRIMARY KEY (`cron_id`), KEY `name` (`name`,`created_at`), KEY `cron_status_index` (`status`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci AUTO_INCREMENT=1 ;
执行文件 init.php
/写个hook程序执行init.php
<?php use Think\Log, Think\Db, Cron\Model\Cron; $Model = new \Think\Model(); $Has = !$Model->query("SHOW TABLES LIKE ‘cron‘")?false:true; if(defined("AUTO_CRON") && $Has){ class CronCommand { protected $_initializedJobs; protected $_jobs; protected $_now; public function __construct() { $this->_now = strtotime(date(‘Y-n-j H:i‘)); import("Cron.Common.Cron.tdcron_entry",‘‘,‘.php‘); import("Cron.Common.Cron.tdcron",‘‘,‘.php‘); } /** * 这里是放要执行的代码 */ public function fire() { restore_error_handler(); restore_exception_handler(); $this->_initializedJobs = array(); $jobs = M(‘cron‘)->where("status = ‘initialized‘")->select(); /** * @var $cron Cron * 已存在 cron */ if($jobs) { $cron = new Cron(); foreach ($jobs as $data) { $cron->setData($data)->isNew(false); $this->_initializedJobs[$data[‘name‘]] = $cron; } } /** * 新 cron */ foreach ($this->getCronJobs() as $name => $cronJob) { if (isset($cronJob[‘expression‘])) { $expression = $cronJob[‘expression‘]; } else { Log::write(‘Cron expression is required for cron job "‘ . $name . ‘"‘,Log::WARN); continue; } if ($this->_now != tdCron::getNextOccurrence($expression, $this->_now)) continue; $cronJob[‘name‘] = $name; $cron = isset($this->_initializedJobs[$name]) ? $this->_initializedJobs[$name] : $this->_initializedJobs[$name] = new Cron(); $cron->initialize($cronJob); } /* @var $cron Cron 处理*/ foreach ($this->_initializedJobs as $cron) { $cron->run(); } } /** * Get All Defined Cron Jobs * 获取配置 * @return array */ public function getCronJobs() { if ($this->_jobs === null) { $this->_jobs = C(‘beastalkd‘); } return $this->_jobs; } } $command = new CronCommand(); $command->fire(); }
cron 模型
<?php namespace Cron\Model; use Common\Model; use Think\Log; /** * Class Cron * @method string getClass() * @method string getMethod() * @method string getName() * @method string getType() * @package Cron\Model */ class Cron extends Model{ const STATUS_COMPLETED = ‘completed‘; const STATUS_FAILED = ‘failed‘; const STATUS_INITIALIZED = ‘initialized‘; const STATUS_RUNNING = ‘running‘; protected $name = ‘cron‘; protected $tableName = ‘cron‘; protected $pk = ‘cron_id‘; protected $_originalData = array(); /** * 保存配置信息CLASS */ protected static $_cron_classes = array(); /** * @param $class * @return mixed 获取配置的 CLASS */ public function getSingleton($class) { isset(static::$_cron_classes[$class]) or static::$_cron_classes[$class] = new $class; return static::$_cron_classes[$class]; } /** * @param $cronJob * @return $this * 初始化 任务状态 */ public function initialize($cronJob) { foreach ($cronJob as $k => $v) { $this->setData($k, $v); } $now = date(‘Y-m-d H:i:s‘); $this->setData(‘status‘,self::STATUS_INITIALIZED)->setData(‘created_at‘,$now)->setData(‘updated_at‘,$now)->save(); return $this; } /** * @return $this run 命令 */ public function run() { $this->setData(‘run_at‘,date(‘Y-m-d H:i:s‘))->setData(‘status‘,self::STATUS_RUNNING)->save(); Timer::start(); try { $class = $this->getData(‘class‘); $method = $this->getData(‘method‘); if (!class_exists($class)) throw new \Exception(sprintf(‘Class "%s" not found!‘, $class)); if (!method_exists($class, $method)) throw new \Exception(sprintf(‘Method "%s::%s()" not found!‘, $class, $method)); $callback = array($this->getSingleton($class), $method); //new CLASS 使用操作方法 call_user_func($callback); Timer::stop(); $this->setData(‘ms‘,round(Timer::diff() * 1000))->setData(‘status‘,self::STATUS_COMPLETED)->save(); } catch (\Exception $e) { Timer::stop(); $this->setData(‘ms‘,round(Timer::diff() * 1000)) ->setData(‘status‘,self::STATUS_FAILED) ->setData(‘error‘,$e->getMessage() . "\nParams:\n" . var_export($this->getDbFields(), true))->save(); Log::write($e->getMessage() . "\n" . $e->getTraceAsString(),Log::ERR); } return $this; } }
Common\Model 模型
<?php namespace Common; use Think\Model as ThinkModel; /** * Class Model * @package Common * * @property \Think\Db\Driver\Mysql $db DB instance */ abstract class Model extends ThinkModel { protected $_isNew = true; protected $_jsonFields = array(); protected $_originalData = array(); protected function _after_find(&$result, $options) { foreach ($this->_jsonFields as $field) { is_string($_data = fnGet($result, $field)) and $result[$field] = json_decode($_data, true); } $this->_originalData = $result; $this->_isNew = !$result; parent::_after_find($result, $options); } protected function _after_save($result) { } protected function _before_find() { $this->_originalData = array(); } protected function _facade($data) { foreach ($this->_jsonFields as $field) { is_array($_data = fnGet($data, $field)) and $data[$field] = json_encode($_data); } return parent::_facade($data); } public function find($options = array()) { $this->_before_find(); return parent::find($options); } public function getData($key = null) { return $key === null ? $this->data : $this->__get($key); } public function getOptions() { return $this->options; } public function getOriginalData($key = null) { return $key === null ? $this->_originalData : fnGet($this->_originalData, $key); } /** * Get or set isNew flag * * @param bool $flag * * @return bool */ public function isNew($flag = null) { if ($flag !== null) $this->_isNew = (bool)$flag; return $this->_isNew; } public function save($data = ‘‘, $options = array()) { if ($this->_isNew) { $oldData = $this->data; $result = $this->add($data, $options); $this->data = $oldData; if ($result && $this->pk && is_string($this->pk)) { $this->setData($this->pk, $result); } $this->_isNew = false; } else { $oldData = $this->data; $result = parent::save($data, $options); $this->data = $oldData; } $this->_after_save($result); return $result; } public function setData($key, $value = null) { is_array($key) ? $this->data = $key : $this->data[$key] = $value; return $this; } }
标签:
原文地址:http://my.oschina.net/xinson/blog/416652