PHP4.xx系 サーバ側からPOST送信(multipart対応)
以前書いたものがPHP4.xx系で動かなかったようで、対応させてみました。
無駄な記述は多くなるものの、このままPHP5系でも動作します。
PHP4系は初めて触ったのですが、tryが無いとか配列リテラルでおこられたりとか色々と不便ですね。
何気ないところで言語の進化を感じました。
<?php define('CRLF', "\r\n"); //PHP4にはhttp_build_queryがないので実装 if (!function_exists('http_build_query')) { function http_build_query($data, $prefix = '', $sep = '', $key = '') { $ret = array(); foreach ((array)$data as $k => $v) { if (is_int($k) && $prefix != null) { $k = urlencode($prefix . $k); } if ((!empty($key)) || ($key === 0)) { $k = $key . '[' . urlencode($k) . ']'; } if (is_array($v) || is_object($v)) { array_push($ret, http_build_query($v, '', $sep, $k)); } else { array_push($ret, $k . '=' . urlencode($v)); } } if (empty($sep)) { $sep = ini_get('arg_separator.output'); } return implode($sep, $ret); } } //PHP4.**用 HTTPリクエスト function PHP4httpRequest($url, $options, $timeout = 300){ $http = $options['http']; $URL = parse_url($url); if (strtoupper($URL['scheme']) !== 'HTTP') { return 'HTTP以外の通信には対応していません。'; } $URL['query'] = (isset($URL['query'])) ? '?' . $URL['query'] : ''; if (!isset($URL['port'])){ $URL['port'] = 80; } if (!isset($http['method'])){ $http['method'] = 'GET'; } $request = $http['method'] . ' ' . $URL['path'] . $URL['query'] . ' HTTP/1.0' . CRLF; $request .= 'Host: ' . $URL['host'] . CRLF; $request .= 'User-Agent: PHP/' . phpversion(). CRLF; // Basic認証用ヘッダ if (isset($URL['user']) && isset($URL['pass'])) { $request .= 'Authorization: Basic ' . base64_encode($URL['user'] . ':' . $URL['pass']) . CRLF; } $request .= $http['header']; $request .= CRLF . CRLF; if (strtoupper($http['method']) == 'POST') { $request .= $http['content']; } $fp = fsockopen($URL['host'], $URL['port'], $errno, $errstr, $timeout); if (!$fp) { return "$errstr ($errno)\n"; } fputs($fp, $request); $response = ''; while (!feof($fp)) { $response .= fgets($fp, 4096); } fclose($fp); $DATA = split(CRLF . CRLF, $response, 2); return $DATA[1]; } //$urlに、$paramsのパラメータをPOST function httpPost($url, $params, $files = NULL){ $isMultipart = ($files) ? true : false; if ($isMultipart){ //ファイルアップロードを伴う場合、multipartで送信 $boundary = '---------------------------'.time(); $contentType = "Content-Type: multipart/form-data; boundary=" . $boundary; $data = ''; foreach($params as $key => $value) { $data .= "--$boundary" . CRLF; $data .= 'Content-Disposition: form-data; name=' . $key . CRLF . CRLF; $data .= $value . CRLF; } foreach($files as $key => $file) { $data .= "--$boundary" . CRLF; $data .= sprintf('Content-Disposition: form-data; name="%s"; filename="%s"%s', 'UploadFile', basename($file), CRLF); $data .= 'Content-Type: application/octet-stream'. CRLF; $data .= file_get_contents($file) . CRLF; } $data .= "--$boundary--" . CRLF; } else { //パラメータのみを送信 $contentType = 'Content-Type: application/x-www-form-urlencoded'; $data = http_build_query($params); } $headers = array( $contentType, 'Content-Length: '.strlen($data) ); $options = array('http' => array( 'method' => 'POST', 'content' => $data, 'header' => implode(CRLF, $headers) )); if (version_compare(PHP_VERSION, '5.0', '>=')){ $contents = file_get_contents($url, false, stream_context_create($options)); //PHP5. }else{ $contents = php4HttpRequest($url, $options); //PHP4. } return $contents; } ?>
こんな感じで呼び出します。
<?php $file = 'D:\tmp\test.txt'; //アップロードするテキストファイル $files = array( 'UploadFile' => $file ); $params = array( 'title' => 'test', 'hoge' => 'fuga' ); $url = 'http://www.xxxxxxx.example.com/api'; $response = httpPost($url, $params, $files); print(nl2br($response)); //結果を表示 ?>
主に以下のサイトを参考にさせていただきました。先輩諸氏に感謝。
http://www.softel.co.jp/blogs/tech/archives/2131
http://www.spencernetwork.org/memo/tips-3.php