分类 PHP 下的文章

升级PHP7之后微信公众号开发遇到的几个问题

由于微信公众号官方给出的示例代码都是比较老旧的,基本支持的都是PHP5.6以前的版本。如果将PHP版本升级到PHP7,那么代码无法正常运行,大概有下面几个问题:

一、$GLOBALS["HTTP_RAW_POST_DATA"] 失效

原因:经过在网上查询发现 PHP >= 5.6 的时候 HTTP_RAW_POST_DATA 被移除了。但是 PHP = 5.6 还可以在配置文件 php.ini 还能找到 always_populate_raw_post_data 选项。当 PHP >= 7.0 就已经彻底移除了 always_populate_raw_post_data 配置。
解决方案:使用file_get_contents('php://input');代替。

二、提示构造函数deprecated

原因:自 PHP 5.3.3 起,在命名空间中,与类名同名的方法不再作为构造函数。不使用命名空间中的类则不受影响。
解决方案:修改pkcs7Encoder.phpwxBizMsgCrypt.php两个文件中的构造函数,使用__construct即可。

三、mcrypt_module_open函数报错

原因:在 PHP7mcrypt_module_open()已经被 OPENSSL 取代。
解决方案:修改pkcs7Encoder.php文件中Prpcrypt类的encryptdecrypt方法,重点是使用openssl_encryptopenssl_decrypt代替mcrypt_开头的函数。为避免表达不清楚,将代码贴在下面。

public function encrypt($text, $appid)
{

    try {
        // 获得16位随机字符串,填充到明文之前
        $random = $this->getRandomStr();
        $text = $random . pack("N", strlen($text)) . $text . $appid;
        // 网络字节序
//         $size = mcrypt_get_block_size(MCRYPT_RIJNDAEL_128, MCRYPT_MODE_CBC);
//         $module = mcrypt_module_open(MCRYPT_RIJNDAEL_128, '', MCRYPT_MODE_CBC, '');
        $iv = substr($this->key, 0, 16);
        //使用自定义的填充方式对明文进行补位填充
        $pkc_encoder = new PKCS7Encoder;
        $text = $pkc_encoder->encode($text);
//         mcrypt_generic_init($module, $this->key, $iv);
//         //加密
//         $encrypted = mcrypt_generic($module, $text);
// 下面这句是重点,使用openssl方法
        $encrypted = openssl_encrypt($text, 'AES-256-CBC', $this->key, OPENSSL_ZERO_PADDING, $iv);
//         mcrypt_generic_deinit($module);
//         mcrypt_module_close($module);

        //print(base64_encode($encrypted));
        //使用BASE64对加密后的字符串进行编码
//         return array(ErrorCode::$OK, base64_encode($encrypted));
        return array(ErrorCode::$OK, $encrypted);
    } catch (Exception $e) {
        //print $e;
        return array(ErrorCode::$EncryptAESError, null);
    }
}

// 只截取了一部分
public function decrypt($encrypted, $appid)
{

    try {
        //使用BASE64对需要解密的字符串进行解码
//         $ciphertext_dec = base64_decode($encrypted);
//         $module = mcrypt_module_open(MCRYPT_RIJNDAEL_128, '', MCRYPT_MODE_CBC, '');
        $iv = substr($this->key, 0, 16);
//         mcrypt_generic_init($module, $this->key, $iv);

//         //解密
//         $decrypted = mdecrypt_generic($module, $ciphertext_dec);
//         mcrypt_generic_deinit($module);
//         mcrypt_module_close($module);
        $decrypted = openssl_decrypt($encrypted, 'AES-256-CBC', $this->key, OPENSSL_ZERO_PADDING, $iv);
    } catch (Exception $e) {
        return array(ErrorCode::$DecryptAESError, null);
    }
...

MySQL配合ThinkPHP(tp6.0.8)实现消息队列

参考上一篇文章:Redis配合ThinkPHP(tp6.0.8)实现消息队列

配置

和Redis版本不一样地方主要在于config\queue.php配置,如下图:
微信截图_20210709161558.png

和Redis版本一样,配置文件中其他参数都是安装think-queue时默认生成的,我没有做改动。

重点部分

和Redis不同的是,MySQL实现消息队列需要两个数据库表:jobsfailed_jobs(如果是自己添加时需加上前缀),通过migrate方式生成,会自动添加表前缀。

首先,安装think-queque扩展:composer require topthink/think-migration,如果是tp5.1,则只能安装2.x版本,使用命令:composer require topthink/think-migration=2.0.*

然后,执行两条命令,分别生成jobsfailed_jobs表的迁移类文件:
php think queue:table
php think queue:failed-table

最后,执行php think migrate:run,数据库表就生成好了。

当然,也可以自行在数据库中添加这两张表,下面列出它们的结构:

CREATE TABLE `jobs` (
 `id` int(11) NOT NULL AUTO_INCREMENT,
 `queue` varchar(255) NOT NULL,
 `payload` longtext NOT NULL,
 `attempts` tinyint(3) unsigned NOT NULL,
 `reserve_time` int(11) unsigned DEFAULT NULL,
 `available_time` int(11) unsigned NOT NULL,
 `create_time` int(11) unsigned NOT NULL,
 PRIMARY KEY (`id`),
 KEY `queue` (`queue`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8

CREATE TABLE `failed_jobs` (
 `id` int(11) NOT NULL AUTO_INCREMENT,
 `connection` text NOT NULL,
 `queue` text NOT NULL,
 `payload` longtext NOT NULL,
 `exception` longtext NOT NULL,
 `fail_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
 PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8

剩余的操作和Redis一致,全文结束。

Redis配合ThinkPHP(tp6.0.8)实现消息队列

运行环境

Windows 10 本地环境
PHP 7.2.9
ThinkPHP v6.0.8
Redis v3.2.100

安装

tp6.0只能通过composer方式安装,而且默认框架不带ORM和Queue,都需要通过composer方式安装。tp6.0环境默认安装的是最新版think-queue,目前是3.X版本
composer require topthink/think-queue

注意:如果是tp5.1,只能安装2.X版本,命令为:composer require topthink/think-queue=2.*

验证是否安装成功,只需命令行执行:php think queue:listen -h,看到如下画面,说明安装成功。
微信截图_20210708154210.png

配置

安装成功之后,在config目录下会有一个queue.php文件,我们选择redis驱动类型,默认驱动类型是sync,即同步执行。
微信截图_20210708154515.png

- 阅读剩余部分 -

微信支付APIv3 在PHP开发(H5支付、APP支付)中容易犯错的地方记录

PHP 7.2.X

微信支付API已经更新到v3版本,同时文档也做了更新,相比之前的版本,条理更清晰,但难免还是有一些地方没讲的太清楚,刚接触的人很容易犯错。

一个很大的改动是SDK。之前是官网可以直接下载一个SDK包,然后照着里面的Demo,加上自己的配置,调试一番就基本可以走通。

但现在不是了,官方提供了一个 wechatpay-guzzle-middleware 库,按照GitHub上的说明,通过composer安装即可。由于这个库是依赖于guzzle的,所以,如果你还没有安装guzzle(6.0+),那么同样需要使用composer进行安装。假如你不想用composer安装,也可以,那就按照各自文档的详细说明,去下载库文件,然后引入自己的代码中。不得不说,composer安装还是十分的方便。

安装好库(其实也可以理解成SDK)之后,按照GitHub上的示例代码(分别演示了POST和GET两种请求如何发送),填写相应的参数,即可发起支付请求了。有三个需要注意的参数(见下图):
微信截图_20210208153952.png

  1. 上图1 微信支付平台证书,通过 证书下载工具 下载,放置到网站中,PemUtil::loadCertificate根据路径参数就可以读取到证书内容;注意:这里的证书要和下面的商户证书区分。
  2. 上图2 商户密钥3 商户API证书序列号接入前准备 这里都可以获取到。不要捉急,一步一步按照文档来操作。很幸运,这两个参数我都一次性拿到了。

- 阅读剩余部分 -

PHP单点登录SSO简单示例Demo

我本地建了三个测试站点,分别为:

  1. www.testa.com
  2. www.testb.com
  3. www.sso.com

其中,站点sso是用于集中验证的站点。

访问站点testa index.php

<?php
// testa: index.php
$url = urlencode("http://www.testa.com/");

if ($_GET['action'] == 'logout') {
    setcookie("islogged");
}

if (isset($_GET['token']) && !empty($_GET['token'])) {
    $token = $_GET['token'];
    $res = file_get_contents("http://www.sso.com/verify.php?token={$token}");
    if ($res == 'yes') {
        echo "verify success";
        setcookie('islogged', true);
    } else {
        echo "verify fail";
    }
    header("Location: index.php");
    exit;
}

if ($_COOKIE['islogged'] == true) {
    echo "a success";
} else {
    echo "fail";
    header("Location: http://www.sso.com/index.php?redirect={$url}");
}

程序判断用户是否登录站点testa,如果没有,则跳转到站点sso进行验证。

- 阅读剩余部分 -