<?php
/**
 * @Desc   : 微信api Request 
 *           php curl http 传输文件和数据
 *           需要安装curl扩展
 * @Author : BraveDu<duchaoqun@360.cn>
 */
class WeixinApiRequest
{
    const GET  = 'GET';
    const POST = 'POST';
    /** 
     * Contains the last HTTP status code returned.
     */
    public static $http_code;
    /** 
     * Contains the last HTTP headers returned.
     */
    public static $http_info;
    /** 
     * http error code
     */
    public static $http_error_code = 0;
    /** 
     * http error
     */
    public static $http_error = ''; 
    /** 
     * Contains the last HTTP response.
     */
    public static $response;
    /** 
     * Contains the last API call.
     */
    public static $url;
    /** 
     * Contains the last HTTP params.
     */
    public static $params;
    /** 
     * Set timeout default.
     */
    public static $timeout = 30; 
    /** 
     * Set connect timeout. 
     */
    public static $connecttimeout = 30;
    /**
     * Verify SSL Cert.
     */
    public static $ssl_verifypeer = false;
    /**
     * Respons format.
     */
    public static $format = 'json';
    /**
     * Decode returned json data.
     */
    public static $decode_json = TRUE;
    /**
     * Set the useragnet.
     */
    public static $useragent = 'WeiXinApi SDK v0.1';
    /**
     * print the debug info
     */
    public static $debug = true;
    /**
     * boundary of multipart
     */
    public static $boundary = '';
    /**
     * GET wrappwer for apiRequest.
     * @return mixed
     */
    public static function get($url, $params = array())
    {
        $response = self::_request($url, self::GET, $params);
        if(self::$http_code!=200) return array('curl_http_code' => self::$http_code );
        if (self::$format === 'json' && self::$decode_json) {
            $result = json_decode($response, true);
            if (! $result) {
                $response = preg_replace("/[\\x00-\\x08\\x0b-\\x0c\\x0e-\\x1f]/", '', $response);
                $result = json_decode($response, true);
            }
            return $result;
        }
        return $response;
     }
    
    /**
     * POST wreapper for apiRequest.
     *
     * @return mixed
     */
    public static function post($url, $params = array(), $multi = false, $json = true)
    {
        $timeout = 0;
        if ('video' == @$params['msgtype']) {
            $timeout = 300;
        }
        if (true == $json) {
            $params = is_array($params) ? urldecode(json_encode($params)) : $params;
        }
        $response = self::_request($url, self::POST, $params, $multi, $timeout);
        if(self::$http_code!=200) return array('curl_http_code' => self::$http_code );
        if (self::$format === 'json' && self::$decode_json) {
            $result = json_decode($response, true);
            if (! $result) {
                $response = preg_replace("/[\\x00-\\x08\\x0b-\\x0c\\x0e-\\x1f]/", '', $response);
                $result = json_decode($response, true);
            }
            return $result;
        }
        return $response;
    }

    /**
     * Format and sign an API request
     *
     * @return string
     */
    private static function _request($url, $method, $params, $multi = false, $timeout = 0)
    {
        self::$url = $url;
        self::$params = $params;
        if (self::GET == $method) {
            $url = $url . (strpos($url, '?') ? '&' : '?') . (is_array($params) ? http_build_query($params) : $params);
            $response = self::_http($url, self::GET);
        } else {
            $headers = array();
            if (! $multi /*  && (is_array($params) || is_object($params)) */ ) {
                //$body = http_build_query($params);
                $body = $params;
            } else {
                //TODO:目前没有使用
                $body = self::_buildHttpQueryMulti($params);
                $headers[] = "Content-Type: multipart/form-data; boundary=" . self::$boundary;
            }
            $response = self::_http($url, self::POST, $body, $headers, $timeout);
        }

        return self::_parseResponse($response);
    }

    /**
     * 解析结果集
     *
     * 把message_id原数字用正则转换为字符串
     *
     */
    private static function _parseResponse($response)
    {
        return preg_replace('/\"message_id\":( )*([\d]{13,})/', "\"message_id\": \"$2\"", $response);
    }

    /**
     * Make an HTTP request
     *
     * @return string API results
     ''
     */
private static function _http($url, $method, $postfields = NULL, $headers = array(), $timeout = 0)
    {
        $timeout = $timeout ? $timeout : self::$timeout;
        self::$http_info = array();
        $ci = curl_init();
        /* Curl settings */
        curl_setopt($ci, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_0);
        curl_setopt($ci, CURLOPT_USERAGENT, self::$useragent);
        curl_setopt($ci, CURLOPT_CONNECTTIMEOUT, self::$connecttimeout);
        curl_setopt($ci, CURLOPT_TIMEOUT, $timeout);
        curl_setopt($ci, CURLOPT_RETURNTRANSFER, TRUE);
        curl_setopt($ci, CURLOPT_ENCODING, "");

        curl_setopt($ci, CURLOPT_SSL_VERIFYPEER, self::$ssl_verifypeer);
        curl_setopt($ci, CURLOPT_SSL_VERIFYHOST, (self::$ssl_verifypeer == true) ? 2 : false);

        curl_setopt($ci, CURLOPT_HEADERFUNCTION, 'WeiXinApiRequest::_getHeader');
        curl_setopt($ci, CURLOPT_HEADER, FALSE);

        if (self::POST == $method) {
            curl_setopt($ci, CURLOPT_POST, TRUE);
            if (!empty($postfields)) {
                curl_setopt($ci, CURLOPT_POSTFIELDS, $postfields);
                //self::$postdata = $postfields;
            }
        }

        curl_setopt($ci, CURLOPT_URL, $url );
        curl_setopt($ci, CURLOPT_HTTPHEADER, $headers );
        curl_setopt($ci, CURLINFO_HEADER_OUT, TRUE );

        self::$response = $response = curl_exec($ci);
        self::$http_code = curl_getinfo($ci, CURLINFO_HTTP_CODE);
        self::$http_info = array_merge(self::$http_info, curl_getinfo($ci));
        self::$http_error_code = curl_errno($ci);
        self::$http_error = curl_error($ci);
        if(!self::$response){
             Logger::writeCrulExecLog("url:" . $url . "\tpost:" . $postfields . "\t" . curl_error($ci));
        }
        curl_close($ci);
        return $response;
    }

   /**
     * Get the header info to store.
     *
     * @return int
     ''
     */
    private static function _getHeader($ch, $header)
    {
        $i = strpos($header, ':');
        if (!empty($i)) {
            $key = str_replace('-', '_', strtolower(substr($header, 0, $i)));
            $value = trim(substr($header, $i + 2));
            //self::$http_header[$key] = $value;
        }
        return strlen($header);
    }

    /**
    *  @Deac : 组合http信息 
    */
    private static function _buildHttpQueryMulti($params)
    {
        if (!$params) return '';

        uksort($params, 'strcmp');

        $pairs = array();

        self::$boundary = $boundary = uniqid('----------');

        $MPboundary = '--'.$boundary;
        $endMPboundary = $MPboundary. '--';
        $multipartbody = '';

        foreach ($params as $param => $value) {

            if( 'media' == $param && $value{0} == '@' ) {
                $url = ltrim( $value, '@' );
                $content = file_get_contents( $url );
                $array = explode( '?', basename( $url ) );
                $filename = $array[0];

                $multipartbody .= $MPboundary . "\r\n";
                $multipartbody .= 'Content-Disposition: form-data; name="' . $param . '"; filename="' . $filename . '"'. "\r\n";
                $multipartbody .= "Content-Type: application/octet-stream\r\n\r\n";
                $multipartbody .= $content. "\r\n";
            } else {
                $multipartbody .= $MPboundary . "\r\n";
                $multipartbody .= 'Content-Disposition: form-data; name="' . $param . "\"\r\n\r\n";
                $multipartbody .= $value."\r\n";
            }

        }

        $multipartbody .= $endMPboundary;
        return $multipartbody;
    }

}