-3

I have the script below written in Ruby. I was wondering is anyone can help me convert it to PHP. I know this is a big ask. I am looking to convert the ruby script to a PHP curl request.

See the link to the documentation https://www.sinch.com/docs/rest-apis/api-documentation/#applicationsignedrequest

The first code is the SAMPLE ruby script. While the second below it is what i have attempted to write in PHP on my own. Without success because i get "Invalid signature error".

require "base64"
require "openssl"
require "time"
require "net/http"
require "uri"
require "json"

to = "+4412345678"
message = "Test sms message"
key = "wwwwwwwwwxxxxxxxx" //Key as supplied by sinch.com
secret = "zzzzzzzyyyyyyyyy" // Secret as supplied by sinch.com

body = "{\"message\":\"" + message + "\"}"
timestamp = Time.now.iso8601
http_verb = "POST"
path = "/v1/sms/" + to
scheme = "Application"
content_type = "application/json"
digest = OpenSSL::Digest.new('sha256')
canonicalized_headers = "x-timestamp:" + timestamp
content_md5 = Base64.encode64(Digest::MD5.digest(body.encode("UTF-8"))).strip
string_to_sign = http_verb + "\n" + content_md5 + "\n" + content_type + "\n" + canonicalized_headers + "\n" + path        
signature = Base64.encode64(OpenSSL::HMAC.digest(digest, Base64.decode64(secret), string_to_sign.encode("UTF-8"))).strip
authorization = "Application " + key + ":" + signature

uri = URI.parse("https://messagingApi.sinch.com" + path)
http = Net::HTTP.new(uri.host, uri.port)
http.use_ssl = true
http.verify_mode = OpenSSL::SSL::VERIFY_NONE
headers = {"content-type" => "application/json", "x-timestamp" => timestamp, "authorization" => authorization}
request = Net::HTTP::Post.new(uri.request_uri)
request.initialize_http_header(headers)
request.body = body
puts JSON.parse(http.request(request).body)

Below is my script and i have no problem accepting an entirely new script. I am a super ruby rookie. Please help.

$to="+4412345678";
$text="Hello there test message";
$curl_post_data = array(
    'Message' => $text
);

$curl_post_data=json_encode($curl_post_data);

$timestamp=date("c");
$key = "wwwwwwwwwwwxxxxxxxxxxx";
$secret = "zzzzzzzzzzzzyyyyyyyyyyy";
$http_verb="POST";
$path = "/v1/sms/".$to."";
$scheme = "Application ";
$content_type = "application/json";
$canonicalized_headers = "x-timestamp:".$timestamp."";
$content_md5=base64_encode( md5($curl_post_data,true) );
$string_to_sign = array(
'http_verb' => $http_verb, 
'content_md5' => $content_md5,
'content_type' => $content_type,
'canonicalized_headers' =>$canonicalized_headers
);      
$signature = hash_hmac("sha256", $secret,json_encode($string_to_sign));
$authorization = "".$scheme."".$key.":".$signature."";

$service_url = 'https://messagingapi.sinch.com/v1/sms/'.$to.'';
$curl = curl_init($service_url);
curl_setopt($curl, CURLOPT_HTTPHEADER, array('Content-Type: application/json; charset=UTF-8', 'x-timestamp: '.$timestamp.'','authorization: '.$authorization.''));
curl_setopt($curl, CURLOPT_RETURNTRANSFER, true);
curl_setopt($curl, CURLOPT_POST, true);
curl_setopt($curl, CURLOPT_POSTFIELDS, $curl_post_data);
curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, false);
$curl_response = curl_exec($curl);
$response = json_decode($curl_response);
curl_close($curl);

var_dump($response);

?>

Any help will do please, Stackoverflow has been a useful resource whenever am stuck with something, i hope my question helps others too.

Stephen
  • 9
  • 2
  • Cut down your example code to what you actually want to convert. You'll probably just need [`hash_hmac`](http://php.net/hash_hmac). It becomes easier if you first translate it into pseudo code / a list of steps. – mario Feb 14 '15 at 11:57

2 Answers2

1

I got it to work, had to rewrite a few things. Anyway, here's a working code for anyone that might need it.

<?php

$to="+4412345678";
$text2="Test sms message from PHP";
$curl_post_data = array(
    'message' => $text2
);

$timestamp=date("c");
$key = "wwwwwwwwwwwwwxxxxxxxxxxxxxxx";
$secret ="zzzzzzzzzzzzyyyyyyyyyyyyyy";
$http_verb="POST";
$path = "/v1/sms/".$to."";
$scheme = "Application";
$content_type = "application/json";
$canonicalized_headers = "x-timestamp:".$timestamp."";

$content_md5=md5(json_encode($curl_post_data),true);

$string_to_sign ="".$http_verb."\n".$content_md5."\n".$content_type."\n".$canonicalized_headers."\n".$path."\n";    

$signature = hash_hmac("sha256", base64_encode($secret),utf8_encode($string_to_sign) true);
$signature=base64_encode($signature);
$authorization = "".$scheme."".$key.":".$signature."";


$curl_post_data=json_encode($curl_post_data);
$service_url = 'https://messagingapi.sinch.com/v1/sms/'.$to.'';
$curl = curl_init($service_url);
curl_setopt($curl, CURLOPT_HTTPHEADER, array('Content-Type: application/json; charset=UTF-8','x-timestamp:'.$timestamp.'','authorization:'.$authorization.''));
curl_setopt($curl, CURLOPT_RETURNTRANSFER, true);
curl_setopt($curl, CURLOPT_POST, true);
curl_setopt($curl, CURLOPT_POSTFIELDS, $curl_post_data);
curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, false);
$curl_response = curl_exec($curl);
$response = json_decode($curl_response);
curl_close($curl);
var_dump($response);
?>
Stephen
  • 9
  • 2
0

Completely working code. Also, thanks to 'Stephen' for basical porting from Ruby to PHP. It saves me a lot of time. Some notes:

  • Key should be copied from apps menu of sinch account as is (without any conversion)
  • String to sign shouldn't contain new line at the end. Also, please check every changes by setting default values from commented code.
  • In the PHP hash_hmac function cody should be defined before secret (in Ruby arguments should be defined in other order)
  • If actual headers will contain charset definition - string_to_sign should contain it too. I have deleted them at all.

    $key     = 'key';
    $secret  = 'secret';
    $message = 'your message';
    $phone   = '+000000000000';
    
    $body = json_encode(array('message'=>$message));
    $timestamp = date("c");
    
    // {{{ test values for checking code (from docs)
    /*
        $phone="+46700000000";
        $key = "5F5C418A0F914BBC8234A9BF5EDDAD97";
        $secret ="JViE5vDor0Sw3WllZka15Q==";
        $timestamp='2014-06-04T13:41:58Z';
        $body = '{"message":"Hello world"}';
    */
    // result:
    //      content-md5 should be 'jANzQ+rgAHyf1MWQFSwvYw=='
    //      signature should be 'qDXMwzfaxCRS849c/2R0hg0nphgdHciTo7OdM6MsdnM='
    // }}}
    
    $path                  = "/v1/sms/" . $phone;
    $content_type          = "application/json";
    $canonicalized_headers = "x-timestamp:" . $timestamp;
    
    $content_md5 = base64_encode( md5( utf8_encode($body), true ));
    
    $string_to_sign =
        "POST\n".
        $content_md5."\n".
        $content_type."\n".
        $canonicalized_headers."\n".
        $path;
    
    $signature = base64_encode(hash_hmac("sha256", utf8_encode($string_to_sign), base64_decode($secret), true));
    $authorization = "Application " . $key . ":" . $signature;
    
    $curl_post_data=json_encode($curl_post_data);
    $service_url = 'https://messagingapi.sinch.com'.$path;
    $curl = curl_init($service_url);
    curl_setopt($curl, CURLOPT_HTTPHEADER, array(
        'content-type: '.$content_type,
        'x-timestamp:' . $timestamp,
        'authorization:' . $authorization
    ));
    curl_setopt($curl, CURLOPT_RETURNTRANSFER, true);
    curl_setopt($curl, CURLOPT_POST, true);
    curl_setopt($curl, CURLOPT_POSTFIELDS, $curl_post_data);
    curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, false);
    $curl_response = curl_exec($curl);
    // @todo: checking response / working with results
    curl_close($curl);