分类 ThinkPHP 下的文章

一、升级前准备

以下是tp6.1.x升级到tp8.0.x的步骤,如果你目前版本是tp6.0.x的,请先将期升级到tp6.1.x切记!!

6.0升级到6.1版本
由于安全性原因,6.1版本移除核心对think-filesystem库的依赖,因此6.0版本升级至6.1版本后,需要单独安装`topthink/think-filesystem`库。

二、查看PHP的版本,tp8要求php >= 8.0

1、查看php版本:

liuhongdi@lhdpc:~$ /usr/local/soft/php8/bin/php --version
PHP 8.1.1 (cli) (built: Dec 20 2021 16:12:16) (NTS)
Copyright (c) The PHP Group
Zend Engine v4.1.1, Copyright (c) Zend Technologies
    with Zend OPcache v8.1.1, Copyright (c), by Zend Technologies

当前版本是 8.1.1 ,显然符合条件

2、查看当前项止的thinkphp版本:

liuhongdi@lhdpc:/data/php/tpapibase$ php think version
v6.1.0

三、升级ThinkPHP开始

1、升级原项目到可用的最新版本:

liuhongdi@lhdpc:/data/php/tpapibase$ composer update topthink/framework
Loading composer repositories with package information
Updating dependencies
Lock file operations: 0 installs, 1 update, 0 removals
  - Upgrading topthink/framework (v6.1.1 => v6.1.4)
Writing lock file
Installing dependencies from lock file (including require-dev)
Package operations: 0 installs, 1 update, 0 removals
  - Downloading topthink/framework (v6.1.4)
  - Upgrading topthink/framework (v6.1.1 => v6.1.4): Extracting archive
Generating autoload files
> @php think service:discover
Succeed!
> @php think vendor:publish
File /data/php/tpapibase/config/trace.php exist!
Succeed!
4 packages you are using are looking for funding.
Use the `composer fund` command to find out more!
No security vulnerability advisories found
liuhongdi@lhdpc:/data/php/tpapibase$ php think version
v6.1.4

可以看到升级完成后版本是v6.1.4

2、修改composer.json

"require": {
        "php": ">=8.0.0",
        "topthink/framework": "^8.0",
        "topthink/think-orm": "^3.0",
        "topthink/think-filesystem": "^2.0"
    },
    "require-dev": {
        "symfony/var-dumper": ">=4.2",
        "topthink/think-trace":"^1.0"
    },

对require需要用到的库的版本调整,我的配置版本号如上,

“topthink/think-filesystem”: “^2.0”, 这一行是我手动添加上的,

说明:这些版本号是从哪里来的?

用下面的命令新创建一个thinkphp8项目,从composer.json中就看到了

liuhongdi@lhdpc:/data/php$ composer create-project topthink/think tp8

3、删除composer.lock

liuhongdi@lhdpc:/data/php/tpapibase$ rm composer.lock

4、升级前查看当前各库的版本:

liuhongdi@lhdpc:/data/php/tpapibase$ composer show
firebase/php-jwt          v6.3.1  A simple library to encode and decode JSON Web Tokens (JWT) in PHP. Should conform to the current spec.
psr/container             1.1.2   Common Container Interface (PHP FIG PSR-11)
psr/http-message          1.0.1   Common interface for HTTP messages
psr/log                   1.1.4   Common interface for logging libraries
psr/simple-cache          1.0.1   Common interfaces for simple caching
symfony/polyfill-mbstring v1.27.0 Symfony polyfill for the Mbstring extension
symfony/polyfill-php72    v1.27.0 Symfony polyfill backporting some PHP 7.2+ features to lower PHP versions
symfony/polyfill-php80    v1.27.0 Symfony polyfill backporting some PHP 8.0+ features to lower PHP versions
symfony/var-dumper        v4.4.47 Provides mechanisms for walking through any arbitrary PHP variable
topthink/framework        v6.1.4  The ThinkPHP Framework.
topthink/think-helper     v3.1.6  The ThinkPHP6 Helper Package
topthink/think-orm        v2.0.56 think orm
topthink/think-trace      v1.5    thinkphp debug trace

5、升级:

liuhongdi@lhdpc:/data/php/tpapibase$ composer install
No composer.lock file present. Updating dependencies to latest instead of installing from lock file. See https://getcomposer.org/install for more information.
Loading composer repositories with package information
Updating dependencies
Lock file operations: 14 installs, 0 updates, 0 removals
  - Locking firebase/php-jwt (v6.8.0)
  - Locking league/flysystem (2.5.0)
  - Locking league/mime-type-detection (1.11.0)
  - Locking psr/container (2.0.2)
  - Locking psr/http-message (1.1)
  - Locking psr/log (3.0.0)
  - Locking psr/simple-cache (3.0.0)
  - Locking symfony/polyfill-mbstring (v1.27.0)
  - Locking symfony/var-dumper (v6.3.0)
  - Locking topthink/framework (v8.0.1)
  - Locking topthink/think-filesystem (v2.0.2)
  - Locking topthink/think-helper (v3.1.6)
  - Locking topthink/think-orm (v3.0.11)
  - Locking topthink/think-trace (v1.6)
Writing lock file
Installing dependencies from lock file (including require-dev)
Package operations: 3 installs, 6 updates, 2 removals
  - Downloading league/mime-type-detection (1.11.0)
  - Downloading psr/container (2.0.2)
  - Downloading symfony/var-dumper (v6.3.0)
  - Downloading psr/simple-cache (3.0.0)
  - Downloading psr/log (3.0.0)
  - Downloading topthink/think-orm (v3.0.11)
  - Downloading topthink/framework (v8.0.1)
  - Downloading league/flysystem (2.5.0)
  - Downloading topthink/think-filesystem (v2.0.2)
  - Removing symfony/polyfill-php80 (v1.27.0)
  - Removing symfony/polyfill-php72 (v1.27.0)
  - Installing league/mime-type-detection (1.11.0): Extracting archive
  - Upgrading psr/container (1.1.2 => 2.0.2): Extracting archive
  - Upgrading symfony/var-dumper (v4.4.47 => v6.3.0): Extracting archive
  - Upgrading psr/simple-cache (1.0.1 => 3.0.0): Extracting archive
  - Upgrading psr/log (1.1.4 => 3.0.0): Extracting archive
  - Upgrading topthink/think-orm (v2.0.61 => v3.0.11): Extracting archive
  - Upgrading topthink/framework (v6.1.4 => v8.0.1): Extracting archive
  - Installing league/flysystem (2.5.0): Extracting archive
  - Installing topthink/think-filesystem (v2.0.2): Extracting archive
2 package suggestions were added by new dependencies, use `composer suggest` to see details.
Generating autoload files
> @php think service:discover
Succeed!
> @php think vendor:publish
File /data/php/tpapibase/config/trace.php exist!
Succeed!
4 packages you are using are looking for funding.
Use the `composer fund` command to find out more!

6、查看升级后的版本:

liuhongdi@lhdpc:/data/php/tpapibase$ composer show
firebase/php-jwt           v6.8.0  A simple library to encode and decode JSON Web Tokens (JWT) in PHP. Should conform to the current spec.
league/flysystem           2.5.0   File storage abstraction for PHP
league/mime-type-detection 1.11.0  Mime-type detection for Flysystem
psr/container              2.0.2   Common Container Interface (PHP FIG PSR-11)
psr/http-message           1.1     Common interface for HTTP messages
psr/log                    3.0.0   Common interface for logging libraries
psr/simple-cache           3.0.0   Common interfaces for simple caching
symfony/polyfill-mbstring  v1.27.0 Symfony polyfill for the Mbstring extension
symfony/var-dumper         v6.3.0  Provides mechanisms for walking through any arbitrary PHP variable
topthink/framework         v8.0.1  The ThinkPHP Framework.
topthink/think-filesystem  v2.0.2  The ThinkPHP6.1 Filesystem Package
topthink/think-helper      v3.1.6  The ThinkPHP6 Helper Package
topthink/think-orm         v3.0.11 the PHP Database&ORM Framework
topthink/think-trace       v1.6    thinkphp debug trace

7、用php命令查看版本:

liuhongdi@lhdpc:/data/php/tpapibase$ php think version
v8.0.0


最后:

需要注意的是,与之相关的扩展也需要一同更新,比如:composer require topthink/think-view否则会出现报错,如:Call to undefined method....

转自:https://www.cnblogs.com/architectforest/p/17584818.html

找到文件 vendor/topthink/think-cache/src/cache/Driver.php文件,如下方法,先将:

//判断$data是否为序列化字符串,如果不是直接返回不需要反序列化
if (!preg_match( '/^[asO]:[0-9]+:/s', $data)) {
    return $data;
}

添加,如下。然后正常的方问网站如登陆后台等操作,待操作完成以后,即完成了字符序列化入数据库,然后会出现\u5148\u950b\u7f51\u7edcUnicode代码,将其修改为正常的中文以后,再将下面新增的代码删除即可。
原因就是升级前的序列化入库与升级的序列化不同了。

/**
 * 反序列化数据
 * @access protected
 * @param  string $data 缓存数据
 * @return mixed
 */
protected function unserialize(string $data)
{
    //判断$data是否为序列化字符串,如果不是直接返回不需要反序列化
    if (!preg_match( '/^[asO]:[0-9]+:/s', $data)) {
        return $data;
    }
    
    $unserialize = $this->options['serialize'][1] ?? function ($data) {
        SerializableClosure::enterContext();
        $data = \unserialize($data);
        SerializableClosure::unwrapClosures($data);
        SerializableClosure::exitContext();
        return $data;
    };

    return $unserialize($data);
}

与G银行对接时用到的

<?php
/**
 * Describe:
 * Author: liziyu
 * Date: 2022/10/31 11:10 AM
 */

namespace App\encrypt;

class MD5WithRSA
{
    /**
     * 利用约定数据和私钥生成数字签名
     * @param $data 待签数据
     * @return String 返回签名
     */
    public function sign($data='')
    {
        if (empty($data))
        {
            return false;
        }
        $private_key="MIICdgIBADANBgkqhkiG9w0BAQEFAASCAmAwggJcAgE==";
        $private_key = chunk_split($private_key, 64, "\n");
        $private_key = "-----BEGIN PRIVATE KEY-----\n$private_key-----END PRIVATE KEY-----";

        if (empty($private_key))
        {
            echo "私钥为空";
            return false;
        }
        // 生成密钥资源id
        $private_key_resource_id = openssl_get_privatekey($private_key);
        if (empty($private_key_resource_id))
        {
            echo "私钥资源id为空";
            return false;
        }

        $verify = openssl_sign($data, $signature, $private_key_resource_id, OPENSSL_ALGO_MD5);
        openssl_free_key($private_key_resource_id);
        // 二次Base64编码
        return base64_encode(base64_encode($signature));
    }

    /**
     * 利用公钥和数字签名以及约定数据验证合法性
     * @param string $data 待验证数据
     * @param string $signature 数字签名
     * @return  -1 验证错误;0 验证失败;1 验证成功
     */
    public function isValid($data='', $signature='')
    {
        if (empty($data) || empty($signature))
        {
            return false;
        }

        $public_key ="MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCB";
        $public_key = chunk_split($public_key, 64, "\n");
        $public_key = "-----BEGIN PUBLIC KEY-----\n$public_key-----END PUBLIC KEY-----";

        if (empty($public_key))
        {
            echo "公钥为空";
            return false;
        }
        // 生成密钥资源id
        $public_key_resource_id = openssl_get_publickey($public_key);
        if (empty($public_key_resource_id))
        {
            echo "公钥资源id为空";
            return false;
        }

        // 对签名进行二次Base64解码
        $signature=base64_decode(base64_decode($signature));
        $ret = openssl_verify($data, $signature, $public_key_resource_id, OPENSSL_ALGO_MD5);
        openssl_pkey_free($public_key_resource_id);
        return $ret;
    }
}

微信小程序获取客户端手机号码,踩的坑。如下提示:

{"errcode":47001,"errmsg":"data format error hint: [6kMDxSDNRa-hAwqia] rid: 6308d1b5-69935bc9-1d99d19f"}

protected function getPhoneNo($code): string
    {
        try {
            $accessToken = $this->getAccessToken();
            if($accessToken) {
                //POST https://api.weixin.qq.com/wxa/business/getuserphonenumber?access_token=ACCESS_TOKEN
                $client = new Client();
                $url = config('mini.get_phone_number');
                $req = $client->post("$url?access_token={$accessToken}", [
                    'json' => [
                        'code' => $code
                    ]
                ]);
                var_export($req->getBody()->getContents());
            }
        } catch (\Throwable | \Exception $e) {
            return $e->getMessage();
        }
    }

这里需要注意的是,post请求时,格式需要用json格式,不能用body格式,即:

正确:

'json' => [
    'code' => $code
]

错误:

'form_params' => [
    'code' => $code
]


/**
 * 下划线转驼峰
 * @param $str
 * @return null|string|string[]
 */
public static function lineToHump($str)
{
    $str = preg_replace_callback('/([-_]+([a-z]{1}))/i', function ($matches) {
        return strtoupper($matches[2]);
    }, $str);
    return $str;
}

/**
 * 驼峰转下划线
 * @param $str
 * @return null|string|string[]
 */
public static function humpToLine($str)
{
    $str = preg_replace_callback('/([A-Z]{1})/', function ($matches) {
        return '_' . strtolower($matches[0]);
    }, $str);
    return $str;
}

方案一

Casbin的核心-表.png

Casbin的核心.png

方案二

111.JPG
原理

222.JPG
规则

333.JPG
数据ER

444.PNG
管理UI

555.JPG
数据表实例

特别声明:其中方案二为某大佬线上生产环境系统设计,如果侵犯到此权限请通知我删除,同时采纳者一同承担相应责任。

评论表

idarticle_idparent_id(string)
130
231
331_2
432
531_2_3

模型操作

删除 id = 1 的1 级文章及下级所有文章
Article::where('id', 1)->delete();
Article::where('parent_id', 'like', '1%')->delete();
这样和 id = 1 的所有相关文章就删除了
删除这些文章下的评论就用观察者就行了



第一步:

习惯将CDN文件下载到本地,保存至静态目录中,注意保留版本号。

<!-- 引入 css -->
<link href="https://cdn.jsdelivr.net/npm/@wangeditor/editor@latest/dist/css/style.css" rel="stylesheet">
<!-- 引入 js -->
<script src="https://cdn.jsdelivr.net/npm/@wangeditor/editor@latest/dist/index.min.js"></script>

第二步:

直接上 HTML代码吧:

<div class="layui-row">
            <div class="layui-col-md12">
                <div class="layui-form-item">
                    <label class="layui-form-label">正文:</label>
                    <div class="layui-input-block">
                        <textarea name="content" id="content" style="display: none"></textarea>
                        <div id="toolbar-container"></div>
                        <div id="editor-container" style="height: 300px;border:1px solid #dddddd"></div>
                    </div>
                </div>
            </div>
        </div>


第三步:

注意从官方拷贝js代码时,要注意javascript与typescript的修改。
直接上 JS代码。

// 渲染富文本编辑器
const { createEditor, createToolbar } = window.wangEditor;
// 编辑器配置
const editorConfig = {MENU_CONF: {}};
// 图片上传
editorConfig.MENU_CONF['uploadImage'] = {
    // 表单字段名称
    fieldName: 'file',
    // 单个文件的最大体积限制,默认为 2M
    maxFileSize: 5 * 1024 * 1024, // 5M
    // 最多可上传几个文件,默认为 100
    maxNumberOfFiles: 5,
    // 选择文件时的类型限制,默认为 ['image/*'] 。如不想限制,则设置为 []
    allowedFileTypes: ['image/*'],
    // 小于该值就插入 base64 格式(而不上传),默认为 0
    base64LimitSize: 5 * 1024, // 5kb
    // 自定义参数
    meta: {
        from: 'editor', //标志是从编辑器上传
    },
    // 上传图片的配置
    server: '<?=route("upload.image")?>',
};
// 默认提示文字
editorConfig.placeholder = '请输入内容'
editorConfig.onChange = (editor) => {
    // 当编辑器选区、内容变化时,即触发
    //console.log('content', editor.children)
    //console.log('html', editor.getHtml())
    document.getElementById('content').value = editor.getHtml();
}


// 工具栏配置
const toolbarConfig = {}

// 创建编辑器
const editor = createEditor({
    html: document.getElementById('content').value,
    selector: '#editor-container',
    config: editorConfig,
    mode: 'simple' // 或 'simple' 参考下文
})
// 创建工具栏
const toolbar = createToolbar({
    editor,
    selector: '#toolbar-container',
    config: toolbarConfig,
    mode: 'simple' // 或 'simple' 参考下文
})

最后:

截图如下。

333333.png

1.composer安装阿里云OSS SDK

composer require aliyuncs/oss-sdk-php

2.控制器里面引用

use OSS\Core\OssException;

use OSS\OssClient;

use OSS\Core\OssUtil; 

2.上传代码逻辑

//        接收文件数据
    $file = request()->file('img');

// 取出文件名截取后缀

    $name = $file->getOriginalName();
    $suffix = strchr($name,'.');

// 阿里云配置

    $accessKeyId = "LTAI5t88SfZ5yhH4Sgu1u3gt";
    $accessKeySecret = "vbLBZWvzazGZvJpPap20ZyKDoBbdq2";
    // Endpoint以杭州为例,其它Region请按实际情况填写。
    $endpoint = "oss-cn-shanghai.aliyuncs.com";
    // 设置存储空间名称。
    $bucket= "*";
    // 设置文件名称。
    //这里是由sha1加密生成文件名 之后连接上文件后缀
    $object = sha1(date('YmdHis', time()) . uniqid()) . $suffix;
    $url = 'http://test.caotengfei.xyz/'.$object;
    // <yourLocalFile>由本地文件路径加文件名包括后缀组成,例如/users/local/myfile.txt。
    $filePath = $file->getPathname();
    $options = array(
        OssClient::OSS_CHECK_MD5 => true,
        OssClient::OSS_PART_SIZE => 1,
    );

    try{
        $ossClient = new OssClient($accessKeyId, $accessKeySecret, $endpoint);
        //返回uploadId。uploadId是分片上传事件的唯一标识,您可以根据uploadId发起相关的操作,如取消分片上传、查询分片上传等。
        $uploadId = $ossClient->initiateMultipartUpload($bucket, $object);
    } catch(OssException $e) {
        printf(__FUNCTION__ . ": initiateMultipartUpload FAILED\n");
        printf($e->getMessage() . "\n");
        return ;
    }
    print(__FUNCTION__ . ": initiateMultipartUpload OK" . "\n");

    $partSize = 10 * 1024 * 1024;
    $uploadFileSize = filesize($filePath);
    $pieces = $ossClient->generateMultiuploadParts($uploadFileSize, $partSize);
    $responseUploadPart = array();
    $uploadPosition = 0;
    $isCheckMd5 = true;
    foreach ($pieces as $i => $piece) {
        $fromPos = $uploadPosition + (integer)$piece[$ossClient::OSS_SEEK_TO];
        $toPos = (integer)$piece[$ossClient::OSS_LENGTH] + $fromPos - 1;
        $upOptions = array(
            // 上传文件。
            $ossClient::OSS_FILE_UPLOAD => $filePath,
            // 设置分片号。
            $ossClient::OSS_PART_NUM => ($i + 1),
            // 指定分片上传起始位置。
            $ossClient::OSS_SEEK_TO => $fromPos,
            // 指定文件长度。
            $ossClient::OSS_LENGTH => $toPos - $fromPos + 1,
            // 是否开启MD5校验,true为开启。
            $ossClient::OSS_CHECK_MD5 => $isCheckMd5,
        );
        // 开启MD5校验。
        if ($isCheckMd5) {
            $contentMd5 = OssUtil::getMd5SumForFile($filePath, $fromPos, $toPos);
            $upOptions[$ossClient::OSS_CONTENT_MD5] = $contentMd5;
        }
        try {
            // 上传分片。
            $responseUploadPart[] = $ossClient->uploadPart($bucket, $object, $uploadId, $upOptions);
        } catch(OssException $e) {
            printf(__FUNCTION__ . ": initiateMultipartUpload, uploadPart - part#{$i} FAILED\n");
            printf($e->getMessage() . "\n");
            return;
        }
        printf(__FUNCTION__ . ": initiateMultipartUpload, uploadPart - part#{$i} OK\n");
    }
// $uploadParts是由每个分片的ETag和分片号(PartNumber)组成的数组。
        $uploadParts = array();
        foreach ($responseUploadPart as $i => $eTag) {
            $uploadParts[] = array(
                'PartNumber' => ($i + 1),
                'ETag' => $eTag,
            );
        }
    try {
        // 执行completeMultipartUpload操作时,需要提供所有有效的$uploadParts。OSS收到提交的$uploadParts后,会逐一验证每个分片的有效性。当所有的数据分片验证通过后,OSS将把这些分片组合成一个完整的文件。
        $ossClient->completeMultipartUpload($bucket, $object, $uploadId, $uploadParts);
    }  catch(OssException $e) {
        printf(__FUNCTION__ . ": completeMultipartUpload FAILED\n");
        printf($e->getMessage() . "\n");
        return;
    }
        return json(['code'=>200,'msg'=>'成功','url'=>$url]);