locked
PHP related SOAP API issues RRS feed

  • Question

  • We were using the free offering, but have recently purchased Translator API access through the Azure marketplace.

    I'm following the guide to obtain an access token (http://msdn.microsoft.com/en-us/library/hh454950.aspx) and I keep getting the following error:

     

    Error: invalid_request
    Error description: ACS90004: The request contains 1 tokens separated by '=' instead of a single key value pair.
    Trace ID: ab8b2358-4df3-429a-8e56-3b79a72e7863
    Timestamp: 2011-09-16 12:35:59Z

    I'm using PHP in this instance, but have pretty emulated the C# example in the document perfectly. Can anyone help with this?

    Many thanks,
    Dave 

     

    Edit: changed thread title to fit content
    • Edited by G4M Thursday, September 22, 2011 9:49 AM
    Friday, September 16, 2011 12:45 PM

Answers

  • Re: Can someone tell me how to use my Access Token in SOAP API calls?

    Here is an example using SOAP with the token as the "Authorization" header using C# (from doc :http://msdn.microsoft.com/en-us/library/ff512387.aspx)

    The following code creates a Http Header with header name "Authorization" and header value with the fomrat "Bearer " + the access token field from the OAuth authentication.  Note that you need to take the access token part of the original token and also need to add "Bearer " as the prefix per OAuth spec.

    And then it addes the Http header to service client (if you are using Java or other languages, there are equivalent ways to add the Http header).

    httpRequestProperty.Headers.Add("Authorization", headerValue);

    Later, it uses "" as the value of the appId field to communicate with the API.

    Please paste your code if you need us to debug the problem. Thanks.

                     // Add the http header

                    HttpRequestMessageProperty httpRequestProperty = new HttpRequestMessageProperty();

                    httpRequestProperty.Method = "POST";

                    httpRequestProperty.Headers.Add("Authorization", headerValue);

     

                    // Call Translator with the header

                    ServiceReference.LanguageServiceClient myClient = new ServiceReference.LanguageServiceClient();

                    using (OperationContextScope scope = new OperationContextScope(myClient.InnerChannel))

                    {

                        OperationContext.Current.OutgoingMessageProperties[HttpRequestMessageProperty.Name] = httpRequestProperty;

                        textBox1.Text = myClient.Translate("", "My first translation.", "en", "fr", null, null);

                    }



    • Edited by Colin Yu Wednesday, September 21, 2011 8:21 PM
    • Marked as answer by Vikram Dendi Wednesday, September 21, 2011 8:24 PM
    Wednesday, September 21, 2011 8:14 PM

All replies

  • Already answered my question here, so I need not wait for a response. However, in case it's of any use to anybody, here is (roughly) what I'm using to retrieve the token:

     

    <?php
    $str_client_id = 'XXX';
    $str_client_secret = '...';
    
    $obj_connection = curl_init();
    $arr_query_bits = array (
       'grant_type' => 'client_credentials',
       'client_id' => $str_client_id,
       'client_secret' => $str_client_secret,
       'scope' => 'http://api.microsofttranslator.com'
    );
    
    $str_query = http_build_query($arr_query_bits);
    
    $str_url = "https://datamarket.accesscontrol.windows.net/v2/OAuth2-13";
    
    curl_setopt($obj_connection, CURLOPT_URL, $str_url);
    curl_setopt($obj_connection, CURLOPT_HEADER, 0);
    curl_setopt($obj_connection, CURLOPT_FOLLOWLOCATION, 1);
    curl_setopt($obj_connection, CURLOPT_RETURNTRANSFER, 1);
    curl_setopt($obj_connection, CURLOPT_POSTFIELDS, $str_query);
    curl_setopt($obj_connection, CURLOPT_POST, TRUE);
    
    $str_result = curl_exec($obj_connection);
    $arr_curl_info = curl_getinfo($obj_connection);
    $obj_response = json_decode($str_result);
    
    if (is_null($obj_response)){
       throw new Exception("Response wasn't valid JSON - {$str_response}");
    }
    
    if (isset($obj_response->error)){
       $obj_token_exception = new TokenException;
       $obj_token_exception ->set_error($obj_response->error);
       $obj_token_exception ->set_error_description($obj_response->error_description);
       throw new $obj_token_exception;
    } else {
       $str_token = $obj_response->access_token;
       return $str_token;
    }
    
    ?>

    Hope this helps someone.

     


    • Edited by G4M Friday, September 16, 2011 3:03 PM
    Friday, September 16, 2011 1:06 PM
  • I knew it wouldn't be this easy.

     

    In the document located at:

    http://msdn.microsoft.com/en-us/library/hh454950.aspx

    It states:

    Use the value of access_token in the “Authorization” header of subsequent calls to the Microsoft Translator API.
    Leave the “appid” field empty (it is there for legacy purposes only).
    When the access token expires, generate a new access token as described in step 3.

    However, when I do this, I get the following error:

    Argument Exception: the parameter 'appId' must contain at least '16' characters

     

    So following on from this, I try supplying the token in the header (as specified in the same document), but when doing so, I get the following error:

    HTTP Error 400. The request has an invalid header name.


    So then I try following the conflicting document here:

    http://msdn.microsoft.com/en-us/library/ff512387.aspx

    Which states:

    Add the URL with the appropriate Access Token to the code (replace the highlighted code below with your application ID). In the following code example, thetxtInput.Text value indicates what the user will be typing into the text box on your web page.

    But when doing so, I get the following error:

    ArgumentOutOfRange Exception: the parameter 'appId' must be less than '160' characters

     

    I'm using the HTTP API and I have a whole heap of debug if it helps.

    Anybody have any clue?

    Friday, September 16, 2011 5:24 PM
  • Hi,

    I still need support for this - anyone?

    Tuesday, September 20, 2011 8:57 AM
  • I'll put it a different way:

    Can someone tell me how to use my Access Token in SOAP API calls?

    Tuesday, September 20, 2011 11:27 AM
  • G4M, do you still need help with this? If so - please email us at mtcont@microsoft.com. Thanks for your patience as we work through any kinks in the new authentication mechanisms.
    Vikram Dendi, Director of Product Management
    Microsoft Translator
    Wednesday, September 21, 2011 7:37 AM
  • Re: Can someone tell me how to use my Access Token in SOAP API calls?

    Here is an example using SOAP with the token as the "Authorization" header using C# (from doc :http://msdn.microsoft.com/en-us/library/ff512387.aspx)

    The following code creates a Http Header with header name "Authorization" and header value with the fomrat "Bearer " + the access token field from the OAuth authentication.  Note that you need to take the access token part of the original token and also need to add "Bearer " as the prefix per OAuth spec.

    And then it addes the Http header to service client (if you are using Java or other languages, there are equivalent ways to add the Http header).

    httpRequestProperty.Headers.Add("Authorization", headerValue);

    Later, it uses "" as the value of the appId field to communicate with the API.

    Please paste your code if you need us to debug the problem. Thanks.

                     // Add the http header

                    HttpRequestMessageProperty httpRequestProperty = new HttpRequestMessageProperty();

                    httpRequestProperty.Method = "POST";

                    httpRequestProperty.Headers.Add("Authorization", headerValue);

     

                    // Call Translator with the header

                    ServiceReference.LanguageServiceClient myClient = new ServiceReference.LanguageServiceClient();

                    using (OperationContextScope scope = new OperationContextScope(myClient.InnerChannel))

                    {

                        OperationContext.Current.OutgoingMessageProperties[HttpRequestMessageProperty.Name] = httpRequestProperty;

                        textBox1.Text = myClient.Translate("", "My first translation.", "en", "fr", null, null);

                    }



    • Edited by Colin Yu Wednesday, September 21, 2011 8:21 PM
    • Marked as answer by Vikram Dendi Wednesday, September 21, 2011 8:24 PM
    Wednesday, September 21, 2011 8:14 PM
  • Hi Colin,

    Thanks for this. I've followed this process exactly, and what I get in response is the following error:

     

    ArgumentOutOfRangeException: the parameter 'appId' must contain at least '16' characters

    Parameter name: appId : ID=3737.V2_Soap.Translate.2F75D00A

     

    I've fixed the HTTP header problem - I was mistakenly setting the value as a SOAP header rather than an HTTP header - fixed.

    I'm not sure how much this is going to help, but here is the code anyway:

    <?php
    $obj_auth = new AzureMarketplaceAuthenticator('xxx','xxx','http://api.microsofttranslator.com');
    $str_token = $obj_auth->get_token();
          
    $arr_context = array('http' =>
      array(
          "header"  => "Authorization: Bearer " . $str_token
      )
    );
    
    $arr_options = array (
       'soap_version' => 'SOAP_1_2',
       'encoding' => 'UTF-8',
       'exceptions' => true,
       'trace' => '1',
       'cache_wsdl' => 'WSDL_CACHE_NONE',
       'stream_context' => stream_context_create($arr_context)
    );
    
    $obj_connection = new SoapClient(self::STR_BASE_URL, $arr_options);
    $str_soap_action = 'Translate';
    $arr_request_arguments = array (
       'appId' => '',
       'text' => $str_source_text,
       'from' => $str_source_language,
       'to' => $str_target_language
    );
    
    $obj_soap_response = call_user_func(array($obj_connection, $str_soap_action), $arr_request_arguments);
    $str_result = $obj_soap_response->TranslateResult;
    ?>
    
    Thanks

    Wednesday, September 21, 2011 9:24 PM
  • G4M, your PHP code looks correct. Since PHP supports both double quote and single quote, your use of double quote for the header shouldn't affect the result. But it may be good to keep them consistent.

    Is it possible for you to dump the Http Web request and see what you are passing out? If you can, can you paste it here? Thanks.

    When you see the following exception, it meant the translation service can't find the Authorization Http header and falls back the legacy AppId field for authentication. But since it is null, the validation failed. This is the error you still see after you moved from SOAP header to Http Header, right?

    ArgumentOutOfRangeException: the parameter 'appId' must contain at least '16' characters


    • Edited by Colin Yu Thursday, September 22, 2011 12:07 AM
    Thursday, September 22, 2011 12:07 AM
  • Hi Colin,

    Being inherently hard to debug HTTP headers in a SOAP call with PHP, I've fired up wireshark and sure enough the HTTP Authorization header was missing. I've done some digging around, and it appears that there is a bug in certain versions of PHP whereby SOAP refuses to set any custom HTTP headers:

    https://bugs.php.net/bug.php?id=49853

    Seems to have been affecting my version.

    Anyhoo, I've made the fix which is to set the PHP user agent string prior to making the SOAP call, for example:

    $str_auth_header = "Authorization: Bearer ". $str_token;
    ini_set('user_agent', 'PHP-SOAP/' . PHP_VERSION . "\r\n" . $str_auth_header);
    
    // ... etc.
    

    Seems to work OK. I'll look at posting a more detailed PHP solution in future if it helps others.

    Thanks for your help!

    Thursday, September 22, 2011 9:21 AM
  • Hi, me again :)

    I've been running translations fine for a day now, but suddenly I'm getting these errors:

    InvalidOperationException:  : ID=3641.V2_Soap.Translate.30AC6EC0
    InvalidOperationException:  : ID=3743.V2_Soap.Translate.30A16F66

    etc. for every single translation requested in the last two hours. I thought this was supposed to indicate an out-of-quota message, but there's no way we can be out of quota.

    Can someone check this for me please?

    Thanks.

    Friday, September 23, 2011 1:28 PM
  • G4M,

    can you email mtlic@microsoft.com with the following info?

    Customer Name:

    Subscribed through Marketplace: Yes/No

    If yes: Quota Subscribed to

    If no: Are you a licensee of the API prior to availability of the Marketplace? Please send your legacy AppID and Quota allocated.

    Error being seen:

    What caused the error:

     

    • Proposed as answer by Gabinnyo group Sunday, September 25, 2011 1:06 PM
    Friday, September 23, 2011 7:58 PM
  • Hi,

    Thanks - I have emailed the address with the details requested.

    Many thanks.

    Monday, September 26, 2011 10:52 AM
  • Hi G4M, I am glad that you have made progress with the PHP app.

    For a fast turn around of the exception you are seeing, please email mtlic@microsoft.com with one more information, the ClientId you are using in your OAuth token. I apologized that we haven't included this information in our first response.

    Thank you!

    Colin

    Monday, September 26, 2011 8:14 PM
  • Hi there, just as you, i searched and searched, and none of the above, below or beyond exmaples worked for me just they way they were, so i had to code my own PHP SOAP w/OAP access token script with the help of said examples.

    Here's a link to my blog post where you may find the script:

    http://scribblesfrombeyond.blogspot.com/2011/12/what-does-it-pro-actually-do-bing-or.html

    Hope it helps you and anybody else =)
    Nstiac


    • Edited by Nstiac Sunday, December 4, 2011 10:10 AM
    Sunday, December 4, 2011 10:09 AM