ผมเคย blog ถึง http post app. โดย php ไปแล้วครั้งหนึ่ง ที่นี่ คราวนั้นเขียนเพราะอัดอั้นตันใจ หลงทางเสียเวลากันอยู่นาน แต่ก็มาเจอสาเหตุที่เส้นผมบังภูเขานี่เอง แต่ว่ามันก็เป็นเส้นผมที่เส้นใหญ่อยู่
เท่าที่ผมสังเกตุดู ปัญหาที่ผมเคยเจอ แบบว่า ไม่รู้จะปิด content ด้วย '\r\n' หรือ '\n' กี่ตัวกันแน่ สำหรับ Apache web  server นั้นไม่เคยเจอปัญหาเลย คือให้ปิด 2 ตัว (ตาม protocol ของ http) แต่ที่เจอปัญหาคือกับ Web server ที่ based on Java เข้าใจว่าเป็น Tomcat ที่พบว่า บางครั้งต้องปิด conent ด้วย '\r\n' หรือ '\n' เพียง 1 ตัว
แต่ก่อนผมจะเขียน http client app. ด้วยวิธีการต่างๆ ดังนี้

1. แบบ Low-level

เช่น
     $request        = "\"1.0\">...";
     $hostName       = "www.example.com";
     $apiName        = "/someServices";
     $contentType    = "text/xml";
     $extHeaderArr   = array(          "Authorization" => "Basic ".base64_encode("authen_user:authen_pwd")
         ,"User-agent"    => "PHPZealots HTTP Client"
     );

     $s  = fsockopen ($hostName, $port, $errNo, $errStr, 60);
     if (!$s)     {         echo "$errstr ($errno)
\n";
     }     else     {         fputs($s, "POST ".$apiName." HTTP/1.1\n");
         fputs($s, "Host: ".$hostName."\n");

         if($extHeaderArr && is_array($extHeaderArr))            foreach($extHeaderArr as $k=>$v)            {                fputs($s, "$k: ".$v."\n");
            }
         fputs($s, "Content-type: ".$contentType."\n");
         fputs($s, "Content-length: " . strLen($request) . "\n");
         fputs($s, "Connection: Close\n");
         fputs($s, "\n");
         fputs($s, $request."\n");
         fputs($s, "\n");
         flush($s);

         while(!feof($s))
        {            $response .= fgetc($s);
        }     }     fclose($s);
     echo $response;
?>

2. ใช้ lib สำเร็จที่ชาวบ้านเขาทำไว้

ได้ลองใช้ Advanced HTTP Client  ก็ใช้งานง่ายดีน้ะครับ เช่น
    require_once 'http.inc.php';

    $host    = "www.example.com";
    $port    = "80";
    $uri     = "/someServices";
    $request = "\"1.0\">...";

    $http_client = new http( HTTP_V11, false, array('auth_user', 'auth_pwd') );
    $http_client->host = $host;
    $http_client->port = $port;
    $responseStatus = $http_client->post_xml( $uri, $request, '' );
    $responseBody   = $http_client->get_response_body();
    $http_client->disconnect();
    unset( $http_client );

    echo $responseBody;
?>

3. ใช้ HTTP_Client ของ PEAR

อันนี้ก็ใช้ง่ายมากๆ เช่น
    require_once "HTTP/Client.php";

    $serviceUrl = "http://www.example.com:80/someServices";
    $request = "\"1.0\">...";

    $h = new HTTP_Client();
    $h->setDefaultHeader(        array(            "Content-type"  => "text/xml"           ,"Authorization" => "Basic ".base64_encode("authen_user:authen_pwd")
        )    );
    $responseStatus = $h->post($serviceUrl, $request);
    $responseArr    = $h->currentResponse();
    $responseBody   = $responseArr['body'];

    echo $responseBody;
?>
โดย ส่วนตัว ผมค่อนข้างเชื่อมั่นใน PEAR แต่ว่า app. ของผมมันก็ยังทำงานไม่ถูกต้องอยู่ดี จริงๆ อยากจะโทษเจ้าของ service ที่ผมเรียกใช้งาน ไม่รู้เขาเขียน app ยังงัย แต่โทษไปก็เท่านั้น คงจะยากที่เขาจะมาแก้ปัญหาให้เรา (หรือแค่ดู log แล้วบอกว่า ปัญหามันอยู่ตรงไหน ก็ใช้เวลานานมักๆ ไม่ได้ซักที)
ทั้ง 3 วิธี ผมเจอปัญหากับงานผมหมดเลย ก็เลยต้องมาใช้อีกวิธีต่อมา

4. ใช้ CURL, Client URL Library Functions

ใช้งานง่ายมากเช่นกัน เช่น

    $urlWithoutProtocol = "www.example.com:80/someServices";
    $request         = "";
    $isRequestHeader = false;

    $exHeaderInfoArr   = array();
    $exHeaderInfoArr[] = "Content-type: text/xml";
    $exHeaderInfoArr[] = "Authorization: "."Basic ".base64_encode("authen_user:authen_pwd");

    $ch = curl_init();
    curl_setopt($ch, CURLOPT_URL, $urlWithoutProtocol);
    curl_setopt($ch, CURLOPT_POST, 1);
    curl_setopt($ch, CURLOPT_POSTFIELDS, $request);
    curl_setopt($ch, CURLOPT_HEADER, (($isRequestHeader) ? 1 : 0));
    curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
    if( is_array($exHeaderInfo) && !empty($exHeaderInfo) )
    {        curl_setopt($ch, CURLOPT_HTTPHEADER, $exHeaderInfo);
    }
    $response = curl_exec($ch);
    curl_close($ch);

    echo $response;
?>
แล้วก็มาจบที่ CURL นี้ ใช้ได้ดี ไม่มีปัญหาเลย เข้าได้กับทุก server ไม่ต้องมากังวลเรื่องปิด content ด้วย '\r\n' หรือ '\n' กี่ตัวกันแน่ ...

เลยอยากมา blog เป็นข้อมูลไว้ให้สำหรับใครที่จะเขียน app. ในลักษณะเป็น http client ลองใช้ CURL นี้ดู จะได้ไม่เสียเวลามาแก้ bug แบบเรื่องไม่เป็นเรื่อง :P (ทั้งๆที่จริงๆ มันเป็นเรื่อง - เอ๊ะยังงัย ... งง??) หรือจริงๆ คงจะมีหลายๆทั่นที่ใช้กันอยู่แล้ว ก็ไม่ต้องงง อ่ะน้ะครับ ว่าไม roteee มันเพิ่งรู้หรือว่ะ ... :) พอดีไม่ค่อยเก่ง :D
แต่ว่า ก่อนที่จะใช้ CURL นี้ได้ ก็ต้อง config ให้ php มัน enabled lib ชุดนี้ด้วยน้ะครับ เพราะรู้สึกว่ามันจะไม่ default ไว้ให้ตั้งแต่แรก ... จะดูว่า server เราใช้ได้หรือไม่ได้ ลอง phpinfo() ดู แล้วลองค้นหาคำว่า CURL ดูว่ามีหรือเปล่า ถ้าไม่มีก็แปลว่ายังใช้ไม่ได้