目的
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 createPostData(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(createPostData($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-Type
にboundary=
を必ず指定することです。これが無い 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
形式となっていることとファイルの内容が正しいことが確認できました。以上です。