├── .gitignore ├── index.php ├── config.php ├── lib ├── functions.php └── db.php ├── controller ├── textMsgController.php ├── eventMsgController.php └── baseMsgController.php └── core.php /.gitignore: -------------------------------------------------------------------------------- 1 | .idea 2 | -------------------------------------------------------------------------------- /index.php: -------------------------------------------------------------------------------- 1 | run(); 14 | -------------------------------------------------------------------------------- /config.php: -------------------------------------------------------------------------------- 1 | 'testtoken233', 5 | 'db' => [ 6 | 'host' => 'localhost', 7 | 'user' => 'root', 8 | 'pwd' => '', 9 | 'db' => 'demo', 10 | 'prefix' => '' 11 | ], 12 | 'default_reply'=>'默认回复内容' 13 | ]; 14 | -------------------------------------------------------------------------------- /lib/functions.php: -------------------------------------------------------------------------------- 1 | post->Content)) return; 22 | $content = $this->post->Content->__toString(); 23 | 24 | return $this->post->Content->__toString(); 25 | } 26 | 27 | } -------------------------------------------------------------------------------- /controller/eventMsgController.php: -------------------------------------------------------------------------------- 1 | post->Event->__toString(); 24 | if (method_exists($this, $event)) { 25 | return call_user_func([$this, $event]); 26 | } 27 | } 28 | 29 | /** 30 | * 订阅 31 | * @return string 32 | */ 33 | protected function subscribe() { 34 | return '垃圾'; 35 | } 36 | 37 | /** 38 | * 取消订阅 39 | * @return string 40 | */ 41 | protected function unsubscribe() { 42 | return ''; 43 | } 44 | } -------------------------------------------------------------------------------- /core.php: -------------------------------------------------------------------------------- 1 | config = require_once 'config.php'; 21 | spl_autoload_register([$this, 'autoload']); 22 | } 23 | 24 | /** 25 | * @var core 26 | */ 27 | public static $instance; 28 | 29 | /** 30 | * 调用实例 31 | * @return core 32 | */ 33 | public static function app() { 34 | return static::$instance; 35 | } 36 | 37 | /** 38 | * 自动加载 39 | * @param $class 40 | */ 41 | public function autoload($class) { 42 | $class = str_replace('\\', '/', $class); 43 | require_once $class . '.php'; 44 | } 45 | 46 | /** 47 | * 开始运行,对一些数据进行处理 48 | */ 49 | public function run() { 50 | if (!isset_r($_GET, 'signature,timestamp,nonce')) { 51 | die('error request'); 52 | } 53 | $array = array($this->config ['token'], $_GET['timestamp'], $_GET['nonce']); 54 | sort($array, SORT_STRING); 55 | $str = implode($array); 56 | $sign = sha1($str); 57 | if ($sign == $_GET['signature']) { 58 | //校验成功,开始处理接收内容 59 | if (isset($_GET['echostr'])) { 60 | die($_GET['echostr']); 61 | } 62 | $this->post = file_get_contents('php://input'); 63 | if ($this->post == '') { 64 | return; 65 | } 66 | $this->start(); 67 | } 68 | } 69 | 70 | /** 71 | * 开始对接,解析接收到的xml 72 | */ 73 | protected function start() { 74 | $this->post = simplexml_load_string($this->post); 75 | if (!isset($this->post->MsgType)) { 76 | die('error'); 77 | } 78 | //初始化数据库链接 79 | \lib\db::init($this->config['db']['host'], $this->config['db']['user'], 80 | $this->config['db']['pwd'], $this->config['db']['db'], 81 | $this->config['db']['prefix'] 82 | ); 83 | \lib\db::query('set names utf8'); 84 | $class = 'controller\\' . $this->post->MsgType->__toString() . 'MsgController'; 85 | new $class($this->post); 86 | } 87 | } -------------------------------------------------------------------------------- /controller/baseMsgController.php: -------------------------------------------------------------------------------- 1 | post = $post; 24 | if (!$this->verify()) { 25 | return; 26 | } 27 | $msg = $this->msgdeal(); 28 | if (is_array($msg)) { 29 | echo $this->reply($msg); 30 | } else if (is_string($msg)) { 31 | echo $this->replyText($msg); 32 | } 33 | } 34 | 35 | /** 36 | * 验证数据是否正确 37 | * @return bool 38 | */ 39 | protected function verify(): bool { 40 | if (!(isset($_GET['openid']) == $this->post->FromUserName->__toString())) { 41 | return false; 42 | } 43 | if (abs($_GET['timestamp'] - $this->post->CreateTime) > 5) { 44 | return false; 45 | } 46 | return true; 47 | } 48 | 49 | /** 50 | * 消息处理 51 | * @return mixed 52 | */ 53 | abstract protected function msgdeal(); 54 | 55 | /** 56 | * 回复xml文本 57 | * @param array $array 58 | * @return string 59 | */ 60 | public function reply(array $array, bool $out = false): string { 61 | $array = $this->replyDefault($array); 62 | $text = ''; 63 | foreach ($array as $key => $value) { 64 | if (is_string($value)) { 65 | $text .= "<$key>"; 66 | } else { 67 | $text .= "<$key>$value"; 68 | } 69 | } 70 | $text .= ''; 71 | if ($out) { 72 | echo $text; 73 | } 74 | return $text; 75 | } 76 | 77 | /** 78 | * 构造回复信息的一些默认值 79 | * @param array $array 80 | * @return array 81 | */ 82 | protected function replyDefault(array $array): array { 83 | if (!isset($array['ToUserName'])) { 84 | $array['ToUserName'] = $this->post->FromUserName->__toString(); 85 | } 86 | if (!isset($array['FromUserName'])) { 87 | $array['FromUserName'] = $this->post->ToUserName->__toString(); 88 | } 89 | if (!isset($array['CreateTime'])) { 90 | $array['CreateTime'] = time(); 91 | } 92 | return $array; 93 | } 94 | 95 | /** 96 | * 回复文本信息 97 | * @param string $text 98 | * @return string 99 | */ 100 | public function replyText(string $text): string { 101 | return $this->reply(['MsgType' => 'text', 'Content' => $text]); 102 | } 103 | } -------------------------------------------------------------------------------- /lib/db.php: -------------------------------------------------------------------------------- 1 | getDBObject($table); 57 | } 58 | 59 | public static function init($host = '', $user = '', $pwd = '', $db = '', $prefix = '') { 60 | $dns = 'mysql:dbname=' . $db . ';host='; 61 | $dns .= $host . ';charset=utf8'; 62 | static::$db = new PDO($dns, $user, $pwd); 63 | static::$db->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION); 64 | static::$db->setAttribute(PDO::ATTR_EMULATE_PREPARES, false); 65 | static::$prefix = $prefix; 66 | } 67 | 68 | /** 69 | * 获取一个数据库操作对象 70 | * @param $table 71 | * @return db 72 | */ 73 | public static function table($table) { 74 | return new db($table); 75 | } 76 | 77 | public static function query($sql) { 78 | return static::$db->query($sql); 79 | } 80 | 81 | public function getDBObject($table = '') { 82 | if (substr($table, 0, 1) == ':') { 83 | $this->table = substr($table, 1); 84 | } else { 85 | $this->table = static::$prefix . str_replace('|', ',' . static::$prefix, $table); 86 | preg_match_all('/,([\d\w_]+)/', ',' . $this->table, $arr);//直接在前面加个逗号...不处理了... 87 | $this->arrTable = $arr[1]; 88 | } 89 | return $this; 90 | } 91 | 92 | public function __call($func, $arguments) { 93 | if (is_null(static::$db)) { 94 | return 0; 95 | } 96 | return call_user_func_array(array( 97 | static::$db, 98 | $func 99 | ), $arguments); 100 | } 101 | 102 | /** 103 | * 数组转换成查询的条件 104 | * @param $where 105 | * @param $param 106 | * @return string 107 | */ 108 | protected function where($where, &$param) { 109 | if (empty($where)) { 110 | throw new \Exception('Sql where can not be empty'); 111 | } 112 | $sql = ' '; 113 | $logical = ''; 114 | $subscript = 0; 115 | foreach ($where as $key => $value) { 116 | $start = ''; 117 | $end = ''; 118 | if (is_numeric($key)) { 119 | if (is_string($value)) { 120 | $sql .= ($subscript++ == 0 ? 'where ' : ' and ') . $value; 121 | continue; 122 | } 123 | $key = $value[0]; 124 | array_splice($value, 0, 1); 125 | } 126 | if (is_array($value)) { 127 | $arrsize = sizeof($value); 128 | $isarr = is_array($value [0]); 129 | $operator = ''; 130 | if ($isarr) { 131 | $tmpArr = $value[0]; 132 | $value[0] = '('; 133 | foreach ($tmpArr as $v) { 134 | $value[0] .= '?,'; 135 | $param[] = $v; 136 | } 137 | $value[0] = substr($value[0], 0, strlen($value[0]) - 1); 138 | $value[0] .= ')'; 139 | } else { 140 | $param[] = $value[0]; 141 | $value[0] = ' ? '; 142 | } 143 | $logical = ''; 144 | for ($n = 1; $n < $arrsize; $n++) { 145 | if (in_array($value[$n], $this->logical)) { 146 | $logical = $value[$n]; 147 | } else if (in_array($value[$n], $this->mark)) { 148 | switch ($value[$n]) { 149 | case 'b_start': 150 | { 151 | $start = '('; 152 | break; 153 | } 154 | case 'b_end': 155 | { 156 | $end = ')'; 157 | break; 158 | } 159 | } 160 | } else { 161 | $operator = $value[$n]; 162 | } 163 | } 164 | $sql .= ($subscript++ == 0 ? 'where ' : ($logical ?: ' and ')); 165 | if ($operator == '' and $isarr) { 166 | $operator = 'in'; 167 | } 168 | $sql .= preg_replace(array( 169 | '/\$start/', 170 | '/\$key/', 171 | '/\$operator/', 172 | '/\$value/', 173 | '/\$end/', 174 | ), array( 175 | $start, 176 | $key, 177 | $operator ?: '=', 178 | !empty($value[0]) ? $value[0] : 'null', 179 | $end 180 | ), '$start $key $operator $value $end'); 181 | } else if (is_numeric($key)) { 182 | $sql .= ($subscript++ == 0 ? 'where ' : ' and ') . $value . ' '; 183 | } else if (substr($key, 0, 2) == '__') { 184 | $sql .= ' ' . substr($key, 2) . ' ' . $value . ' '; 185 | } else { 186 | $sql .= ($subscript++ == 0 ? 'where ' : ' and ') . $key . ' = ? '; 187 | $param[] = $value; 188 | } 189 | } 190 | return $sql; 191 | } 192 | 193 | /** 194 | * 插入一条数据返回改变条数 195 | * 196 | * @access public 197 | * @author Farmer 198 | * @param array $data 199 | * @return int 200 | */ 201 | public function insert($data = 0) { 202 | if (!empty ($data)) { 203 | $table = $this->table; 204 | $param = []; 205 | $sql = 'insert into ' . $table . '(`' . implode('`,`', array_keys($data)) . '`) values('; 206 | foreach ($data as $value) { 207 | $sql .= '?,'; 208 | $param[] = $value; 209 | } 210 | $sql = substr($sql, 0, strlen($sql) - 1); 211 | $sql .= ')'; 212 | $result = static::$db->prepare($sql); 213 | if ($count = $result->execute($param)) { 214 | return $result->rowCount(); 215 | } 216 | return false; 217 | } 218 | return false; 219 | } 220 | 221 | /** 222 | * 删除数据返回变化条数 223 | * 224 | * @author Farmer 225 | * @param mixed $where 226 | * @return int 227 | */ 228 | public function delete($where = 0) { 229 | $sql = "delete from $this->table"; 230 | $param = []; 231 | if (is_string($where)) { 232 | $sql .= $where; 233 | } else if (is_array($where) and !empty($where)) { 234 | $sql .= $this->where($where, $param); 235 | } 236 | $result = static::$db->prepare($sql); 237 | if ($count = $result->execute($param)) { 238 | return $result->rowCount(); 239 | } 240 | return false; 241 | } 242 | 243 | /** 244 | * 修改数据返回变化条数 245 | * 246 | * @access public 247 | * @author Farmer 248 | * @param array $where 249 | * @return int 250 | */ 251 | function update($data, $where = 0) { 252 | $sql = "update $this->table set "; 253 | $param = []; 254 | if (is_string($data)) { 255 | $sql .= $data; 256 | } else if (is_array($data)) { 257 | $add = 0; 258 | foreach ($data as $key => $value) { 259 | if (is_numeric($key)) { 260 | $sql .= ($add++ != 0 ? ',' : '') . $value; 261 | } else { 262 | $sql .= ($add++ != 0 ? ',' : '') . $key . '= ? '; 263 | $param[] = $value; 264 | } 265 | } 266 | } 267 | if (is_string($where)) { 268 | $sql .= $where; 269 | } else if (is_array($where)) { 270 | $sql .= $this->where($where, $param); 271 | } 272 | $result = static::$db->prepare($sql); 273 | if ($result->execute($param)) { 274 | return $result->rowCount(); 275 | } 276 | return false; 277 | } 278 | 279 | /** 280 | * 查询返回sql记录集 281 | * @param int $where 282 | * @param int $field 283 | * @param string $join 284 | * @return bool|record 285 | * @throws \Exception 286 | */ 287 | function select($where = 0, $field = 0, $join = '') { 288 | $sql = 'select ' . (empty($field) ? '*' : $field); 289 | $join = str_replace(':', static::$prefix, $join); 290 | $sql .= " from $this->table $join"; 291 | $param = []; 292 | if (is_string($where)) { 293 | $sql .= $where; 294 | } else if (is_array($where)) { 295 | $sql .= $this->where($where, $param); 296 | } 297 | $result = static::$db->prepare($sql); 298 | if ($result->execute($param)) { 299 | return new record($result); 300 | } 301 | return false; 302 | } 303 | 304 | /** 305 | * 查找 306 | * @param int $where 307 | * @param int $field 308 | * @param string $join 309 | * @return mixed 310 | * @throws \Exception 311 | */ 312 | function find($where = 0, $field = 0, $join = '') { 313 | $where['__limit'] = '1'; 314 | return $this->select($where, $field, $join)->fetch(); 315 | } 316 | 317 | /** 318 | * 开始事务 319 | * @author Farmer 320 | */ 321 | function begin() { 322 | $this->exec('begin'); 323 | } 324 | 325 | /** 326 | * 提交事务 327 | * @author Farmer 328 | */ 329 | function commit() { 330 | $this->exec('commit'); 331 | } 332 | 333 | /** 334 | * 回滚事务 335 | * @author Farmer 336 | */ 337 | function rollback() { 338 | $this->exec('rollback'); 339 | } 340 | } 341 | 342 | /** 343 | * 记录集类 344 | * Class record 345 | * @package lib 346 | */ 347 | class record { 348 | 349 | /** 350 | * @var \PDOStatement 351 | */ 352 | private $result; 353 | 354 | public function __call($func, $arguments) { 355 | if (is_null($this->result)) { 356 | return 0; 357 | } 358 | return call_user_func_array(array( 359 | $this->result, 360 | $func 361 | ), $arguments); 362 | } 363 | 364 | function __construct($result) { 365 | $this->result = $result; 366 | $this->result->setFetchMode(PDO::FETCH_ASSOC); 367 | } 368 | 369 | public function countAll() { 370 | $rec = db::query('select FOUND_ROWS()'); 371 | return $rec->fetch()['FOUND_ROWS()']; 372 | } 373 | 374 | public function fetch() { 375 | return $this->result->fetch(); 376 | } 377 | } 378 | --------------------------------------------------------------------------------