使用THTTPClient无法向服务器发送文件的问题排查(Delphi 11)
Delphi THTTPClient 文件上传至PHP服务端失败问题排查与解决
问题背景
- 环境:Embarcadero® Delphi 11.0 Version 28.0
- 任务:将本地文件
d:\1.txt上传至http://example.com/upload.php,保存至网站根目录 - 问题:调用
THTTPClient.Post后,服务器返回200状态码,但PHP服务端未接收到文件,$_FILES数组无有效数据
相关日志与代码
服务器日志
[19/Jan/2024:21:08:46 +0500] "POST /upload.php HTTP/1.0" 200 3507 "-" "Embarcadero URI Client/1.0"
原Delphi客户端代码
var HTTPClient: THTTPClient; begin HTTPClient := THTTPClient.Create; try // 设置Content-Type请求头 HTTPClient.CustomHeaders['Content-Type'] := 'application/octet-stream'; // 上传文件至服务器 HTTPClient.Post('http://example.com/upload.php', TFileStream.Create('d:\1.txt', fmOpenRead), nil); finally HTTPClient.Free; end; end;
原PHP服务端代码
<?php // 保存上传文件的路径 $targetPath = '/path/to/save/1.txt'; if ($_FILES['file']['error'] === UPLOAD_ERR_OK) { // 将上传文件移动到指定位置 if (move_uploaded_file($_FILES['file']['tmp_name'], $targetPath)) { // 文件上传成功 echo 'Success: File uploaded successfully.'; } else { // 移动文件失败 echo 'Error: Unable to move uploaded file.'; } } else { // 文件上传出错 echo 'Error: File upload error.'; }?>
原因分析
- 请求格式不匹配:客户端设置的
Content-Type: application/octet-stream是二进制流格式,但PHP的$_FILES仅支持解析**multipart/form-data**格式的表单文件上传请求,这种格式是HTTP文件上传的标准协议格式。 - 数据未按表单字段封装:客户端直接上传原始文件流,没有按照表单字段的结构封装数据,PHP无法识别该请求为文件上传请求,因此不会将数据写入
$_FILES数组。
修复方案
1. 修改Delphi客户端代码
使用TMultipartFormData构建符合标准的表单上传请求,THTTPClient会自动处理正确的Content-Type和请求体结构:
var HTTPClient: THTTPClient; FormData: TMultipartFormData; begin HTTPClient := THTTPClient.Create; FormData := TMultipartFormData.Create; try // 添加文件到表单,字段名'file'需与服务端$_FILES['file']对应 // 第三个参数为文件MIME类型,文本文件可设为'text/plain' FormData.AddFile('file', 'd:\1.txt', 'text/plain'); // 发送POST请求,无需手动设置Content-Type HTTPClient.Post('http://example.com/upload.php', FormData); finally // 务必释放资源 FormData.Free; HTTPClient.Free; end; end;
2. 优化PHP服务端代码
- 修正目标路径为网站根目录的实际路径(例如
/var/www/html/1.txt) - 添加权限检查与调试输出,便于排查问题:
<?php // 调试:输出所有上传信息(上线前可删除) var_dump($_FILES); var_dump($_POST); // 替换为网站根目录的实际路径 $targetPath = '/var/www/html/1.txt'; $targetDir = dirname($targetPath); // 先检查目标目录是否存在且可写 if (!is_dir($targetDir)) { mkdir($targetDir, 0755, true); } if (isset($_FILES['file']) && $_FILES['file']['error'] === UPLOAD_ERR_OK) { if (is_writable($targetDir)) { if (move_uploaded_file($_FILES['file']['tmp_name'], $targetPath)) { echo 'Success: File uploaded successfully.'; } else { echo 'Error: Failed to move file. Check file permissions.'; } } else { echo 'Error: Target directory is not writable.'; } } else { $errorMsg = isset($_FILES['file']) ? 'Upload error code: ' . $_FILES['file']['error'] : 'No file received.'; echo 'Error: ' . $errorMsg; } ?>
关键说明
- 表单字段名必须前后端一致:客户端
AddFile的第一个参数'file',必须和服务端$_FILES['file']的索引完全匹配。 TMultipartFormData会自动生成正确的请求边界和Content-Type头,无需手动设置,避免格式错误。
内容的提问来源于stack exchange,提问作者ывапав
相关产品推荐
相关产品推荐

