MiniFramework 2.10 已经发布,超轻量级的国产 PHP 框架

MiniFramework 2.10 已经发布,超轻量级的国产 PHP 框架

此版本更新内容包括:

版本变化

  • 新增常量 ERROR_PAGE,默认值为空,用于声明自定义错误页面。
  • 新增支持输出自定义错误页的特性。
  • 新增自定义错误页的示例代码。
  • 新增 Mini\Base\Response 类的 charset() 方法,用于在响应头中自定义字符编码。
  • 新增 Mini\Base\Rest 类的 response() 和 type() 方法,对输出进行统一封装。
  • 调整错误信息输出方式,当启用 REST 模式对 API 接口请求遇到异常时,将以 JSON 格式输出错误信息。
  • 改进 Mini\Base\App 类的 dispatch() 方法,支持传入参数带入 Action 中。
  • 改进 Mini\Base\App 类,增加名为 isApi 属性,用于判断当前请求是否为 REST 接口。
  • 改进 Mini\Base\Action 类的 forward() 方法,支持跳转时传递参数。
  • 改进 Mini\Base\Rest 类,在构造阶段即将默认的 json 方式传递给 Response 对象。
  • 改进 Mini\Base\Exception 类,在 CLI 模式下运行时默认输出错误信息。
  • 改进 Mini\Base\Loader 类,在自动加载过程遇到文件不存在时不主动抛出错误。
  • 改进 Mini\Base\Layout 类的 setLayout() 方法,参数允许留空或传入 null 以清除历史布局设置。
  • 调整 Mini\Base\Layout 类,取消单例模式,改为常规的实例化对象方式。
  • 改进 Mini\Base\Action 类的 forward() 方法,跳转前默认清除历史的布局设置。
  • 改进 Mini\Base\View 类的属性声明方式,以兼容 PHP 7.2 和 7.3 版本。
  • 改进框架默认的报错输出格式,优化阅读体验。
  • 修复 Mini\Cache\File 类的 set() 和 del() 两个方法中写入和删除文件的Bug。
  • 修复配置自定义路由与 CLI 模式运行时出现的路由冲突问题。

升级说明

  • 兼容 PHP 最低版本为 7.2.0,PHP 8.3 已测试可正常运行。
  • 当前版本向前兼容至 2.4.0 版本,使用 2.4.0 及后续版本的开发者可直接升级至 2.10.0 版本。
  • 文档已同步更新,地址:http://www.miniframework.com/docv2/guide/

详情查看:https://gitee.com/jasonwei/miniframework/releases/2.10.0

使用 ArkUI 开发鸿蒙 HarmonyOS 原生应用界面交互 实现 Stepper 组件内部滚动浏览内容

在基于华为鸿蒙 HarmonyOS 的 ArkUI 搭建界面交互时,使用 Stepper 组件时,让其内部的内容在超出容器可视范围时,能够正常进行滚动浏览,可以使用 Scroll 可滚动的容器组件。

由于 Stepper 组件内部只允许嵌入 StepperItem 组件,所以我们要把 Scroll 放入 StepperItem 内部,下面给出代码示例:

阅读更多

解决使用 aws-sdk-php 向天翼云对象存储请求 STS 临时凭证报错的问题

本人近期在使用天翼云部署一个 PHP 开发的系统时,在使用 aws-sdk-php 向天翼云对象存储发起STS临时凭证请求时,遇到了如下报错:

Fatal error: Uncaught Aws\Api\Parser\Exception\ParserException: Invalid timestamp value passed to DateTimeResult::fromTimestamp in /data/htdocs/myapp/vendor/aws/aws-sdk-php/src/Api/DateTimeResult.php:100

经过对 aws-sdk-php 源代码进行分析后,决定自己动手进行一些改造,让 aws-sdk-php 兼容天翼云,具体方法如下:

阅读更多

详解用 MiniFramework 框架实现对 GET 或 POST 请求参数进行签名校验的方法

在一些特殊场景下,我们可能希望对于 GET 或 POST 进入到接口的数据进行签名和有效期的校验,例如 APP 请求后端接口的场景,我们通常需要考虑两个问题:

问题1:如何避免攻击者在捕获到接口请求后,自行构造请求参数,向接口发送请求,而不通过 APP 的正常界面进行操作。

问题2:在接口请求不可避免能被捕获的情况下,如何确保每一次请求能够过期,不被反复的利用,例如投票刷票的问题。

基于上面两个问题,我们在设计接口时,就需要通过给请求参数进行签名的方式来对数据来源和有效期进行校验。下面将以 MiniFramework 框架为例,演示如何通过 MiniFramework 框架来实现对请求参数进行签名和签名校验的方法。

阅读更多

MiniFramework 2.9.0 已经发布,超轻量级的 PHP 框架

MiniFramework 2.9.0 已经发布,超轻量级的 PHP 框架

此版本更新内容包括:

版本变化

  • 新增 Mini\Base\Header 类,用于处理 Request 和 Response 的 Header 信息。
  • 新增 Mini\Base\Response 类,用于响应客户端,控制请求结果的输出。
  • 新增 Mini\Base\App::setAction () 方法,用于设置动作。
  • 新增 Mini\Base\App::setController () 方法,用于设置控制器。
  • 新增 Mini\Base\Action::forward () 替代原 _forward () 方法,旧方法暂时保留,新旧两个方法功能完全一致。
  • 新增 Mini\Security\Sign 类的 setEncryptType () 方法,用于指定加密方式。
  • 改进 Controller 和 Action 的设置由 Mini\Base\App 类负责处理。
  • 改进在部分核心类库中用 Mini\Base\Response 替代 Mini\Base\Http 以规范响应输出。
  • 改进并优化框架异常报错的特性。
  • 修复 Action 中使用 $this->_forward () 跳转相同的 Action 时出现死循环的 Bug。
  • 修复 Mini\Base\Http 在被继承的场景中可能出现的实例获取 Bug。
  • 修复全局函数 isTimestamp () 校验时间戳的 Bug。

升级说明

  • 兼容 PHP 最低版本为 7.2.0,PHP 8.0.0 已测试可正常运行。
  • 当前版本向前兼容至 2.4.0 版本,使用 2.4.0 及后续版本的开发者可直接升级至 2.9.0 版本。
  • 文档已同步更新,地址:http://www.miniframework.com/docv2/guide/

详情查看:https://gitee.com/jasonwei/miniframework/releases/2.9.0

详解用 MiniFramework 计算程序运行时间的方法

我们在项目调优过程中,通常会对代码的运行时间进行统计,以便了解程序运行的性能和效率,这些统计结果将作为代码优化时的重要指标,帮助开发者有针对性的进行调优工作。

MiniFramework 在 1.3.0 版本中,新增了 Debug 类,其中包含有时间统计功能的若干方法,可以非常便捷地帮助开发者实现上述统计需求,下面我们来通过示例代码介绍具体实现方法。

首先,假设我们有一个名为 Index 的 Controller,并且其中包含有一个名为 index 的 Action(MiniFramework下载包中已经包含),我们将代码写在这个 Action 中,如下:

阅读更多

Golang 开发 Socket 通信时常用的 TCP 封包和解包协议

在开发 Socket 通信时,由于 TCP 协议的特性,在网络状况不佳的情况下,数据传输过程中经常会出现半包或粘包。为解决这一问题,通常我们需要自定义一个通信协议,增加一个 HEADER 部分,并在其中对数据包的长度进行声明,下面分享一段封包和解包的示例代码,可用于 Golang 开发 Socket 时处理数据传输,具体代码如下:

package protocol
 
import (
    "bytes"
    "encoding/binary"
)
 
const (
    TCP_HEADER     = "TCPHEADER"
    TCP_HEADER_LEN = 9
    TCP_DATA_LEN   = 4
)
 
// 封包
func Enpack(msg []byte) []byte {
    return append(append([]byte(TCP_HEADER), IntToBytes(len(msg))...), msg...)
}
 
// 解包
func Depack(buffer []byte, readerChannel chan []byte) []byte {
    length := len(buffer)
 
    var i int
    for i = 0; i < length; i++ {
        if length < i + TCP_HEADER_LEN + TCP_DATA_LEN {
            break
        }
        if string(buffer[i:i + TCP_HEADER_LEN]) == TCP_HEADER {
            msgLen := BytesToInt(buffer[i + TCP_HEADER_LEN : i + TCP_HEADER_LEN + TCP_DATA_LEN])
            if length < i + TCP_HEADER_LEN + TCP_DATA_LEN + msgLen {
                break
            }
            data := buffer[i + TCP_HEADER_LEN + TCP_DATA_LEN : i + TCP_HEADER_LEN + TCP_DATA_LEN + msgLen]
            readerChannel <- data
 
            i += TCP_HEADER_LEN + TCP_DATA_LEN + msgLen - 1
        }
    }
 
    if i == length {
        return make([]byte, 0)
    }
    
    return buffer[i:]
}
 
// 整形转换成字节
func IntToBytes(n int) []byte {
	x := int32(n)
    bytesBuffer := bytes.NewBuffer([]byte{})
    binary.Write(bytesBuffer, binary.BigEndian, x)
    
    return bytesBuffer.Bytes()
}
 
// 字节转换成整形
func BytesToInt(b []byte) int {
    bytesBuffer := bytes.NewBuffer(b)
    var x int32
    binary.Read(bytesBuffer, binary.BigEndian, &x)
    
    return int(x)
}