hmac签名在python和php中不同

I need little help to figure out issue with php hash_hmac. I am converting a existing python script into php that call an api for process data. Python script is working fine.

There is few similar question out there, one of them is HMAC value not consistent in Python and PHP but it dosen't help me. I have tried many way but all time i am getting error your signature doesn't match

Here is my php code

$session_id = xxxxxxxxxxxxxxxxxxxxx;
$accessKey = xxxxxxxxxxxxxxxxxxxxxx;
$url = '/APIENDPOINT?action=mobileAccess&autoJoin=true';
$timestamp = date('r');
$body = '{"expireTime": "20160322T2359", "doorOperations": [{"operation": "guest", "doors": ["103"]}], "endPointID": "enpointID", "format": "rfid48"}';

$params["action"] = "mobileAccess";
$params["override"] = "true";

$canonicalized_query = array();
foreach ($params as $param => $value) {
    $param = str_replace("%7E", "~", rawurlencode($param));
    $value = str_replace("%7E", "~", rawurlencode($value));
    $canonicalized_query[] = $param . "=" . $value;
}
ksort($canonicalized_query);
$canonicalized_query = implode("&", $canonicalized_query);

$string_to_sign = "POST
";
$string_to_sign .= base64_encode(md5($body, true))."
";
$string_to_sign .="application/json;charset=utf-8
";
$string_to_sign .= $timestamp."
";
$string_to_sign .= 'APIEDNPOINT?'.$canonicalized_query;
echo strlen($string_to_sign);
$header=array(
    'Date: '.$timestamp,
    'Content-Type: application/json;charset=utf-8', 
    'Content-MD5: '.base64_encode(md5($body, true)),    
    'Authorization: Basic '.$session_id.':'.base64_encode(hash_hmac('sha1', iconv(mb_detect_encoding($string_to_sign, mb_detect_order(), true), "UTF-8", $string_to_sign), iconv(mb_detect_encoding($accessKey, mb_detect_order(), true), "UTF-8", $accessKey), true))

Here is working python code

url=self._basepath+url
        headers={}

        if body:
            # Encode request body as JSON
            body=json.dumps(body)
            headers['Content-Type']='application/json;charset=utf-8'

            # Compute MD5 digest
            h=hashlib.new('md5')
            h.update(body)
            headers['Content-MD5']=base64.b64encode(h.digest())

        # Format the date correctly, after applying the client/server skew
        headers['Date']=email.Utils.formatdate(time()+self._time_skew)

        if sign and 'id' in self._session:
            # Canonicalize the URL
            (canonicalized_resource,q,query_string)=url.partition('?')
            canonicalized_resource+=q+'&'.join(sorted(query_string.split('&')))

            # Build the string to be signed
            string_to_sign=method+"
"
            if 'Content-MD5' in headers:
                string_to_sign+=headers['Content-MD5']
            string_to_sign+="
"
            if 'Content-Type' in headers:
                string_to_sign+=headers['Content-Type']
            string_to_sign+="
"+headers['Date']+"
"+canonicalized_resource

            # Create the signature
            h=hmac.new(self._session['accessKey'].encode('utf-8'),\
                           string_to_sign.encode('utf-8'),hashlib.sha1)
            headers['Authorization']='Basic %s:%s'\
                %(self._session['id'],base64.b64encode(h.digest()))

call for endpoint in python

ws.send_request("POST","APIENDPOINT",\
                                         {"doorOperations": [{"doors": ["101"],"operation": "guest"}],"expireTime": "20150522T2359","format": "rfid48","endPointID":"endpointid"})

I have checked body content md5 & string_to_sign output is same for both script.