本文目录导读:

在 PHP 中测试文件上传有多种方法,以下是几种常见且实用的测试方案:
使用 PHP 内置测试类(推荐)
使用 PHPUnit 和 vfsStream
<?php
use PHPUnit\Framework\TestCase;
use org\bovigo\vfs\vfsStream;
class FileUploadTest extends TestCase
{
public function testFileUpload()
{
// 创建虚拟文件系统
$root = vfsStream::setup('uploads');
// 模拟上传文件
$file = [
'name' => 'test.txt',
'type' => 'text/plain',
'tmp_name' => vfsStream::newFile('test.txt')
->withContent('这是一段测试内容')
->at($root)
->url(),
'error' => UPLOAD_ERR_OK,
'size' => 57
];
// 调用上传处理函数
$result = handleFileUpload($file, vfsStream::url('uploads') . '/');
// 断言
$this->assertTrue($result['success']);
$this->assertFileExists(vfsStream::url('uploads') . '/test.txt');
}
// 测试上传错误
public function testFileUploadWithError()
{
$file = [
'name' => 'test.txt',
'type' => 'text/plain',
'tmp_name' => '',
'error' => UPLOAD_ERR_NO_FILE,
'size' => 0
];
$result = handleFileUpload($file, '/tmp/uploads/');
$this->assertFalse($result['success']);
$this->assertEquals('没有文件上传', $result['message']);
}
}
使用 curl 命令测试
创建测试脚本 upload_test.php
<?php
function handleFileUpload($file, $uploadDir) {
$uploadDir = rtrim($uploadDir, '/') . '/';
if ($file['error'] !== UPLOAD_ERR_OK) {
return ['success' => false, 'message' => '上传失败,错误码: ' . $file['error']];
}
if (!is_uploaded_file($file['tmp_name'])) {
return ['success' => false, 'message' => '不是一个有效的上传文件'];
}
// 验证文件类型和大小
if ($file['size'] > 2 * 1024 * 1024) {
return ['success' => false, 'message' => '文件太大'];
}
// 移动文件
$targetPath = $uploadDir . time() . '_' . basename($file['name']);
if (move_uploaded_file($file['tmp_name'], $targetPath)) {
return ['success' => true, 'path' => $targetPath, 'message' => '上传成功'];
}
return ['success' => false, 'message' => '文件保存失败'];
}
// 处理上传请求
if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_FILES['file'])) {
header('Content-Type: application/json');
echo json_encode(handleFileUpload($_FILES['file'], '/tmp/uploads/'));
}
使用 curl 测试
# 测试文件上传 curl -X POST -F "file=@/path/to/local/file.txt" http://localhost/upload_test.php # 测试图片上传 curl -X POST -F "image=@/path/to/image.png;type=image/png" http://localhost/upload_test.php # 测试文件上传并设置 MIME 类型 curl -X POST -F "file=@/path/to/document.pdf;type=application/pdf" http://localhost/upload_test.php # 测试多个文件 curl -X POST -F "files[]=@/path/to/file1.txt" -F "files[]=@/path/to/file2.txt" http://localhost/upload_test.php
编写独立的测试脚本
创建 test_upload.php
<?php
// 创建测试方法
function createTestFile($filename, $content) {
$tempDir = sys_get_temp_dir();
$tempFile = $tempDir . '/' . $filename;
file_put_contents($tempFile, $content);
return $tempFile;
}
function simulateFileUpload() {
// 模拟表单上传
$_FILES = [
'file' => [
'name' => 'test.txt',
'type' => 'text/plain',
'tmp_name' => createTestFile('phptmp', '这是模拟的上传文件内容'),
'error' => UPLOAD_ERR_OK,
'size' => 57
]
];
// 创建临时上传目录
$uploadDir = sys_get_temp_dir() . '/uploads';
if (!is_dir($uploadDir)) {
mkdir($uploadDir, 0777, true);
}
// 调用上传处理逻辑
$result = processUpload($uploadDir);
// 验证结果
echo "测试结果:" . json_encode($result) . "\n";
// 清理
unlink($_FILES['file']['tmp_name']);
return $result;
}
function processUpload($uploadDir) {
if (!isset($_FILES['file'])) {
return ['success' => false, 'message' => '没有找到文件'];
}
$file = $_FILES['file'];
if ($file['error'] !== UPLOAD_ERR_OK) {
return ['success' => false, 'message' => '上传错误'];
}
$targetFile = rtrim($uploadDir, '/') . '/' . $file['name'];
if (move_uploaded_file($file['tmp_name'], $targetFile)) {
return ['success' => true, 'path' => $targetFile];
}
return ['success' => false, 'message' => '移动失败'];
}
// 执行测试
simulateFileUpload();
使用 BrowserStack / TestingBot 云测试
<?php
require 'vendor/autoload.php';
class BrowserUploadTest extends PHPUnit_Extensions_Selenium2TestCase
{
public function setUp() {
$this->setBrowser('firefox');
$this->setBrowserUrl('http://localhost:3000/');
// 云测试平台配置
$this->setHost('hub-cloud.browserstack.com');
$this->setPort(80);
$this->setBrowserUrl('http://localhost');
}
public function testFileUpload() {
$this->open('/upload_form.php');
// 找到文件上传输入框
$fileInput = $this->byCssSelector('input[type="file"]');
// 设置文件路径
$fileInput->value(__DIR__ . '/test_files/upload_test.txt');
// 提交表单
$this->byId('submit')->click();
// 验证上传结果
$this->assertContains('上传成功', $this->body()->text());
}
}
完整的测试脚本示例
<?php
class FileUploadTester {
private $uploadDir;
private $testResults = [];
public function __construct($uploadDir) {
$this->uploadDir = $uploadDir;
}
public function testAll() {
$this->testTextFileUpload();
$this->testImageFileUpload();
$this->testLargeFile();
$this->testEmptyFile();
$this->testInvalidFileType();
return $this->testResults;
}
private function testTextFileUpload() {
$file = $this->createMockFile('test.txt', 'text/plain', 'Hello World');
$result = $this->uploadFile($file);
$this->testResults['text_upload'] = $result;
}
private function testImageFileUpload() {
// 创建模拟图片文件
$imageContent = base64_decode('iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJ');
$file = $this->createMockFile('test.png', 'image/png', $imageContent);
$result = $this->uploadFile($file);
$this->testResults['image_upload'] = $result;
}
private function createMockFile($name, $type, $content) {
$tempFile = tempnam(sys_get_temp_dir(), 'upload');
file_put_contents($tempFile, $content);
return [
'name' => $name,
'type' => $type,
'tmp_name' => $tempFile,
'error' => UPLOAD_ERR_OK,
'size' => strlen($content)
];
}
private function uploadFile($file) {
// 这里实现实际的上传逻辑
$targetFile = rtrim($this->uploadDir, '/') . '/' . time() . '_' . $file['name'];
if (move_uploaded_file($file['tmp_name'], $targetFile)) {
unlink($file['tmp_name']);
return ['success' => true, 'message' => '文件上传成功'];
}
return ['success' => false, 'message' => '文件上传失败'];
}
}
// 使用测试器
$tester = new FileUploadTester('/tmp/uploads/');
$results = $tester->testAll();
echo "测试结果:\n";
foreach ($results as $test => $result) {
echo $test . ': ' . ($result['success'] ? '✓' : '✗') . ' ' . $result['message'] . "\n";
}
Postman 测试
使用 Postman 进行测试:
- 创建新请求
- 选择 POST 方法
- 在 Body 中选择
form-data - 添加 key 为 file 的文件字段
- 选择要上传的文件
- 发送请求并查看响应
最佳实践建议
- 使用
is_uploaded_file()验证:确保文件确实是 HTTP POST 上传的 - 验证文件类型和大小:使用
$_FILES['file']['size']和 content type 验证 - 使用安全的文件名:不要直接使用用户提供的文件名
- 设置临时目录:确保 php.ini 中的
upload_tmp_dir可写 - 错误处理:始终检查
$_FILES['file']['error']的值
这些方法覆盖了单元测试、集成测试和手动测试的不同场景,可以根据具体需求选择使用。