PHPでPOSTする
大昔に書いた記事にウソがあったので、それを訂正しつつ、PHPでPOSTするためのコードを何通りか書いてみるテスト。
下準備
以下のようなAPIを用意しておく。HTMLコードを吐き出す仕様になっているのは気にしない。
<dl> <?php foreach ($_POST as $key => $value): ?> <dt><?php echo htmlspecialchars($key); ?></dt> <dd><?php echo htmlspecialchars($value); ?></dd> <?php endforeach ?> </dl> <hr /> <dl> <?php foreach ($_FILES as $key => $file): ?> <dt><?php echo htmlspecialchars($key); ?></dt> <dd> name: <?php echo htmlspecialchars($file['name']); ?> <br /> type: <?php echo htmlspecialchars($file['type']); ?> <br /> size: <?php echo htmlspecialchars($file['size']); ?> <br /> error: <?php echo htmlspecialchars($file['error']); ?> <br /> tmp_name: <?php echo htmlspecialchars($file['tmp_name']); ?> <br /> <pre><?php var_dump(htmlspecialchars(file_get_contents($file['tmp_name']))); ?></pre> </dd> <?php endforeach ?> </dl>
本題
以前に書いたコードの焼き直しみたいなものだが。
<?php $protocol = 'http'; $host = 'localhost'; $port = 80; $path = '/post-api.php'; $apiUrl = "{$protocol}://{$host}:{$port}/{$path}"; $params = array( 'title' => 'POST test', 'content' => 'sample text', ); $files = array( 'my_file' => 'sample.txt' ); function buildRequestData($params, $files = null) { $data = ''; if (!empty($files) && is_array($files)) { $boundaryStr = '________' . time() . '________'; $contentType = "Content-Type: multipart/form-data; boundary={$boundaryStr}"; foreach ($params as $key => $value) { $data .= "--{$boundaryStr}\r\n"; $data .= "Content-Disposition: form-data; name={$key}\r\n"; $data .= "\r\n"; $data .= "{$value}\r\n"; } foreach ($files as $key => $file) { $filename = basename($file); $data .= "--{$boundaryStr}\r\n"; $data .= "Content-Disposition: form-data; name={$key}; filename=\"{$filename}\"\r\n"; $data .= "Content-Type: application/octet-stream\r\n"; $data .= "\r\n"; $data .= file_get_contents($file) . "\r\n"; } $data .= "--{$boundaryStr}--\r\n"; } else { $contentType = 'Content-Type: application/x-www-form-urlencoded'; $data .= http_build_query($params); } $headers = array( $contentType, 'Content-Length: ' . strlen($data), ); $requestData = array( 'method' => 'POST', 'content' => $data, 'header' => implode("\r\n", $headers), ); return $requestData; } function test_file_get_contents($url, $params, $files = null) { printf("=== %s ===\n", __FUNCTION__); $context = stream_context_create(array('http' => buildRequestData($params, $files))); var_dump(file_get_contents($url, false, $context)); } function test_fopen($url, $params, $files = null) { printf("=== %s ===\n", __FUNCTION__); $context = stream_context_create(array('http' => buildRequestData($params, $files))); $sock = fopen($url, 'rb', false, $context); if ($sock) { while (($s = fgets($sock))) { $tmp .= $s; } var_dump($tmp); fclose($sock); } } function test_fsockopen($host, $port, $path, $params, $files = null) { printf("=== %s ===\n", __FUNCTION__); $sock = fsockopen($host, $port); if ($sock) { $requestData = buildRequestData($params, $files); fputs($sock, "{$requestData['method']} {$path} HTTP/1.1\r\n"); fputs($sock, "Host: {$host}\r\n"); fputs($sock, "{$requestData['header']}\r\n"); fputs($sock, "\r\n"); fputs($sock, "{$requestData['content']}"); $len = 0; while (strlen(trim($s = fgets($sock)))) { if (preg_match('/^Content-Length: /', $s)) { $len = (int)preg_replace('/^Content-Length: /', '', $s); } echo "[H] {$s}"; } $s = fread($sock, $len); var_dump($s); fclose($sock); } } function test_stream_socket_client($protocol, $host, $port, $path, $params, $files = null) { printf("=== %s ===\n", __FUNCTION__); $remoteSocket = "{$protocol}://{$host}:{$port}"; $sock = stream_socket_client($remoteSocket); if ($sock) { $requestData = buildRequestData($params, $files); fputs($sock, "{$requestData['method']} {$path} HTTP/1.1\r\n"); fputs($sock, "Host: {$host}\r\n"); fputs($sock, "{$requestData['header']}\r\n"); fputs($sock, "\r\n"); fputs($sock, "{$requestData['content']}"); $len = 0; while (strlen(trim($s = fgets($sock)))) { if (preg_match('/^Content-Length: /', $s)) { $len = (int)preg_replace('/^Content-Length: /', '', $s); } echo "[H] {$s}"; } $s = fread($sock, $len); var_dump($s); fclose($sock); } } test_file_get_contents($apiUrl, $params); test_file_get_contents($apiUrl, $params, $files); echo "\n"; test_fopen($apiUrl, $params); test_fopen($apiUrl, $params, $files); echo "\n"; test_fsockopen($host, $port, $path, $params); test_fsockopen($host, $port, $path, $params, $files); echo "\n"; test_stream_socket_client('tcp', $host, $port, $path, $params); test_stream_socket_client('tcp', $host, $port, $path, $params, $files);
実行結果は以下のような感じ。
=== test_file_get_contents === string(105) "<dl> <dt>title</dt> <dd>POST test</dd> <dt>content</dt> <dd>sample text</dd> </dl> <hr /> <dl> </dl> " === test_file_get_contents === string(326) "<dl> <dt>title</dt> <dd>POST test</dd> <dt>content</dt> <dd>sample text</dd> </dl> <hr /> <dl> <dt>my_file</dt> <dd> name: sample.txt <br /> type: application/octet-stream <br /> size: 21 <br /> error: 0 <br /> tmp_name: /tmp/phpTb7Eyx <br /> <pre>string(21) "SAMPLE TEXT CONTENTS " </pre> </dd> </dl> " === test_fopen === string(105) "<dl> <dt>title</dt> <dd>POST test</dd> <dt>content</dt> <dd>sample text</dd> </dl> <hr /> <dl> </dl> " === test_fopen === string(326) "<dl> <dt>title</dt> <dd>POST test</dd> <dt>content</dt> <dd>sample text</dd> </dl> <hr /> <dl> <dt>my_file</dt> <dd> name: sample.txt <br /> type: application/octet-stream <br /> size: 21 <br /> error: 0 <br /> tmp_name: /tmp/php2AD6yA <br /> <pre>string(21) "SAMPLE TEXT CONTENTS " </pre> </dd> </dl> " === test_fsockopen === [H] HTTP/1.1 200 OK [H] Date: Sun, 30 May 2021 11:54:49 GMT [H] Server: Apache/2.4.6 (CentOS) OpenSSL/1.0.2k-fips PHP/5.6.40 [H] X-Powered-By: PHP/5.6.40 [H] Content-Length: 105 [H] Content-Type: text/html; charset=UTF-8 string(105) "<dl> <dt>title</dt> <dd>POST test</dd> <dt>content</dt> <dd>sample text</dd> </dl> <hr /> <dl> </dl> " === test_fsockopen === [H] HTTP/1.1 200 OK [H] Date: Sun, 30 May 2021 11:54:49 GMT [H] Server: Apache/2.4.6 (CentOS) OpenSSL/1.0.2k-fips PHP/5.6.40 [H] X-Powered-By: PHP/5.6.40 [H] Content-Length: 326 [H] Content-Type: text/html; charset=UTF-8 string(326) "<dl> <dt>title</dt> <dd>POST test</dd> <dt>content</dt> <dd>sample text</dd> </dl> <hr /> <dl> <dt>my_file</dt> <dd> name: sample.txt <br /> type: application/octet-stream <br /> size: 21 <br /> error: 0 <br /> tmp_name: /tmp/phpssgUsE <br /> <pre>string(21) "SAMPLE TEXT CONTENTS " </pre> </dd> </dl> " === test_stream_socket_client === [H] HTTP/1.1 200 OK [H] Date: Sun, 30 May 2021 11:54:49 GMT [H] Server: Apache/2.4.6 (CentOS) OpenSSL/1.0.2k-fips PHP/5.6.40 [H] X-Powered-By: PHP/5.6.40 [H] Content-Length: 105 [H] Content-Type: text/html; charset=UTF-8 string(105) "<dl> <dt>title</dt> <dd>POST test</dd> <dt>content</dt> <dd>sample text</dd> </dl> <hr /> <dl> </dl> " === test_stream_socket_client === [H] HTTP/1.1 200 OK [H] Date: Sun, 30 May 2021 11:54:49 GMT [H] Server: Apache/2.4.6 (CentOS) OpenSSL/1.0.2k-fips PHP/5.6.40 [H] X-Powered-By: PHP/5.6.40 [H] Content-Length: 326 [H] Content-Type: text/html; charset=UTF-8 string(326) "<dl> <dt>title</dt> <dd>POST test</dd> <dt>content</dt> <dd>sample text</dd> </dl> <hr /> <dl> <dt>my_file</dt> <dd> name: sample.txt <br /> type: application/octet-stream <br /> size: 21 <br /> error: 0 <br /> tmp_name: /tmp/phpPF5VVZ <br /> <pre>string(21) "SAMPLE TEXT CONTENTS " </pre> </dd> </dl> "