Archive for December, 2012

0138 | function get url ผ่าน https ใช้แทน curl

Monday, December 17th, 2012 Posted in Misc | No Comments »

วันก่อนเจอบั๊กระหว่าง curl + openssl + centos 6 นิดหน่อย
ที่ทำให้ curl และ app ทุกอย่างที่ใช้ libcurl ต่อไปหา server ที่เป็น https บางตัวบนบางเงื่อนไขไม่ได้
หาข้อมูลไปก็พบว่าต้องไปแก้ที่ฝั่ง server (จะบ้าเรอะ server ชาวบ้าน) ไม่ก็ต้องแก้ code ใหม่ให้ใช้ library อย่างอื่นแทน ก็เลยเกิดมาเป็น function นี้ครับ

มี requirement นิดหน่อยคือ PHP 5.3.4 ขึ้นไป และ เปิด allow_url_fopen ไว้ใน php.ini

feature
=> custom header ได้
=> รองรับ cookie โดยอัตโนมัติ
=> method ได้ทั้ง get และ post (รวมถึง post แบบใส่ data ด้วย)
=> url ได้ทั้ง http และ https (มี validate url เผื่อไว้ด้วย)
=> บังคับ verify ssl certificate ที่ฝั่งปลายทางด้วยว่า cert ถูกต้อง (file get content ปกติจะไม่ verify)
=> ใช้ ca file ของ OS (แก้ได้)

<?php
function httpquery($url, $method = 'GET', $headers = array(), $body = '', $returnheader = false, $followlocation = true){
    global $cookies;
    $reqinfo = parse_url($url);
    if (empty($reqinfo['host']) || empty($reqinfo['path'])) return false;
    if (empty($reqinfo['scheme'])) $reqinfo['scheme'] = 'http';
    if ($reqinfo['scheme'] != 'http' && $reqinfo['scheme'] != 'https') {
        trigger_error("Unsupported scheme '".$reqinfo['scheme']."'");
        return false;
    }
    if (empty($reqinfo['port'])) {
        if ($reqinfo['scheme'] == 'https')
            $reqinfo['port'] = 443;
        else
            $reqinfo['port'] = 80;
    }
 
    $headers['User-Agent'] = (!isset($headers['User-Agent']) ? 'Mozilla/4.0 (compatible; icez.net http client)' : $headers['User-Agent']);
    $headers['Host'] = $reqinfo['host'];
    $headers['Accept'] = '*/*';
 
 
    $cdata = array();
    foreach($cookies as $ckey => $cval) {
        $cdata[] = $ckey.'='.$cval;
    }
    $headers['Cookie'] = implode('; ', $cdata); // http_build_query($cookies);
    unset($cdata);
 
    if ($method == 'POST') {
        $headers['Content-Type'] = (isset($headers['Content-Type']) ? $headers['Content-Type'] : 'application/x-www-form-urlencoded');
    }
 
    $headerstring = '';
    foreach ($headers as $header => $content) {
        $headerstring .= $header.': '.$content."\r\n";
    }
 
    $reqpath = $reqinfo['path'].(isset($reqinfo['query']) ? '?'.$reqinfo['query'] : '');
 
    $opts = array('ssl' => array(
            'verify_peer' => true,
            'cafile' => '/etc/pki/tls/certs/ca-bundle.crt'
        ),
        'http' => array(
            'method' => $method,
            'follow_location' => ($followlocation ? 1 : 0),
            'ignore_errors' => true,
            'timeout' => 15,
            'header' => $headerstring
        )
    );
    if (!empty($body)) $opts['http']['content'] = $body;
    $context = stream_context_create($opts);
 
    $stream = fopen($url, 'r', false, $context);
    $meta = stream_get_meta_data($stream);
    $content = stream_get_contents($stream);
    if (!is_array($meta['wrapper_data'])) {
        trigger_error("Invalid HTTP Header Response");
    }
    $header = '';
 
    foreach($meta['wrapper_data'] as $header) {
        if (strpos($header, ':') !== false) {
            $line = explode(':', $header, 2);
            if (strtolower($line[0]) == 'set-cookie') {
                $cookie = explode(';', trim($line[1]), 2);
                if (strpos($cookie[0], '=') !== false) {
                    //valid cookie
                    $cdata = explode('=', $cookie[0], 2);
                    $cookies[$cdata[0]] = $cdata[1];
                }
            }
        }
    }
    fclose($stream);
    if ($returnheader) $content = implode("\r\n", $meta['wrapper_data'])."\r\n\r\n".$content;
    return $content;
}
?>