• 首页
  • 碎语
  • 归档
  • 友联
  • 相册
  • 足迹
  • 关于
  • 搜索
  • 夜间模式
    ©2010-2026  点燃博客 Theme by OneBlog
    搜索
    标签
    # 日常记录 # 我的足迹 # Typecho 技巧 # 小神兽日常 # 电影 # 记录生活 # 折腾时光 # 书籍笔记 # 博客大事件 # 代码
  • 首页>
  • 整理收集>
  • 正文
  • 搭建微信公众号快速发布“时光机/说说” Typecho handsome主题

    2024年07月31日 5 阅读 5 评论 13465 字

    通过摸索和折腾,把一件事做成,会有一种小小的成就感。期待发现的问题,可以帮助需要的朋友。

    环境说明:

    Typecho 1.2.1 版本
    handsome主题 9.2.1 版本
    篱落VPS空间宝塔8.2.0 版本

    下载程序:

    微信公众号服务端Github 下载

    php环境基本要求:

    PHP >= 7.4
    PHP SimpleXML 扩展
    PHP fileinfo 扩展
    PHP PDO_MYSQL 扩展
    i> 对于空间是否支持以上服务可以使用PHP探针进行检测1
    (宝塔用户主要,检查PHP版本设置,扩展是否安装 fileinfo )2

    微信公众号配置

    页面配置服务器URL (微信公众号页面配置服务器URL(不支持二级目录作为接口地址),如果你的博客是https://blog.xxx.cn,那么这个域名可以是https://weixin.xxx.cn。)
    Token

    安装教程:

    1. 拷贝项目文件到服务器根目录
    2. 打开 网址/install.php 安装3
    3. 在公众号后台服务器配置填写服务器地址为 项目所在网址/server.php 并启用服务器配置
    4. 公众号发送绑定,点击链接填写相关信息进行绑定
      网址:你的博客地址。如:https://blog.xxx.cn
      openid:一般会自动获取
      cid:时光机/说说的页面cid(博客后台鼠标放在标题上获得链接地址cid=)
      cid密钥:自定义参,以防止他人操作发布(1、主题后台设置的身份验证值,2、微信公众号配置Token,3、 网址/install.php安装处Token,4处值保持一致)4
      mid:你想要发布文章的所属分类(可在后台获得)
    5. 配置完成,尽情使用吧!使用方法同handsome官方时光机发送公众号

    常见问题汇总:

    1、微信公众号配置URL提示:系统发生错误,请稍后重试
    解决思路:
    一、错误反馈未能和服务器地址连接,检查URL地址和格式是否正确
    二、访问 网址/server.php 检查程序运行是否正常,参考常见问题汇总3

    2、微信公众号配置提示:Token 验证失败
    解决思路:公众号Token、install.php安装Token、cid密钥、主题后台设置的身份验证值,四处是否保持一值。

    3、访问 网址/server.php 检查程序运行异常提示
    红底黑字:error on line 2 at column 1:Extra content at the end of the document
    解决方法:在服务端代码 /config.php 内大概13行高德API 暂时删除,保留$amapSecret =
    (一切正常后,此代码可以再加上,保证地图功能正常)

    4、公众号发送消息异常:身份验证失败
    解决方法:检查在服务端代码 /cross.php 内大概42行
    'time_code' => md5("$timecode"),
    md5 值是否存在乱码,进行修改,上面是正确显示。

    5、错误提示:Serialization of 'PDO' is not allowed
    解决方法:打开根目录 var/Typecho/Db.php 粘贴以下代码进行覆盖,强烈建议备份文件
    [collapse status="false" title="Db.php 代码"]

    <?php
    
    namespace Typecho;
    
    use Typecho\Db\Adapter;
    use Typecho\Db\Query;
    use Typecho\Db\Exception as DbException;
    
    /**
     * 包含获取数据支持方法的类.
     * 必须定义__TYPECHO_DB_HOST__, __TYPECHO_DB_PORT__, __TYPECHO_DB_NAME__,
     * __TYPECHO_DB_USER__, __TYPECHO_DB_PASS__, __TYPECHO_DB_CHAR__
     *
     * @package Db
     */
    class Db
    {
        /** 读取数据库 */
        public const READ = 1;
    
        /** 写入数据库 */
        public const WRITE = 2;
    
        /** 升序方式 */
        public const SORT_ASC = 'ASC';
    
        /** 降序方式 */
        public const SORT_DESC = 'DESC';
    
        /** 表内连接方式 */
        public const INNER_JOIN = 'INNER';
    
        /** 表外连接方式 */
        public const OUTER_JOIN = 'OUTER';
    
        /** 表左连接方式 */
        public const LEFT_JOIN = 'LEFT';
    
        /** 表右连接方式 */
        public const RIGHT_JOIN = 'RIGHT';
    
        /** 数据库查询操作 */
        public const SELECT = 'SELECT';
    
        /** 数据库更新操作 */
        public const UPDATE = 'UPDATE';
    
        /** 数据库插入操作 */
        public const INSERT = 'INSERT';
    
        /** 数据库删除操作 */
        public const DELETE = 'DELETE';
    
        /**
         * 数据库适配器
         * @var Adapter
         */
        private $adapter;
    
        /**
         * 默认配置
         *
         * @var array
         */
        private $config;
    
        /**
         * 已经连接
         *
         * @access private
         * @var array
         */
        private $connectedPool;
    
        /**
         * 前缀
         *
         * @access private
         * @var string
         */
        private $prefix;
    
        /**
         * 适配器名称
         *
         * @access private
         * @var string
         */
        private $adapterName;
    
        /**
         * 实例化的数据库对象
         * @var Db
         */
        private static $instance;
    
        /**
         * 数据库类构造函数
         *
         * @param mixed $adapterName 适配器名称
         * @param string $prefix 前缀
         *
         * @throws DbException
         */
        public function __construct($adapterName, string $prefix = 'typecho_')
        {
            /** 获取适配器名称 */
            $adapterName = $adapterName == 'Mysql' ? 'Mysqli' : $adapterName;
            $this->adapterName = $adapterName;
    
            /** 数据库适配器 */
            $adapterName = '\Typecho\Db\Adapter\\' . str_replace('_', '\\', $adapterName);
    
            if (!call_user_func([$adapterName, 'isAvailable'])) {
                throw new DbException("Adapter {$adapterName} is not available");
            }
    
            $this->prefix = $prefix;
    
            /** 初始化内部变量 */
            $this->connectedPool = [];
    
            $this->config = [
                self::READ => [],
                self::WRITE => []
            ];
    
            //实例化适配器对象
            $this->adapter = new $adapterName();
        }
    
        /**
         * @return Adapter
         */
        public function getAdapter(): Adapter
        {
            return $this->adapter;
        }
    
        /**
         * 获取适配器名称
         *
         * @access public
         * @return string
         */
        public function getAdapterName(): string
        {
            return $this->adapterName;
        }
    
        /**
         * 获取表前缀
         *
         * @access public
         * @return string
         */
        public function getPrefix(): string
        {
            return $this->prefix;
        }
    
        /**
         * @param Config $config
         * @param int $op
         */
        public function addConfig(Config $config, int $op)
        {
            if ($op & self::READ) {
                $this->config[self::READ][] = $config;
            }
    
            if ($op & self::WRITE) {
                $this->config[self::WRITE][] = $config;
            }
        }
    
        /**
         * getConfig
         *
         * @param int $op
         *
         * @return Config
         * @throws DbException
         */
        public function getConfig(int $op): Config
        {
            if (empty($this->config[$op])) {
                /** DbException */
                throw new DbException('Missing Database Connection');
            }
    
            $key = array_rand($this->config[$op]);
            return $this->config[$op][$key];
        }
    
        /**
         * 重置连接池
         *
         * @return void
         */
        public function flushPool()
        {
            $this->connectedPool = [];
        }
    
        /**
         * 选择数据库
         *
         * @param int $op
         *
         * @return mixed
         * @throws DbException
         */
        public function selectDb(int $op)
        {
            if (!isset($this->connectedPool[$op])) {
                $selectConnectionConfig = $this->getConfig($op);
                $selectConnectionHandle = $this->adapter->connect($selectConnectionConfig);
                $this->connectedPool[$op] = $selectConnectionHandle;
            }
    
            return $this->connectedPool[$op];
        }
    
        /**
         * 获取SQL词法构建器实例化对象
         *
         * @return Query
         */
        public function sql(): Query
        {
            return new Query($this->adapter, $this->prefix);
        }
    
        /**
         * 为多数据库提供支持
         *
         * @access public
         * @param array $config 数据库实例
         * @param integer $op 数据库操作
         * @return void
         */
        public function addServer(array $config, int $op)
        {
            $this->addConfig(Config::factory($config), $op);
            $this->flushPool();
        }
    
        /**
         * 获取版本
         *
         * @param int $op
         *
         * @return string
         * @throws DbException
         */
        public function getVersion(int $op = self::READ): string
        {
            return $this->adapter->getVersion($this->selectDb($op));
        }
    
        /**
         * 设置默认数据库对象
         *
         * @access public
         * @param Db $db 数据库对象
         * @return void
         */
        public static function set(Db $db)
        {
            self::$instance = $db;
        }
    
        /**
         * 获取数据库实例化对象
         * 用静态变量存储实例化的数据库对象,可以保证数据连接仅进行一次
         *
         * @return Db
         * @throws DbException
         */
        public static function get(): Db
        {
            if (empty(self::$instance)) {
                /** DbException */
                throw new DbException('Missing Database Object');
            }
    
            return self::$instance;
        }
    
        /**
         * 选择查询字段
         *
         * @param ...$ags
         *
         * @return Query
         * @throws DbException
         */
        public function select(...$ags): Query
        {
            $this->selectDb(self::READ);
    
            $args = func_get_args();
            return call_user_func_array([$this->sql(), 'select'], $args ?: ['*']);
        }
    
        /**
         * 更新记录操作(UPDATE)
         *
         * @param string $table 需要更新记录的表
         *
         * @return Query
         * @throws DbException
         */
        public function update(string $table): Query
        {
            $this->selectDb(self::WRITE);
    
            return $this->sql()->update($table);
        }
    
        /**
         * 删除记录操作(DELETE)
         *
         * @param string $table 需要删除记录的表
         *
         * @return Query
         * @throws DbException
         */
        public function delete(string $table): Query
        {
            $this->selectDb(self::WRITE);
    
            return $this->sql()->delete($table);
        }
    
        /**
         * 插入记录操作(INSERT)
         *
         * @param string $table 需要插入记录的表
         *
         * @return Query
         * @throws DbException
         */
        public function insert(string $table): Query
        {
            $this->selectDb(self::WRITE);
    
            return $this->sql()->insert($table);
        }
    
        /**
         * @param $table
         * @throws DbException
         */
        public function truncate($table)
        {
            $table = preg_replace("/^table\./", $this->prefix, $table);
            $this->adapter->truncate($table, $this->selectDb(self::WRITE));
        }
    
        /**
         * 执行查询语句
         *
         * @param mixed $query 查询语句或者查询对象
         * @param int $op 数据库读写状态
         * @param string $action 操作动作
         *
         * @return mixed
         * @throws DbException
         */
        public function query($query, int $op = self::READ, string $action = self::SELECT)
        {
            $table = null;
    
            /** 在适配器中执行查询 */
            if ($query instanceof Query) {
                $action = $query->getAttribute('action');
                $table = $query->getAttribute('table');
                $op = (self::UPDATE == $action || self::DELETE == $action
                    || self::INSERT == $action) ? self::WRITE : self::READ;
            } elseif (!is_string($query)) {
                /** 如果query不是对象也不是字符串,那么将其判断为查询资源句柄,直接返回 */
                return $query;
            }
    
            /** 选择连接池 */
            $handle = $this->selectDb($op);
    
            /** 提交查询 */
            $resource = $this->adapter->query($query instanceof Query ?
                $query->prepare($query) : $query, $handle, $op, $action, $table);
    
            if ($action) {
                //根据查询动作返回相应资源
                switch ($action) {
                    case self::UPDATE:
                    case self::DELETE:
                        return $this->adapter->affectedRows($resource, $handle);
                    case self::INSERT:
                        return $this->adapter->lastInsertId($resource, $handle);
                    case self::SELECT:
                    default:
                        return $resource;
                }
            } else {
                //如果直接执行查询语句则返回资源
                return $resource;
            }
        }
    
        /**
         * 一次取出所有行
         *
         * @param mixed $query 查询对象
         * @param callable|null $filter 行过滤器函数,将查询的每一行作为第一个参数传入指定的过滤器中
         *
         * @return array
         * @throws DbException
         */
        public function fetchAll($query, ?callable $filter = null): array
        {
            //执行查询
            $resource = $this->query($query);
            $result = $this->adapter->fetchAll($resource);
    
            return $filter ? array_map($filter, $result) : $result;
        }
    
        /**
         * 一次取出一行
         *
         * @param mixed $query 查询对象
         * @param callable|null $filter 行过滤器函数,将查询的每一行作为第一个参数传入指定的过滤器中
         * @return array|null
         * @throws DbException
         */
        public function fetchRow($query, ?callable $filter = null): ?array
        {
            $resource = $this->query($query);
    
            return ($rows = $this->adapter->fetch($resource)) ?
                ($filter ? call_user_func($filter, $rows) : $rows) :
                null;
        }
    
        /**
         * 一次取出一个对象
         *
         * @param mixed $query 查询对象
         * @param array|null $filter 行过滤器函数,将查询的每一行作为第一个参数传入指定的过滤器中
         * @return object|null
         * @throws DbException
         */
        public function fetchObject($query, ?array $filter = null): ?object
        {
            $resource = $this->query($query);
    
            return ($rows = $this->adapter->fetchObject($resource)) ?
                ($filter ? call_user_func($filter, $rows) : $rows) :
                null;
        }
    
        /**
         * 序列化时保存必要的配置信息,不包含连接池
         *
         * @return array
         */
        public function __serialize(): array
        {
            return [
                'adapterName' => $this->adapterName,
                'prefix' => $this->prefix,
                'config' => $this->config
            ];
        }
    
        /**
         * 反序列化时恢复配置并初始化适配器
         *
         * @param array $data 序列化数据
         * @return void
         */
        public function __unserialize(array $data): void
        {
            $this->adapterName = $data['adapterName'];
            $this->prefix = $data['prefix'];
            $this->config = $data['config'];
            $this->connectedPool = []; // 重置连接池,防止 PDO 被序列化
    
            // 重新实例化适配器
            $adapterName = '\Typecho\Db\Adapter\\' . str_replace('_', '\\', $this->adapterName);
            if (!class_exists($adapterName)) {
                throw new DbException("Adapter {$adapterName} is not available");
            }
            $this->adapter = new $adapterName();
        }
    }

    解决方法来自:秃头张
    [/collapse]

    如果问题依然没有解决,欢迎提问

    经历过数天不懈努力,将自己公众号搭建完成,中间遇到很多问题,也有一些问题并没写出来,并不是所有问题都可以用同样的方法可以解决。在向各位博主请假和搜索时发现,以上问题是询问最多的一部分,今天整理出来供参考,希望可以帮助更多的博主。
    在此感谢
    1、空空裤兜、一句话点醒
    2、目的地-Destination、远程协助修改,反复解决异常问题
    3、白亮吖雅黑丫の小站、解决问题思路解答
    4、还有很多博文参考,博主们
    5、必应、百度

    以上感谢不分前后,每一次的成功离不开所有帮助过的朋友,谢谢你们!!!


    1. 空间某些扩展不支持 ↩
    2. 容易忽略扩展安装 ↩
    3. 注意此处Token和高德API ↩
    4. cid秘钥和Token 值保持一致 ↩
    本文著作权归作者 [ 点燃 ] 享有,未经作者书面授权,禁止转载,封面图片来源于 [ 互联网 ] ,本文仅供个人学习、研究和欣赏使用。如有异议,请联系博主及时处理。
    Typecho 技巧
    取消回复

    发表留言
    回复

    读者留言5

    1. 大峰 Lv.2
      2024-10-12 11:09 回复

      这个很厉害! ::twemoji:star::

    2. 老孙 Lv.1
      2024-07-31 16:42 回复

      是支持二级目录的吧 我以前就放在子目录里的OωO

      1. 星图 博主
        2024-08-02 10:05 回复
        @老孙

        文件可以放在二级目录里,在微信公众号URL设置不支持https://www.xxxx.com/weixin/server.php 二级格式

    3. 空空裤兜 Lv.1
      2024-07-31 15:43 回复

      记录折腾经历很不错,我都是折腾,然后下次不会了再百度,浪费时间。

      1. 星图 博主
        2024-08-02 10:25 回复
        @空空裤兜

        记录下疼苦点,下次重置好恢复 ::aru:cryingface::

    加载更多评论
    加载中...
    — 已加载全部评论 —
    首页碎语归档友联相册足迹关于
    Copyright©2010-2026  点燃博客.  Load:0.025 s
    Theme by OneBlog V3.6.4
    夜间模式

    开源不易,请尊重作者版权,保留基本的版权信息。