You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在REST API中使用PUT方法实现文件及参数上传

问题根因

你遇到的PUT请求无法正常获取multipart/form-data格式的参数和文件,本质不是Slim框架的问题:PHP原生仅会自动解析POST请求的multipart/form-data请求体,填充到$_POST和$_FILES全局变量中,PUT、PATCH等请求方法的同格式请求体不会被默认解析,因此Slim也无法直接通过常规方法拿到参数和上传文件。

推荐实现方案

方案1:使用HTTP方法欺骗(优先推荐,无额外开发成本)

这是Slim官方推荐的兼容方案,完全符合RESTful规范,不需要修改你之前写的POST请求业务逻辑:

  • 前端仍然发送multipart/form-data格式的POST请求
  • 在请求中添加_METHOD=PUT的参数(可以是表单隐藏字段,也可以是请求参数),或者添加X-HTTP-Method-Override: PUT请求头
  • Slim会自动将该请求匹配到你定义的PUT路由规则,同时你仍然可以正常使用$request->getParsedBody()获取普通参数、$request->getUploadedFiles()获取上传文件,和之前POST请求的调用逻辑完全一致。

方案2:原生PUT请求手动解析请求体

如果必须发送原生PUT请求,可以通过中间件提前解析multipart请求体,将解析结果注入到Slim的请求对象中:

  1. 安装成熟的multipart解析库,避免手动处理边界问题:
composer require riverline/multipart-parser
  1. 全局添加解析中间件:
use Riverline\MultiPartParser\StreamedPart;
use Psr\Http\Message\ServerRequestInterface as Request;
use Psr\Http\Server\RequestHandlerInterface as RequestHandler;
use Slim\Psr7\UploadedFile;

$app->add(function (Request $request, RequestHandler $handler) {
    // 仅处理PUT类型的multipart/form-data请求
    if (
        $request->getMethod() === 'PUT'
        && str_starts_with($request->getHeaderLine('Content-Type'), 'multipart/form-data')
    ) {
        $stream = fopen('php://temp', 'rw+');
        fwrite($stream, (string) $request->getBody());
        rewind($stream);
        $parser = new StreamedPart($stream);

        $parsedParams = [];
        $uploadedFiles = [];

        foreach ($parser->getParts() as $part) {
            if ($part->isFile()) {
                // 写入临时文件
                $tmpPath = tempnam(sys_get_temp_dir(), 'slim_put_upload');
                file_put_contents($tmpPath, $part->getBody());
                // 封装为Slim标准的UploadedFile对象
                $uploadedFiles[$part->getName()] = new UploadedFile(
                    $tmpPath,
                    $part->getFileName(),
                    $part->getMimeType(),
                    $part->getSize(),
                    UPLOAD_ERR_OK
                );
            } else {
                $parsedParams[$part->getName()] = $part->getBody();
            }
        }

        // 将解析结果注入请求对象
        $request = $request->withParsedBody($parsedParams);
        $request = $request->withUploadedFiles($uploadedFiles);
    }

    return $handler->handle($request);
});
  1. 路由层正常调用即可,和POST逻辑完全一致:
$app->put('/resource/{id}', function (Request $request, $response, $args) {
    $resourceId = $args['id'];
    // 获取普通参数
    $updateParams = $request->getParsedBody();
    // 获取上传文件
    $uploadedFiles = $request->getUploadedFiles();

    // 原有业务逻辑直接复用即可

    return $response->withStatus(200);
});

注意事项

  • 方法欺骗方案兼容性最好,没有额外的内存开销,适合绝大多数场景
  • 原生PUT解析方案需要注意大文件上传场景,建议使用流式解析避免内存溢出
  • 不要手动实现multipart解析逻辑,边界场景(嵌套参数、特殊文件名、分块传输等)处理成本极高

内容的提问来源于stack exchange,提问作者Jdc

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.27 15:06:04