Issue
I am sending a POST request in PHP via cURL to a REST API that uses XML. When I use Postman or Advanced REST Client, I get a XML response to my POST request. However, when I use PHP and cURL I do not seem able to see back the XML responses. What do I need to do to get these back? Eventually I need to retrieve a token that I can then use to process INSERT, UPDATES and GETS through this API via XML.
Here is the code that I am currently using:
$curl = curl_init();
curl_setopt_array($curl, array(
CURLOPT_URL => 'https://xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx',
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => '',
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 0,
CURLOPT_FOLLOWLOCATION => true,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => 'POST',
CURLOPT_HTTPHEADER => array(
'xxxxxx-Username: xxx',
'xxxxxx-Password: xxx',
'content-type: application/xml'
),
));
$response = curl_exec($curl);
curl_close($curl);
echo $response;
and currently I am getting a blank page. I have tried quite a few solutions, like the following
//header("Content-Type: text/xml");
//header('Content-type: application/xml');
//$decoded = iconv("UTF-8", "ISO-8859-1//TRANSLIT", $response);
//echo $decoded;
//echo $response;
//print_r($response);
// set up your xml result
$xml = new SimpleXMLElement($response, LIBXML_NOCDATA);
// loop through the results
$cnt = count($xml->Result);
for($i=0; $i<$cnt; $i++){
echo 'XML : First Name: = ';
}
but nothing seems to give me back what I get from Postman or Advanced REST Client, which on this particular command is the following
<?xml version="1.0" encoding="UTF-8"?>
<AuthInfo>
<token/>
<AuthStatus>
<Id>503</Id>
<Description>There's no proapi manager running with the given company code: crmapp</Description>
</AuthStatus>
</AuthInfo>
I understand that at this stage there is an issue with my url that I need to fix, but I still should be able to receive that error back via XML.
Can anyone please help me get this XML response back so that I can progress my interface?
Thank you in advance, Adri
Thanks again Professor, here is the full debug with the latest version of PHP and cUrl
Verbose debug info
* Trying xxx.xx.xxx.xxx:443...
* Connected to xxxxx-xx-xx.xxxxxxxx.com.au (xxx.xx.xxx.xxx) port 443 (#0)
* ALPN, offering h2
* ALPN, offering http/1.1
* successfully set certificate verify locations:
* CAfile: D:/Adri/PHP/MoW/famac/cacert.pem
* CApath: D:/Adri/PHP/MoW/famac/cacert.pem
* SSL connection using TLSv1.2 / ECDHE-RSA-AES256-GCM-SHA384
* ALPN, server did not agree to a protocol
* Server certificate:
* subject: CN=*.prontohosted.com.au
* start date: Jun 2 00:00:00 2020 GMT
* expire date: Sep 4 00:00:00 2022 GMT
* subjectAltName: host "xxxxx-xx-xx.xxxxxxxx.com.au" matched cert's "*.xxxxxxxx.com.au"
* issuer: C=GB; ST=Greater Manchester; L=Salford; O=Sectigo Limited; CN=Sectigo RSA Domain Validation Secure Server CA
* SSL certificate verify ok.
> GET /xxxxx/rest/xxx.xxx/login HTTP/1.1
Host: xxxxx-xx-xx.xxxxxxxx.com.au
User-Agent: Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.38 (KHTML, like Gecko) Chrome/83.0.4103.97 Safari/537.38
Accept: */*
Accept-Encoding: deflate, gzip
xxxxxx-Username: xxx
xxxxxx-Password: xxx
Content-Type: application/xml
* Mark bundle as not supporting multiuse
< HTTP/1.1 404 Not Found
< Date: Tue, 09 Nov 2021 11:34:57 GMT
< Server: Apache
< Referrer-Policy: origin-when-cross-origin, strict-origin-when-cross-origin
< X-Frame-Options: SAMEORIGIN
< X-XSS-Protection: 1; mode=block
< X-Content-Type-Options: nosniff
< Content-Security-Policy: img-src 'self' *.xxxxx.net *.xxxxx.com.au https://www.google.com https://*.googleapis.com/ www.google-analytics.com stats.g.doubleclick.net http://*.xxxxx-xxxxx.com *.twitter.com *.twimg.com data: blob: https://*.google.com https://*.gstatic.com https://*.googleapis.com; frame-src * blob:; script-src 'self' 'unsafe-inline' 'unsafe-eval' *.xxxxx.net *.xxxxx.com.au https://*.google.com www.google-analytics.com *.twitter.com *.twimg.com https://*.googleapis.com https://jawj.github.io https://*.gstatic.com; connect-src 'self' wss: blob: *.twitter.com www.google-analytics.com stats.g.doubleclick.net; base-uri 'none'; style-src 'self' 'unsafe-inline' *.twitter.com *.twimg.com https://*.google.com *.googleapis.com https://*.gstatic.com; font-src 'self' data: https://*.googleapis.com https://fonts.gstatic.com; child-src * blob:; object-src 'none'; default-src 'self' blob:
< X-Permitted-Cross-Domain-Policies: master-only
< Content-Type: text/html; charset=UTF-8
< Content-Length: 994
* The requested URL returned error: 404
* Closing connection 0
Info
stdClass Object
(
[url] => https://xxxxx-xx-xx.xxxxxxxx.com.au/xxxxx/rest/xxx.xxx/login
[content_type] => text/html; charset=UTF-8
[http_code] => 404
[header_size] => 1271
[request_size] => 350
[filetime] => -1
[ssl_verify_result] => 0
[redirect_count] => 0
[total_time] => 0.232624
[namelookup_time] => 0.029367
[connect_time] => 0.05058
[pretransfer_time] => 0.162497
[size_upload] => 0
[size_download] => 0
[speed_download] => 0
[speed_upload] => 0
[download_content_length] => 994
[upload_content_length] => 0
[starttransfer_time] => 0.232609
[redirect_time] => 0
[redirect_url] =>
[primary_ip] => xxx.xx.xxx.xxx
[certinfo] => Array
(
)
[primary_port] => 443
[local_ip] => xxx.xxx.x.xxx
[local_port] => 52711
[http_version] => 2
[protocol] => 2
[ssl_verifyresult] => 0
[scheme] => HTTPS
[appconnect_time_us] => 162464
[connect_time_us] => 50580
[namelookup_time_us] => 29367
[pretransfer_time_us] => 162497
[redirect_time_us] => 0
[starttransfer_time_us] => 232609
[total_time_us] => 232624
)
Can you please let me know what you think of this? While I am no longer getting the previous error, I still seem unable to receive the XML response back. :(
Thank you in advance, Adri
Solution
The curl function I use is as follows. It has extra debugging information in the output and the default settings can be easily overridden at runtime by supplying a different $options
argument. I'm not suggesting this is the answer but with a better set of options configured and better debug info you should get closer.
function curl( $url=NULL, $options=NULL, $headers=false ){
$cacert='c:/wwwroot/cacert.pem';
$vbh = fopen('php://temp', 'w+');
/*
Download a copy of CACERT.pem from
https://curl.haxx.se/docs/caextract.html
save to webserver and modify the $cacert variable
to suit - ensuring that the path you choose is
readable.
*/
$res=array(
'response' => NULL,
'info' => array( 'http_code' => 100 ),
'headers' => NULL,
'errors' => NULL
);
if( is_null( $url ) ) return (object)$res;
session_write_close();
/* Initialise curl request object - these should be OK as-is */
$curl=curl_init();
if( parse_url( $url,PHP_URL_SCHEME )=='https' ){
curl_setopt( $curl, CURLOPT_SSL_VERIFYPEER, true );
curl_setopt( $curl, CURLOPT_SSL_VERIFYHOST, 2 );
curl_setopt( $curl, CURLOPT_CAINFO, $cacert );
curl_setopt( $curl, CURLOPT_CAPATH, $cacert );
}
/* Define standard options */
curl_setopt( $curl, CURLOPT_URL,trim( $url ) );
curl_setopt( $curl, CURLOPT_AUTOREFERER, true );
curl_setopt( $curl, CURLOPT_FOLLOWLOCATION, true );
curl_setopt( $curl, CURLOPT_FAILONERROR, true );
curl_setopt( $curl, CURLOPT_HEADER, false );
curl_setopt( $curl, CURLINFO_HEADER_OUT, false );
curl_setopt( $curl, CURLOPT_RETURNTRANSFER, true );
curl_setopt( $curl, CURLOPT_BINARYTRANSFER, true );
curl_setopt( $curl, CURLOPT_CONNECTTIMEOUT, 20 );
curl_setopt( $curl, CURLOPT_TIMEOUT, 60 );
curl_setopt( $curl, CURLOPT_USERAGENT, 'Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.38 (KHTML, like Gecko) Chrome/83.0.4103.97 Safari/537.38' );
curl_setopt( $curl, CURLOPT_MAXREDIRS, 10 );
curl_setopt( $curl, CURLOPT_ENCODING, '' );
/* enhanced debug */
curl_setopt( $curl, CURLOPT_VERBOSE, true );
curl_setopt( $curl, CURLOPT_NOPROGRESS, true );
curl_setopt( $curl, CURLOPT_STDERR, $vbh );
/* Assign runtime parameters as options to override defaults if needed. */
if( isset( $options ) && is_array( $options ) ){
foreach( $options as $param => $value ) curl_setopt( $curl, $param, $value );
}
/* send any headers with the request that are needed */
if( $headers && is_array( $headers ) ){
curl_setopt( $curl, CURLOPT_HTTPHEADER, $headers );
}
/* Execute the request and store responses */
$res=(object)array(
'response' => curl_exec( $curl ),
'info' => (object)curl_getinfo( $curl ),
'errors' => curl_error( $curl )
);
rewind( $vbh );
$res->verbose=stream_get_contents( $vbh );
fclose( $vbh );
curl_close( $curl );
return $res;
}
Then, to use it:
$url='https://www.example.com/api/';
$args=array();
$headers=array(
'xxxxxx-Username: xxx',
'xxxxxx-Password: xxx',
'Content-Type: application/xml'
);
$res=curl( $url, $args, $headers );
if( $res->info->http_code==200 ){
#cool - use $res->response in further processing
print_r($res->response,true);
}else{
# useful information will be displayed here...
printf('<h1>Verbose debug info</h1><pre>%s</pre>',print_r($res->verbose,true));
printf('<h1>Info</h1><pre>%s</pre>',print_r($res->info,true));
}
Answered By - Professor Abronsius