ผมเคย 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. ด้วยวิธีการต่างๆ ดังนี้
ทั้ง 3 วิธี ผมเจอปัญหากับงานผมหมดเลย ก็เลยต้องมาใช้อีกวิธีต่อมา
เลยอยากมา blog เป็นข้อมูลไว้ให้สำหรับใครที่จะเขียน app. ในลักษณะเป็น http client ลองใช้ CURL นี้ดู จะได้ไม่เสียเวลามาแก้ bug แบบเรื่องไม่เป็นเรื่อง :P (ทั้งๆที่จริงๆ มันเป็นเรื่อง - เอ๊ะยังงัย ... งง??) หรือจริงๆ คงจะมีหลายๆทั่นที่ใช้กันอยู่แล้ว ก็ไม่ต้องงง อ่ะน้ะครับ ว่าไม roteee มันเพิ่งรู้หรือว่ะ ... :) พอดีไม่ค่อยเก่ง :D
แต่ว่า ก่อนที่จะใช้ CURL นี้ได้ ก็ต้อง config ให้ php มัน enabled lib ชุดนี้ด้วยน้ะครับ เพราะรู้สึกว่ามันจะไม่ default ไว้ให้ตั้งแต่แรก ... จะดูว่า server เราใช้ได้หรือไม่ได้ ลอง phpinfo() ดู แล้วลองค้นหาคำว่า CURL ดูว่ามีหรือเปล่า ถ้าไม่มีก็แปลว่ายังใช้ไม่ได้
เท่าที่ผมสังเกตุดู ปัญหาที่ผมเคยเจอ แบบว่า ไม่รู้จะปิด 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\">โดย ส่วนตัว ผมค่อนข้างเชื่อมั่นใน PEAR แต่ว่า app. ของผมมันก็ยังทำงานไม่ถูกต้องอยู่ดี จริงๆ อยากจะโทษเจ้าของ service ที่ผมเรียกใช้งาน ไม่รู้เขาเขียน app ยังงัย แต่โทษไปก็เท่านั้น คงจะยากที่เขาจะมาแก้ปัญหาให้เรา (หรือแค่ดู log แล้วบอกว่า ปัญหามันอยู่ตรงไหน ก็ใช้เวลานานมักๆ ไม่ได้ซักที)... "; $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; ?>
ทั้ง 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 ดูว่ามีหรือเปล่า ถ้าไม่มีก็แปลว่ายังใช้ไม่ได้
- roteee's blog
- Login to post comments
- 5487 reads
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER,0);
เพิ่มเข้าไปถึงจะใช้ได้ แต่แบบนี้จะมีผลต่อ security มั๊ยคะ เพราะปานนี่ต้องใช้กับระบบlogin การซื้อขายหน่ะค่ะ
แล้วจริงๆถ้าใช้งานกับ https ปกติถ้าไม่ใส่code ตัวนี้มันใช้ได้มั๊ยคะ หรือเพราะ url ที่เป็น https นี้มันเซ็ต ssl ไว้ไม่ดี ขึ้นpopup alert เตือนทุกครั้งที่เปิดเรยค่ะ
แต่ขอแสดงความคิดเห็นกับคำถามของ parnni แบบบ้านๆ ดังนี้:
>> พี่โรตีคะ แล้วถ้าจะใช้งานกับ https หล่ะคะ เคยลองใช้แล้วมันใช้ไม่ได้ เลยลองใส่
>> curl_setopt($ch, CURLOPT_SSL_VERIFYPEER,0);
>> เพิ่มเข้าไปถึงจะใช้ได้ แต่แบบนี้จะมีผลต่อ security มั๊ยคะ
>> เพราะปานนี่ต้องใช้กับระบบlogin การซื้อขายหน่ะค่ะ
เท่าที่ไป google ดู ในการเซต CURLOPT_SSL_VERIFYPEER ให้เป็น 0 นั้น จะเป็นการ bypass หรือการข้ามขั้นตอนการ verify ไป คือ ไม่ต้องทำการ Verify กับทาง server ที่เรา request ไป แต่การรับส่งข้อมูลระหว่างกันนั้น ยังมีการเข้ารหัสในการเชื่อมต่อกันด้วย ssl เหมือนเดิม แต่เราจะไม่รู้ ว่าเรากับลังเชื่อมต่ออยู่กับใครเท่านั้น (อ้างอิงที่นี่)
ซึ่งถ้าถามว่า จะมีผลต่อ security มั้ยนี่ ในแง่ของการป้องกันชาวบ้านมาดักดูข้อมูลระหว่างทาง ไม่น่าจะมีผลอะไร แต่ในแง่ของการยืนยันว่าเรากำลังคุยกับใครอยู่นั้น ก็คงจะมีผลบ้าง แต่ถ้าไม่ได้กังวล หรือ server ที่เราคุยไปนั้นเชื่อถือได้ ก็คงจะไม่เป็นอะไร (อันนี้ความคิดเห็นส่วนตัวน้ะคับ)
>> แล้วจริงๆถ้าใช้งานกับ https ปกติถ้าไม่ใส่code ตัวนี้มันใช้ได้มั๊ยคะ
CURLOPT_SSL_VERIFYPEER โดย default จะมีค่าเป็น 1 หรือ TRUE อยู่ (อ้างอิงที่นี่) เพราะฉะนั้นถ้าไม่ใส่ code นี้เข้าไปเพื่อเซตให้มันเป็น 0 หรือ FALSE ก็ต้องใส่ code เพื่อเซต CURLOPT_CAFILE หรือ CURLOPT_CAINFO เพื่อใส่ข้อมูลการ verify ถ้าไม่อย่างนั้น ก็คงจะไม่ผ่าน
>> หรือเพราะ url ที่เป็น https นี้มันเซ็ต ssl ไว้ไม่ดี ขึ้นpopup alert เตือนทุกครั้งที่เปิดเรยค่ะ
เท่าที่ทราบมา มันไม่เกี่ยวกับการเซต ssl ไว้ไม่ดีหรอกครับ แต่ที่มันขึ้น popup alert เข้าใจว่าเขาเซตโดยใช้ OpenSSL ซึ่งเป็นของฟรี ไม่เสียค่า licene ก็จะขึ้น popup alert อย่างนั้นแหล่ะ ถ้าไม่อยากให้มันขึ้น popup ต้องใช้ SSL แบบเสียตังค์ :)
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
เซือในสิ่งที่เฮ็ด เฮ็ดในสิ่งที่เซือ...
ผมเคยลองเรียกแบบย้อนกลับเข้าหาโดเมนหลัก แค่นั้น
บางโฮสถึงกับนิ่งไปเลย
ผมเลยใช้ fsockopen .. ฉิวเลย
ถ้าใครคิดจะใช้ fsockopen ผมมีข้อแนะนำ 2 ข้อ
1. ถ้าลำบากเรื่องการเขียน GET POST อย่างไรถึงจะเหมาะ
หา Sniffer มาดัก Browser เลยครับ ก็อบ/แก้/วาง อิๆ
2. ระวังเรื่อง Connection ด้วย ผมเคยเผลอก็อบ keep-alive มา
ถึงกับนิ่งเลย เลยต้องมาใช้ Connection: Close
สคริปถึงจะทำงานต่อครับ
ถ้าจะใช้แบบ low-level แบบนี้ นักพัฒนาก็ต้องมีความรู้เยอะหน่อย รู้ว่าอะไรไปยังงัย มายังงัย ซึ่งจะทำให้เราสามารถควบคุมทุกอย่างไว้ได้ แต่ ... อย่างหนึ่งที่น่าคำนึงต่อหน่อย (อย่างปัญหาที่ผมพบอยู่บ่อยๆ) คือว่า หลังๆ มาชักเริ่มไม่แน่ใจว่า standard มันเป็นยังงัยกันแน่ แล้วก็ถ้าเราใช้ tools เข้ามาช่วยเหมือนที่คุณ EThaiZone แนะนำ เช่น Sniffer อย่างนี้ก็ดีน้ะคับ แต่ว่า ถ้าเกิดเราทำงานกับ server หลายๆ ที่เช่น ต้องเขียน app. คุยกับ operator ซึ่งบ้านเรามีอยู่ 3 เจ้าหลัก คือ AIS, DTAC และ TRUEMOVE (อันนี้บ่นจากประสบการณ์ตรง อิอิ) ถ้าทั้งสามเจ้านี้ ต้องเขียน post ไปคนละแบบ อย่างน้อยๆ เราก็ต้องมี 3 เงื่อนไข และทั้งนี้ทั้งนั้น ถ้าทั่นๆ ทั้ง 3 operator นี้เปลี่ยนระบบ หรือ upgrade ระบบ เราก็ต้องมานั่งทดลองกันใหม่ ในบางครั้ง ผมจึงเลือกใช้ tools หรือ lib ที่มีออกมาเช่น curl นี้ ซึ่งถ้าเทียบกับความเร็วที่ช้าลง แต่จะได้ความไวในการพัฒนามาแทน ผมว่ามันก็คุ้มน้ะครับ
แต่ทั้งนี้ทั้งนั้น ก็คงจะ แล้วแต่ลักษณะของงานเป็นหลัก ว่าอะไรควร อะไรไม่ควร :)
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
เซือในสิ่งที่เฮ็ด เฮ็ดในสิ่งที่เซือ...
สำหรับการรับข้อมูล เช่นข้อมูล xml ซึ่งปกติจะถูกส่งมาด้วย POST สามารถรับได้ด้วยตัวแปล HTTP_POST_RAW_DATA แต่ทางผู้ส่ง ต้องระบุ content-type มาด้วย และต้องไม่เป็น mulitpart/form-data
หรืออีกวิธี ลองใช้
ob_start(); readfile("php://input"); $rawData = ob_get_clean(); ?>
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
เซือในสิ่งที่เฮ็ด เฮ็ดในสิ่งที่เซือ...
ตัว app เขียนแบบนี้ค่ะ
$urlWithProtocol = "http://ip:port/app";
$request = "";
$isRequestHeader = false;
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $urlWithProtocol);
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);
$response = curl_exec($ch);
curl_close($ch);
print_r($response);
ซึ่งเมื่อรันแล้ว ไม่แสดงค่าอะไรเลยน่ะค่ะ เป็นหน้าจอว่างๆ..
สำหรับตัว $urlWithProtocol ลองใส่ 2 url ค่ะ urlนึงแสดงผล อีกตัวไม่แสดงผล เลยงงว่า เกิดจากอะไรค่ะ
>> ขอสอบถามเพิ่มเติมค่ะสำหรับการรับข้อมูล เช่นข้อมูล xml ซึ่งปกติจะถูกส่งมาด้วย POST
ปกติแล้ว ฝั่ง server ที่ response ข้อมูลมาให้ เช่นข้อมูล xml ที่พูดถึงกันอยู่นี้ ผมเรียกว่า "response ข้อมูลมา" เพราะว่า ทาง server เขาจะไม่ได้ "ส่งมาด้วย POST" คือเขาแค่ response หรือ return ข้อมูลกลับมา เพื่อเป็นการตอบสนอง request ของ client
ถ้าจะพูดให้ถูก น่าจะต้องบอกว่า:
>> ขอสอบถามเพิ่มเติมค่ะสำหรับการรับข้อมูล เช่นข้อมูล xml ซึ่งทางผู้ให้บริการ หรือ server จะรับ request ด้วย POST method และจะ response ข้อมูลกลับมา ในรูปแบบของ xml
ตอบคำถามต่อ :)
จากข้อมูลที่ให้มานี้ ขอแยกออกเป็น 3 ประเด็น
[1] >> $request = "";
ตรงนี้ ไม่รู้ว่าเป็น request ที่ถูกต้องหรือไม่ อย่างไร เช่น ทาง server ยอมให้ request โดยที่ไม่ส่งข้อมูลอะไรไป ได้หรือไม่ อย่างไร แต่ทั้งนี้ ทั้งนั้น server ที่ดี ก็ควรจะ ตอบสนองต่อ request ที่มีเข้ามา ไม่ว่าข้อมูลจะถูกต้องตาม protocol ที่ server กำหนดหรือไม่ก็ตาม
[2] >> ซึ่งเมื่อรันแล้ว ไม่แสดงค่าอะไรเลยน่ะค่ะ เป็นหน้าจอว่างๆ..
การที่หน้าจอว่างๆ อาจจะเกิดจาก response ที่ได้รับมาเป็น xml และเป็น tag ที่ browser ไม่รู้จัก ก็เลยไม่ได้แสดงผลออกมาก็ได้น้ะครับ เช่น เขาอาจจะ response กลับมาเป็น
[3] >> สำหรับตัว $urlWithProtocol ลองใส่ 2 url ค่ะ urlนึงแสดงผล อีกตัวไม่แสดงผล เลยงงว่า เกิดจากอะไรค่ะ
อันนี้ ก็คงตอบอะไรไม่ได้มาก เพราะไม่รู้ protocol ของทั้ง 2 urls นี้ ว่าเหมือน หรือแตกต่างกันยังงัย แต่ถ้าจะให้เดา ก็คงเป็นเรื่องของการจัดการ request ที่เข้ามา เช่น url แรกที่แสดงผล อาจจะจัดการ request และ response ดีกว่า จึงแสดงผล แต่อีก url นั้นไม่
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
เซือในสิ่งที่เฮ็ด เฮ็ดในสิ่งที่เซือ...
$request = "";
นี่แหล่ะ ว่าทาง server เค้ายอมให้ request ด้วยข้อมูลว่างๆ ได้หรือไม่ อย่างไร
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
เซือในสิ่งที่เฮ็ด เฮ็ดในสิ่งที่เซือ...
ถ้าเข้าใจไม่ผิด มันคือ ตัว bot หรือ engine ที่จะไปดูดเอา web document (หรือ html document หรือ xhtml document หรือ rss document หรืออื่นๆ) มาจาก web site ต่างๆ แล้วเอา web document มาประมวลผล อาจจะเอามาจัด indexing สำหรับทำ search engine หรืออื่นๆ ใช่ป่ะคับ ??
ถ้าใช่ ...
การนำ curl ใน php มาใช้ในการทำ web spider นั้น สามารถนำมาช่วยได้ ในขั้นตอนการ ดูด (get, fetch แล้วแต่จะเรียก แต่ไม่รู้ว่าศัพท์ทางการเขาเรียกอะไร) web document มา ซึ่งก็สะดวกมากด้วย
แต่ขั้นตอนการประมวลผล web document นั้นคิดว่า curl ไม่มี function อะไรที่จะมาช่วย (เพราะมันถูกสร้างขึ้นมาเป็น web client ไม่ใช่ string processor) เราคงจะต้องเขียนโปรแกรม เพื่อมาประมวลผล และจัดการต่อเองครับ
สำหรับตัวอย่าง ของการเอา curl มาทำแบบนี้ ผมไม่มีเหมือนกัน แต่ว่า ถ้าจะเอามันมาทำหน้าที่ดูด web document ตัวอย่างข้างต้นนี้ ก็น่าจะใช้ได้น้ะคับ
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
เซือในสิ่งที่เฮ็ด เฮ็ดในสิ่งที่เซือ...
$urlWithoutProtocol = "www.example.com:80/someServices"; $ch = curl_init(); curl_setopt($ch, CURLOPT_URL, $urlWithoutProtocol); curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1); $response = curl_exec($ch); curl_close($ch); echo $response; ?>