Joyber 发布的文章

一、PHP SG11 是什么?

SG11 是一款 PHP 代码加密/混淆工具(全称:SourceGuardian 11),核心作用是对 PHP 源代码进行加密、混淆和授权保护,防止代码被篡改、盗用或逆向破解。

它的本质是:将人类可读的 PHP 源码(明文)转换为机器可执行但人类难以理解的加密格式,同时提供运行时解密机制(需配合 SG11 扩展),确保加密后的代码能在服务器正常运行,但无法被轻易还原为原始源码。

二、核心功能(为什么开源项目会用它)

开源项目使用 SG11,核心诉求是 “开源但不完全开放核心”“保护商业权益”,具体场景如下:

1. 保护核心逻辑/商业机密(最核心用途)

很多“开源项目”并非 100% 开源:

  • 项目主体功能开源(吸引用户、共建生态),但 核心算法、付费模块、关键业务逻辑 是团队的核心资产(比如 SaaS 对接逻辑、付费插件的核心功能)。
  • 若这些核心代码明文开源,可能被竞争对手抄袭、恶意篡改,或被用户绕过付费机制(比如破解授权)。
  • SG11 加密后,代码无法被直接阅读和修改,能有效阻挡大部分非专业破解,保护商业利益。

2. 防止代码篡改与恶意使用

开源项目的明文代码可被任意修改:

  • 恶意用户可能篡改代码植入后门、挖矿脚本,或修改版权信息后二次分发(冒充原创)。
  • 加密后的代码无法直接修改,即使强行修改也会导致运行报错,确保项目在用户环境中运行的是“官方纯净版”,保障项目声誉和用户安全

3. 实现授权控制(付费开源项目常用)

很多开源项目采用“开源免费+付费增值”模式:

  • SG11 支持结合授权机制(比如绑定服务器 IP、域名、有效期),加密后的代码需验证授权密钥才能运行。
  • 例如:开源项目的基础版免费(明文),高级功能模块(加密)需付费购买授权码才能启用,避免用户“白嫖”付费功能。

4. 轻量化保护,不影响运行效率

SG11 属于 “运行时解密”,加密后的代码在执行时由 SG11 扩展实时解密(解密过程在内存中完成,不落地明文),相比其他加密工具

  • 性能损耗极低(几乎不影响项目运行速度);
  • 兼容性强(支持 PHP 5.2+ 到 PHP 8.2+ 全版本,支持 Windows/Linux 等主流系统);
  • 部署简单(仅需在服务器安装 SG11 扩展,无需修改项目架构)。

三、开源项目使用 SG11 的争议与注意事项

虽然 SG11 能保护核心利益,但也存在一些争议,需理性看待:

  1. “开源精神”的冲突:部分开源社区认为“加密代码违背开源的开放透明原则”,因此纯公益开源项目(无商业诉求)很少使用;但“商业开源项目”(如 Laravel 生态的部分付费扩展、企业级开源软件)使用较为普遍,属于“开源商业模式的折中方案”。
  2. 依赖扩展风险:加密后的代码必须在安装了 SG11 扩展的服务器上才能运行,增加了用户的部署成本(需手动安装扩展),若扩展版本不兼容可能导致代码无法运行。
  3. 无法完全防破解:SG11 能阻挡普通用户和初级破解者,但专业破解者可通过内存dump、逆向扩展等方式还原代码(只是门槛极高,多数场景下足够安全)。

总结

SG11 是 PHP 项目的 “代码保镖”,核心价值是“加密保护+授权控制”。开源项目使用它,本质是在“开源生态”和“商业利益”之间找平衡——既通过开源吸引用户、共建社区,又通过加密保护核心资产,避免被抄袭或恶意使用,尤其适合“商业开源”(开源免费+付费增值)模式。

在 Git 中,CRLF(Carriage Return + Line Feed) 是 Windows 系统的换行符,而 Linux/macOS 用 LF(Line Feed)。Git 默认会自动转换换行符(Windows 下拉取时 LF→CRLF,提交时 CRLF→LF),若想禁用这种自动转换(即 “不设置 CRLF”),核心是通过 Git 配置关闭换行符自动处理,具体操作如下:
一、核心配置:禁用 CRLF 自动转换
通过 core.autocrlf 配置控制换行符转换,禁用需设置为 false,支持全局配置(所有仓库)或局部配置(当前仓库)。

  1. 全局配置(推荐,所有 Git 仓库生效)
    打开终端 / 命令行,执行:

    git config --global core.autocrlf false
  2. 局部配置(仅当前仓库生效)
    进入项目的 Git 仓库根目录,执行:

    git config core.autocrlf false

    配置说明:
    core.autocrlf false:Git 不做任何换行符转换,工作区文件的换行符完全由你本地编辑器 / 系统决定(Windows 保留 CRLF,Linux/macOS 保留 LF);
    对比默认值 true(Windows 下自动转换)和 input(仅提交时 CRLF→LF,拉取不转换),false 是彻底禁用转换。
    二、补充配置:避免 Git 标记文件为 “已修改”(可选)
    若禁用转换后,Git 仍误判文件因换行符变化为 “已修改”,需配置 core.safecrlf 关闭换行符检查:

    # 全局禁用换行符检查(推荐)
    git config --global core.safecrlf false
    core.safecrlf

    说明:
    true(默认):提交时若存在混合换行符,Git 会报错阻止提交;
    false:关闭检查,允许混合换行符提交

检查并会阻止提交

git config --global core.autocrlf true
git config --global --unset core.safecrlf

仅恢复 core.autocrlf 默认值

Windows 系统中 Git 默认core.autocrlf为true,若之前设为false,执行以下命令单独恢复该配置:

git config --global core.autocrlf true

1. 克隆主仓库时直接拉取子模块(首次拉取代码时,默认会拉取子模块,推荐)

# --recursive 递归拉取所有子模块
git clone --recursive git@gitcode.com:xxx/supo-admin.git

2. 已克隆主仓库,后续同步子模块

# 初始化子模块(若未初始化)
git submodule init

# 拉取子模块代码并更新到最新版本
git submodule update --remote

3. 常用子模块维护命令

# 3-1. 更新子模块到远程最新版本
# 只更新 admin-web 子模块
git submodule update --remote admin-web

# 或更新所有子模块
git submodule update --remote

# 3-2. 进入子模块操作(如提交子模块代码)
# 进入子模块目录
cd admin-web
# 拉取子模块的远程更新
git pull origin 子模块分支名

git add .
git commit -m "fix: 子模块修复bug"

# 推送子模块的代码到远程
git push origin master

4. 移除子模块(如需删除)

# 4-1. 解除主仓库对子模块的跟踪
git submodule deinit -f admin-web

# 4-2. 删除子模块的本地目录
rm -rf admin-web

# 4-3. 删除主仓库中 .git 目录下的子模块配置
rm -rf .git/modules/admin-web

# 4-4. 从 .gitmodules 中删除该子模块的配置(或手动编辑 .gitmodules 删除对应段落)
git rm --cached admin-web

# 4-5. 提交删除操作
git commit -m "feat: 移除 admin-web 子模块"
git push

5. 添加子模块

git submodule https://gitcode.com/xxx/merchant-web.git merchant-web

恢复到项目 未执行 git submodule init 的状态,后续可再次拉子模块代码

要让 Git 子模块目录恢复到“未初始化/未拉取代码”的状态(和执行 git submodule init 前一致,仅保留子模块配置,删除本地代码),核心是 保留子模块的 Git 配置(.gitmodules.git/config 中的记录),但删除子模块的本地代码目录和 Git 跟踪文件。以下是具体步骤:

核心逻辑

目标状态:

  • 保留 .gitmodules 文件(子模块配置记录);
  • 保留 .git/config 中可能存在的子模块配置(可选,若之前执行过 init);
  • 删除子模块的本地代码目录(如 submodule-dir/);
  • 删除 Git 对其子模块的跟踪文件(.git/modules/[子模块名])。

具体操作步骤

假设你的子模块目录名为 submodule-dir(替换为实际子模块目录名):

1. 先确保子模块目录无未提交的修改(可选,避免数据丢失)

如果子模块目录中有自己的修改,先备份或提交(否则删除后会丢失):

# 进入子模块目录查看状态
cd submodule-dir
git status
# 若有未提交文件,可备份或提交(根据需求选择)

2. 删除子模块的本地代码目录

直接删除子模块的物理目录(这是“看起来没拉取代码”的核心):

# 回到项目根目录
cd ..
# 删除子模块目录(本地代码全部删除)
rm -rf submodule-dir/

3. 删除 Git 对其子模块的跟踪文件

Git 会将子模块的版本信息、配置等存储在 .git/modules/[子模块名] 目录中,必须删除才能彻底恢复到“未初始化”状态:

# 删除 Git 跟踪的子模块元数据(替换为实际子模块名)
rm -rf .git/modules/submodule-dir/

4. (可选)保留子模块配置(关键!和 git submodule init 前一致)

如果想保留 .gitmodules 中的配置(后续可重新执行 git submodule init && git submodule update 拉取代码),无需删除 .gitmodules 文件

若之前执行过 git submodule init.git/config 中会有子模块的配置记录,若想完全恢复到“从未 init”的状态,可删除该记录:

# 取消 .git/config 中对子模块的配置(可选,不删也不影响“无代码”状态)
git config --unset-all submodule.submodule-dir

最终效果验证

操作完成后,项目状态如下:

  • 子模块目录 submodule-dir/ 不存在(或为空);
  • .gitmodules 文件保留(子模块配置还在);
  • 执行 git submodule status 会显示类似 -xxxxxx submodule-dir (未初始化) 的提示(说明子模块未拉取代码);
  • 后续若需重新拉取子模块,只需执行:

    git submodule init  # 初始化(读取 .gitmodules 配置)
    git submodule update  # 拉取子模块代码

简化命令(一键操作,替换为实际子模块名)

# 替换 submodule-dir 为你的子模块目录名
SUBMODULE_NAME="submodule-dir" && rm -rf $SUBMODULE_NAME && rm -rf .git/modules/$SUBMODULE_NAME && git config --unset-all submodule.$SUBMODULE_NAME

总结

通过“删除子模块目录 + 删除 Git 跟踪元数据”,即可让子模块恢复到“未拉取代码”的初始状态,和未执行 git submodule init/update 时完全一致,且保留了后续重新拉取的配置。

在 Yii2 中编写自定义类时,继承框架基础类的核心原则是:根据自定义类的功能场景,选择最贴合的「抽象基类/接口」或「功能基类」,避免盲目继承(如直接继承 yii\base\Object 已过时,Yii2.0.13+ 推荐 yii\base\BaseObject)。

以下按「功能场景分类」,整理常用的可继承基础类,附使用场景和代码示例,覆盖绝大多数开发需求:

一、核心基础类(所有自定义类的通用父类)

这类类是 Yii2 所有组件的根基,提供「属性访问、事件触发、依赖注入」等核心能力,适合所有需要框架核心特性的自定义类。

框架基础类核心功能适用场景代码示例
yii\base\BaseObject提供 __get()/__set()hasProperty()init() 等属性和初始化能力(Yii2.0.13+ 推荐)所有需要「属性访问、初始化逻辑」的自定义类php namespace app\components; use yii\base\BaseObject; class MyTool extends BaseObject { public $name; public function init() { parent::init(); // 初始化逻辑(如参数校验) if (empty($this->name)) { throw new \Exception('名称不能为空'); } } }
yii\base\Component继承 BaseObject,额外提供「事件机制、行为(Behavior)支持」需事件触发、行为扩展的类(如组件、服务)php namespace app\components; use yii\base\Component; class MyService extends Component { const EVENT_AFTER_DO = 'afterDo'; public function doSomething() { // 触发事件 $this->trigger(self::EVENT_AFTER_DO); } } // 使用时绑定事件 $service = new MyService(); $service->on(MyService::EVENT_AFTER_DO, function() { echo '执行后触发'; });
yii\base\Object旧版核心基类(Yii2.0.13 前),功能与 BaseObject 一致,已被弃用兼容旧版本代码(不推荐新增)-

二、数据模型类(处理数据验证、数据库交互)

若自定义类需「数据验证、数据库 CRUD」,优先继承以下模型基类,直接复用 Yii2 的数据处理能力。

框架基础类核心功能适用场景代码示例
yii\base\Model提供「属性验证、场景支持、错误信息管理」(无数据库交互)表单提交、接口参数验证(非数据库模型)php namespace app\models; use yii\base\Model; class LoginForm extends Model { public $username; public $password; public function rules() { return [ [['username', 'password'], 'required'], ['password', 'string', 'min' => 6], ]; } } // 使用时验证 $form = new LoginForm(['username' => 'test', 'password' => '123456']); if ($form->validate()) { // 验证通过 }
yii\db\ActiveRecord继承 Model,额外提供「数据库 CRUD、关联查询、属性映射」数据库表对应的模型(核心推荐)php namespace app\models; use yii\db\ActiveRecord; class User extends ActiveRecord { public static function tableName() { return 'user'; // 对应数据库表名 } } // 数据库操作 $user = User::findOne(1); $user->username = 'newName'; $user->save();
yii\db\BaseActiveRecordActiveRecord 的抽象基类,可用于自定义 ORM 逻辑(如非关系型数据库)扩展数据库驱动、自定义 ORM 时使用-
yii\base\DynamicModel动态模型,无需预先定义属性,适合临时数据验证(如单次接口参数)临时数据验证、动态表单(无需创建实体类)php $model = DynamicModel::validateData([ 'email' => 'test@example.com', 'age' => 20, ], [ ['email', 'email'], ['age', 'integer', 'min' => 18], ]); if ($model->hasErrors()) { // 处理错误 }

三、控制器/动作类(Web 接口/页面逻辑)

用于编写 Web 接口、页面渲染逻辑,继承后可直接复用「请求处理、响应输出、权限控制」等能力。

框架基础类核心功能适用场景代码示例
yii\web\ControllerWeb 应用核心控制器,提供「视图渲染、请求获取、响应处理、行为支持」普通 Web 页面、HTML 接口控制器php namespace app\controllers; use yii\web\Controller; class SiteController extends Controller { public function actionIndex() { // 渲染视图 return $this->render('index'); } }
yii\rest\Controller专为 RESTful 接口设计,提供「JSON 响应、HTTP 方法映射、接口权限」RESTful API 控制器(如前后端分离接口)php namespace app\controllers; use yii\rest\Controller; class ApiController extends Controller { public function actionUser($id) { return ['id' => $id, 'name' => 'test']; // 自动转为 JSON 响应 } }
yii\rest\ActiveController继承 rest\Controller,自动实现「CRUD 接口」(无需手动写增删改查)快速实现 RESTful CRUD 接口(如资源管理)php namespace app\controllers; use yii\rest\ActiveController; class UserController extends ActiveController { public $modelClass = 'app\models\User'; // 关联数据模型 } // 自动生成接口:GET /user(列表)、GET /user/1(详情)、POST /user(新增)
yii\console\Controller命令行控制器,用于编写定时任务、脚本(如数据迁移、批量处理)控制台命令、定时任务(如 yii xxx/xxxphp namespace app\commands; use yii\console\Controller; class TestController extends Controller { public function actionIndex() { echo '控制台命令执行成功'; } } // 执行:php yii test/index

四、过滤器/行为类(请求拦截、功能扩展)

用于「请求拦截、权限校验、日志记录、缓存控制」等横切逻辑,继承后可嵌入控制器/组件的生命周期。

框架基础类核心功能适用场景代码示例
yii\base\ActionFilter动作过滤器基类,提供 beforeAction()(动作执行前)、afterAction()(执行后)钩子接口权限校验、日志记录、请求频率限制php namespace app\filters; use yii\base\ActionFilter; class AuthFilter extends ActionFilter { public function beforeAction($action) { // 动作执行前校验 if (!Yii::$app->user->isGuest) { return true; } Yii::$app->response->statusCode = 401; return false; } } // 在控制器中使用 public function behaviors() { return [ 'auth' => ['class' => AuthFilter::class], ]; }
yii\filters\AccessControl内置权限过滤器,支持「角色权限、IP 白名单、HTTP 方法限制」快速实现权限控制(如仅管理员访问)php public function behaviors() { return [ 'access' => [ 'class' => \yii\filters\AccessControl::class, 'rules' => [ ['allow' => true, 'roles' => ['@'], // 仅登录用户允许 'actions' => ['index'], ], ], ], ]; }
yii\base\Behavior行为基类,用于给组件动态添加属性/方法(无侵入扩展)组件功能扩展(如给模型添加日志方法)php namespace app\behaviors; use yii\base\Behavior; use yii\db\ActiveRecord; class LogBehavior extends Behavior { public function events() { return [ ActiveRecord::EVENT_AFTER_INSERT => 'afterInsert', ]; } public function afterInsert($event) { // 模型新增后记录日志 Yii::info('新增数据:' . $event->sender->id); } } // 给模型添加行为 public function behaviors() { return ['log' => ['class' => LogBehavior::class]]; }

五、工具/辅助类(特定功能场景)

针对「缓存、日志、验证器、命令行」等特定场景,继承对应基类可复用框架内置能力。

框架基础类核心功能适用场景代码示例
yii\caching\Cache缓存抽象基类,提供 get()/set()/delete() 等缓存操作接口自定义缓存驱动(如 Redis 扩展、本地文件缓存)php namespace app\caching; use yii\caching\Cache; class MyCache extends Cache { protected function getValue($key) { // 自定义获取缓存逻辑 } protected function setValue($key, $value, $duration) { // 自定义设置缓存逻辑 } }
yii\log\Target日志目标基类,用于自定义日志存储方式(如写入数据库、第三方日志服务)扩展日志存储(如 ELK、阿里云日志)php namespace app\log; use yii\log\Target; class DbTarget extends Target { public function export() { $logs = $this->getLogs(); // 将日志写入数据库 foreach ($logs as $log) { Yii::$app->db->createCommand()->insert('sys_log', [ 'message' => $log[0], 'level' => $log[1], ])->execute(); } } }
yii\validators\Validator验证器基类,用于自定义数据验证规则(如手机号、身份证号校验)扩展验证规则(框架未提供的自定义校验)php namespace app\validators; use yii\validators\Validator; class PhoneValidator extends Validator { public function validateAttribute($model, $attribute) { $value = $model->$attribute; if (!preg_match('/^1[3-9]\d{9}$/', $value)) { $this->addError($model, $attribute, '手机号格式错误'); } } } // 在模型中使用 public function rules() { return [ ['phone', PhoneValidator::class], ]; }
yii\console\Action命令行动作基类,用于编写复杂命令行逻辑(拆分命令为多个动作)复杂控制台命令(如批量导入数据的子步骤)php namespace app\commands\actions; use yii\console\Action; class ImportAction extends Action { public function run($file) { // 执行导入逻辑 echo "从 {$file} 导入数据"; } } // 在命令行控制器中绑定 public function actions() { return [ 'import' => ImportAction::class, ]; } // 执行:php yii test/import --file=data.csv

六、继承原则与避坑要点

  1. 最小继承原则:不需要的功能不继承(如仅需属性验证 → 继承 Model,无需继承 ActiveRecord);
  2. 优先接口/抽象类:框架提供的抽象基类(如 CacheValidator)定义了标准接口,继承后需实现必填方法(如 CachegetValue());
  3. 避免多层继承:Yii2 推荐「组合优于继承」,复杂功能优先用「行为(Behavior)」扩展,而非多层继承;
  4. 注意版本兼容性BaseObject 是 Yii2.0.13+ 新增,若项目版本低于该版本,需用 Object
  5. 初始化逻辑写在 init():继承 BaseObject/Component 时,不要重写 __construct(),而是通过 init() 实现初始化(框架会自动调用)。

总结

选择继承的框架类,核心看「自定义类的功能场景」:

  • 数据验证 → yii\base\Model
  • 数据库交互 → yii\db\ActiveRecord
  • Web 接口 → yii\rest\Controller
  • 请求拦截 → yii\base\ActionFilter
  • 通用组件 → yii\base\Component(需事件/行为)或 yii\base\BaseObject(仅需属性/初始化)。

按场景选择合适的基类,可最大化复用框架能力,减少重复代码,同时保证代码符合 Yii2 的设计规范。