Web・IT うんたらら

業務系とWeb系の狭間でIT業界を彷徨いながら備忘録と足跡を残していきます

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