CommandRunnable.php 4.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130
  1. <?php
  2. namespace addons\crontab\library;
  3. use fast\Http;
  4. use think\Config;
  5. use think\Db;
  6. class CommandRunnable implements \Jenner\SimpleFork\Runnable
  7. {
  8. protected $connect = null;
  9. protected $crontab = null;
  10. public function __construct($crontab)
  11. {
  12. $this->crontab = $crontab;
  13. }
  14. public function run()
  15. {
  16. $processId = getmypid();
  17. //这里需要强制重连数据库,使用已有的连接会报2014错误
  18. $this->connect = Db::connect([], true);
  19. $this->connect->execute("SELECT 1");
  20. $message = '';
  21. $result = false;
  22. $this->crontabLog = null;
  23. $log = [
  24. 'crontab_id' => $this->crontab['id'],
  25. 'executetime' => time(),
  26. 'completetime' => null,
  27. 'content' => '',
  28. 'processid' => $processId,
  29. 'status' => 'inprogress',
  30. ];
  31. $this->connect->name("crontab_log")->insert($log);
  32. $this->crontabLogId = $this->connect->getLastInsID();
  33. try {
  34. if ($this->crontab['type'] == 'url') {
  35. if (substr($this->crontab['content'], 0, 1) == "/") {
  36. // 本地项目URL
  37. $message = shell_exec('php ' . ROOT_PATH . 'public/index.php ' . $this->crontab['content']);
  38. $result = (bool)$message;
  39. } else {
  40. $arr = explode(" ", $this->crontab['content']);
  41. $url = $arr[0];
  42. $params = $arr[1] ?? '';
  43. $method = $arr[2] ?? 'POST';
  44. try {
  45. // 远程异步调用URL
  46. $ret = Http::sendRequest($url, $params, $method);
  47. $result = $ret['ret'];
  48. $message = $ret['msg'];
  49. } catch (\Exception $e) {
  50. $message = $e->getMessage();
  51. }
  52. }
  53. } elseif ($this->crontab['type'] == 'sql') {
  54. $ret = $this->sql($this->crontab['content']);
  55. $result = $ret['ret'];
  56. $message = $ret['msg'];
  57. } elseif ($this->crontab['type'] == 'shell') {
  58. // 执行Shell
  59. $message = shell_exec($this->crontab['content']);
  60. $result = !is_null($message);
  61. }
  62. } catch (\Exception $e) {
  63. $message = $e->getMessage();
  64. }
  65. //设定任务完成
  66. $this->connect->name("crontab_log")->where('id', $this->crontabLogId)->update(['content' => $message, 'completetime' => time(), 'status' => $result ? 'success' : 'failure']);
  67. }
  68. /**
  69. * 执行SQL语句
  70. */
  71. protected function sql($sql)
  72. {
  73. // 执行SQL
  74. $sqlquery = str_replace('__PREFIX__', config('database.prefix'), $sql);
  75. $sqls = preg_split("/;[ \t]{0,}\n/i", $sqlquery);
  76. $result = false;
  77. $message = '';
  78. $this->connect->startTrans();
  79. try {
  80. foreach ($sqls as $key => $val) {
  81. if (trim($val) == '' || substr($val, 0, 2) == '--' || substr($val, 0, 2) == '/*') {
  82. continue;
  83. }
  84. $message .= "\nSQL:{$val}\n";
  85. $val = rtrim($val, ';');
  86. if (preg_match("/^(select|explain)(.*)/i ", $val)) {
  87. $count = $this->connect->execute($val);
  88. if ($count > 0) {
  89. $resultlist = Db::query($val);
  90. } else {
  91. $resultlist = [];
  92. }
  93. $message .= "Total:{$count}\n";
  94. $j = 1;
  95. foreach ($resultlist as $m => $n) {
  96. $message .= "\n";
  97. $message .= "Row:{$j}\n";
  98. foreach ($n as $k => $v) {
  99. $message .= "{$k}:{$v}\n";
  100. }
  101. $j++;
  102. }
  103. } else {
  104. $count = $this->connect->getPdo()->exec($val);
  105. $message = "Affected rows:{$count}";
  106. }
  107. }
  108. $this->connect->commit();
  109. $result = true;
  110. } catch (\PDOException $e) {
  111. $message = $e->getMessage();
  112. $this->connect->rollback();
  113. $result = false;
  114. }
  115. return ['ret' => $result, 'msg' => $message];
  116. }
  117. }