Uppy与CodeIgniter Events集成:PHP事件系统
引言:解决文件上传的事件驱动痛点
在Web开发中,文件上传是一个常见但复杂的功能。传统的上传处理方式往往将验证、存储和后续操作耦合在一起,导致代码难以维护和扩展。Uppy作为现代化的文件上传前端库,提供了强大的上传体验,而CodeIgniter的事件系统则为后端处理提供了灵活的钩子机制。本文将展示如何将两者结合,构建一个松耦合、可扩展的文件上传处理流程。
读完本文后,你将能够:
- 理解Uppy与CodeIgniter事件系统集成的优势
- 掌握在CodeIgniter中配置和使用事件的方法
- 实现文件上传过程中的事件触发与处理
- 构建可扩展的文件上传处理流程
Uppy前端配置
首先,我们需要配置Uppy前端,使其能够与CodeIgniter后端进行通信。以下是一个基本的Uppy配置示例:
import Uppy from '@uppy/core'
import Dashboard from '@uppy/dashboard'
import Webcam from '@uppy/webcam'
import XHRUpload from '@uppy/xhr-upload'
import '@uppy/core/dist/style.css'
import '@uppy/dashboard/dist/style.css'
import '@uppy/webcam/dist/style.css'
const uppy = new Uppy({
debug: true,
autoProceed: false,
})
uppy.use(Webcam)
uppy.use(Dashboard, {
inline: true,
target: 'body',
plugins: ['Webcam'],
})
uppy.use(XHRUpload, {
endpoint: '/upload',
headers: {
'X-CSRF-TOKEN': document.querySelector('meta[name="csrf-token"]').content
}
})
// 监听上传成功事件
uppy.on('upload-success', (file, response) => {
console.log('Upload successful:', file, response)
// 可以在这里触发前端后续操作
})
这段代码配置了一个包含仪表盘和 webcam 功能的 Uppy 实例,并使用 XHRUpload 插件将文件上传到 CodeIgniter 后端的 /upload 端点。我们还添加了 CSRF 令牌,以确保与 CodeIgniter 的安全通信。
CodeIgniter 后端设置
1. 创建上传控制器
首先,我们需要创建一个处理上传请求的控制器。在 CodeIgniter 中,创建一个 UploadController.php 文件:
<?php
namespace App\Controllers;
use CodeIgniter\Controller;
use CodeIgniter\Events\Events;
class UploadController extends Controller
{
public function index()
{
// 检查请求方法
if ($this->request->getMethod() !== 'post') {
return $this->response->setStatusCode(405)->setJSON(['error' => 'Method Not Allowed']);
}
// 获取上传的文件
$file = $this->request->getFile('file');
// 触发文件上传开始事件
Events::trigger('upload_start', $file);
// 验证文件
if (!$file->isValid()) {
// 触发上传验证失败事件
Events::trigger('upload_validation_failed', $file, $file->getErrorString());
return $this->response->setStatusCode(400)->setJSON([
'error' => $file->getErrorString()
]);
}
// 触发文件验证成功事件
Events::trigger('upload_validated', $file);
// 移动文件到上传目录
$newName = $file->getRandomName();
$file->move(WRITEPATH . 'uploads', $newName);
// 准备文件信息数组
$fileInfo = [
'name' => $file->getClientName(),
'new_name' => $newName,
'type' => $file->getClientMimeType(),
'size' => $file->getSize(),
'path' => WRITEPATH . 'uploads/' . $newName
];
// 触发文件上传成功事件
Events::trigger('upload_success', $fileInfo);
return $this->response->setStatusCode(201)->setJSON([
'message' => 'File uploaded successfully',
'file' => $fileInfo
]);
}
}
2. 配置路由
在 app/Config/Routes.php 中添加一个路由,将上传请求映射到我们刚刚创建的控制器:
$routes->post('upload', 'UploadController::index');
3. 配置事件处理
现在,我们需要配置 CodeIgniter 的事件系统来处理我们触发的事件。在 app/Config/Events.php 文件中注册事件处理器:
<?php
namespace Config;
use CodeIgniter\Events\Events;
Events::on('upload_start', function ($file) {
log_message('info', 'File upload started: ' . $file->getClientName());
// 可以在这里执行上传开始前的准备工作
});
Events::on('upload_validation_failed', function ($file, $error) {
log_message('error', 'File validation failed for ' . $file->getClientName() . ': ' . $error);
// 可以在这里添加错误处理逻辑,如发送通知等
});
Events::on('upload_validated', function ($file) {
log_message('info', 'File validated successfully: ' . $file->getClientName());
// 可以在这里执行文件验证后的操作,如病毒扫描等
});
Events::on('upload_success', function ($fileInfo) {
log_message('info', 'File uploaded successfully: ' . $fileInfo['name']);
// 可以在这里执行文件上传后的操作,如生成缩略图、添加到数据库等
// 例如,我们可以在这里触发另一个事件来处理文件处理
Events::trigger('process_uploaded_file', $fileInfo);
});
// 处理已上传文件的事件
Events::on('process_uploaded_file', function ($fileInfo) {
log_message('info', 'Processing uploaded file: ' . $fileInfo['name']);
// 示例:如果是图片文件,生成缩略图
if (strpos($fileInfo['type'], 'image/') === 0) {
// 这里添加生成缩略图的逻辑
log_message('info', 'Generating thumbnail for image: ' . $fileInfo['name']);
}
// 示例:将文件信息保存到数据库
$model = new \App\Models\FileModel();
$model->save([
'name' => $fileInfo['name'],
'new_name' => $fileInfo['new_name'],
'type' => $fileInfo['type'],
'size' => $fileInfo['size'],
'path' => $fileInfo['path'],
'uploaded_at' => date('Y-m-d H:i:s')
]);
});
4. 创建文件模型
为了演示如何将文件信息保存到数据库,我们创建一个简单的 FileModel.php:
<?php
namespace App\Models;
use CodeIgniter\Model;
class FileModel extends Model
{
protected $table = 'files';
protected $primaryKey = 'id';
protected $allowedFields = ['name', 'new_name', 'type', 'size', 'path', 'uploaded_at'];
}
完整的上传流程
下图展示了Uppy与CodeIgniter事件系统集成的完整上传流程:
高级应用:自定义事件和监听器
对于更复杂的应用,我们可以创建自定义事件类和监听器,使代码更加结构化。
创建自定义事件类
<?php
namespace App\Events;
class FileUploadEvent
{
public $fileInfo;
public function __construct(array $fileInfo)
{
$this->fileInfo = $fileInfo;
}
}
创建监听器类
<?php
namespace App\Listeners;
use App\Events\FileUploadEvent;
class ProcessImageListener
{
public function handle(FileUploadEvent $event)
{
$fileInfo = $event->fileInfo;
// 仅处理图片文件
if (strpos($fileInfo['type'], 'image/') === 0) {
// 图片处理逻辑
log_message('info', 'Processing image: ' . $fileInfo['name']);
// 例如:生成缩略图、裁剪图片等
}
}
}
注册自定义事件和监听器
在 app/Config/Events.php 中:
Events::on('upload_success', function ($fileInfo) {
$event = new \App\Events\FileUploadEvent($fileInfo);
Services::events()->trigger($event);
});
Services::events()->on('App\Events\FileUploadEvent', 'App\Listeners\ProcessImageListener::handle');
总结与扩展
通过将Uppy与CodeIgniter的事件系统集成,我们构建了一个松耦合、可扩展的文件上传处理流程。这种方式的主要优势包括:
- 关注点分离:将上传处理的不同阶段分离为独立的事件处理函数
- 可扩展性:可以轻松添加新的事件处理逻辑,而无需修改核心上传代码
- 可维护性:每个事件处理器负责单一职责,使代码更易于理解和维护
未来,你可以进一步扩展这个系统:
- 添加更多事件,如上传进度事件、文件删除事件等
- 实现更复杂的文件处理逻辑,如视频转码、文档转换等
- 集成第三方服务,如云存储、CDN等
- 添加文件权限控制和用户配额管理
通过这种事件驱动的架构,你的文件上传系统将能够适应不断变化的需求,同时保持代码的清晰和可维护性。
参考资料
- Uppy官方文档: packages/@uppy/core/README.md
- CodeIgniter事件系统: CodeIgniter用户指南
- 示例代码: examples/xhr-php/
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考



