0
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

MultipartStreamを使用してmultipart/form-dataでPOSTする

Posted at

目的

multipart/form-data形式で添付ファイルを伴いPOSTするForm画面を作ったが、諸般の事情でBrowserKitを使ったテストを使っており、その流れでMultipartStreamを使うことになったのでその手順を記載します。

テストするフォーム

テストするフォームはここでは簡易的にビルトインウェブサーバーを使用してダミーのものを用意します。

% mkdir public_html
% cd ~/public_html
% vi test.php
%
test.php
<?php

// POSTされた内容を表示
$fp = fopen('php://stdout', 'w');
fprintf($fp, var_export($_POST, true));
fprintf($fp, "\n");

// ファイルがある場合は情報と内容を表示
foreach($_FILES as $file) {
    fprintf($fp, "ファイル情報\n");
    fprintf($fp, var_export($file, true));
    fprintf($fp, "ファイル内容\n");
    fprintf($fp, var_export(file_get_contents($file['tmp_name']), true));
}
ビルトインウェブサーバーを起動
% php -S localhost:8000 -t ~/public_html
[Sun Jun 15 17:01:13 2025] PHP 8.4.7 Development Server (http://localhost:8000) started

テストスクリプト

テスト環境作成
mkdir test_script
cd test_script
# composer.phar をインストール(手順省略)

php composer.phar require symfony/browser-kit
php composer.phar require symfony/http-client
php composer.phar require symfony/mime  
php composer.phar require guzzlehttp/guzzle

vi post_multipart_form.php
post_multipart_form.php
<?php

require_once __DIR__ . '/vendor/autoload.php';

use GuzzleHttp\Psr7\MultipartStream;
use GuzzleHttp\Psr7\UploadedFile;
use Symfony\Component\BrowserKit\HttpBrowser;
use Symfony\Component\HttpClient\HttpClient;

function getBrowser(): HttpBrowser
{
    try {
        $client = HttpClient::create();
        $browser = new HttpBrowser($client);
    } catch (Exception $e) {
        echo $e->getMessage() . "\n";
    }
    return $browser;
}

function create_post_data(array $array, string $prefix = '', string $suffix = ''): array
{
    $result = [];

    foreach ($array as $key => $value) {
        // 再帰的に処理
        if (is_array($value)) {
            $result = array_merge($result, flatten($value, $prefix . $key . $suffix . '[', ']'));
        } else {
            if ($value instanceof UploadedFile) {
                // ファイルの場合
                $result[] = [
                    'name' => $prefix . $key . $suffix,
                    'filename' => $value->getClientFilename(),
                    'Mime-Type' => $value->getClientMediaType(),
                    'contents' => file_get_contents($value->getClientFilename()),
                ];
            } else {
                // ファイル以外の場合
                $result[] = [
                    'name' => $prefix . $key . $suffix,
                    'contents' => $value,
                ];
            }
        }
    }

    return $result;
}

// POSTするデータ
$file = __DIR__ . '/test.txt';
$data = [
    'title' => 'こんにちは',
    'description' => 'よろしくお願いします',
    'file' => new UploadedFile($file, filesize($file), UPLOAD_ERR_OK, $file, 'text/plain')
];

$browser = getBrowser();
$stream = new MultipartStream(create_post_data($data));
$contents = $stream->getContents();
$browser->request(
    'POST',
    'http://127.0.0.1:8000/test.php',
    [],
    [],
    ['Content-Type' => 'multipart/form-data; boundary=' . $stream->getBoundary()], $contents);

ここで重要なのはContent-Typeboundary=必ず指定することです。これが無い or 指定した値に誤りがあるとサーバーサイドではmultipart/form-dataであることを正確に認識してくれません。

アップロードするファイルは適当に用意

text.txt
あああああああああああああああああ

実際にPOSTしてみます

% php post_multipart_form.php

ビルトインサーバー側では以下のように表示されます

[Sun Jun 15 18:35:46 2025] PHP 8.4.7 Development Server (http://localhost:8000) started
[Sun Jun 15 18:35:49 2025] 127.0.0.1:65123 Accepted
array (
  'title' => 'こんにちは',
  'description' => 'よろしくお願いします',
)
ファイル情報
array (
  'name' => 'test.txt',
  'full_path' => 'test.txt',
  'type' => 'text/plain',
  'tmp_name' => '/private/var/folders/1x/zscw44zn5pjczmjb4cl7lzqr0000gn/T/php0bpnfo4fk4jkbbzgFC7',
  'error' => 0,
  'size' => 52,
)
ファイル内容
'あああああああああああああああああ
'[Sun Jun 15 18:35:49 2025] 127.0.0.1:65123 [200]: POST /test.php
[Sun Jun 15 18:35:49 2025] 127.0.0.1:65123 Closing

POSTした内容がmultipart/form-data形式となっていることとファイルの内容が正しいことが確認できました。以上です。

0
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?