The bounty expires in 6 days. Answers to this question are eligible for a +50 reputation bounty.
Porcellino80 wants to draw more attention to this question.
I'm a little bit out of my comfort zone. I'm trying to create a SOAP request with PHP, and I'm using the "in" famous API of KBO, here's the documentation:
https://economie.fgov.be/sites/default/files/Files/Entreprises/CBE/Cookbook-CBE-Public-Search-Webservice.pdf
So essentially everything went well, but I'm still struggling with something about the authentication, which makes me fail my entire small framework:
<?php
$endpoint = 'https://kbopub-acc.economie.fgov.be/kbopubws110000/services/wsKBOPub';
$wsdl = 'https://kbopub-acc.economie.fgov.be/kbopubws110000/services/wsKBOPub?wsdl';
$username = 'myusername';
$password = 'mypassword';
$timestamp = gmdate('Y-m-d\TH:i:s\Z');
$nonce = base64_encode(random_bytes(16));
$passwordDigest = base64_encode(sha1($nonce . $timestamp . $password, true));
$header = '
<wsse:Security xmlns:wsse="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd">
<wsse:UsernameToken>
<wsse:Username>' . $username . '</wsse:Username>
<wsse:Password Type="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-username-token-profile-1.0#PasswordDigest">' . $passwordDigest . '</wsse:Password>
<wsse:Nonce>' . $nonce . '</wsse:Nonce>
<wsu:Created xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd">' . $timestamp . '</wsu:Created>
</wsse:UsernameToken>
</wsse:Security>';
$options = array(
'soap_version' => SOAP_1_1,
'trace' => true,
'exceptions' => true,
'encoding' => 'UTF-8',
'cache_wsdl' => WSDL_CACHE_NONE,
'stream_context' => stream_context_create(array(
'http' => array(
'header' => 'Authorization: WSSE profile=' . $header,
'user_agent' => 'PHPSoapClient'
),
'ssl' => array(
'verify_peer' => false,
'verify_peer_name' => false
)
))
);
$context = stream_context_create(array(
'ssl' => array(
'verify_peer' => false,
'verify_peer_name' => false,
),
));
$options['stream_context'] = $context;
// $options = array(
// 'soap_version' => SOAP_1_1
// );
$client = new SoapClient($wsdl, $options);
// Set up the request parameters
$enterpriseNumber = '0810.002.854';
$request = array('EnterpriseNumber' => $enterpriseNumber);
// Call the SOAP operation with the request parameters
$response = $client->__soapCall('ReadEnterprise', array($request));
// Get the request and response XML
$requestXML = $client->__getLastRequest();
$responseXML = $client->__getLastResponse();
var_dump($response);
I also followed some suggestions from my PHP log file, where it was written to use a different version of the soap version: SOAP_1_1 instead of the SOAP_1_2.
What I find really challenging is the fact that I can't debug it in any way, I have no idea on how I can check the error message, or I can't have any hint in my error log file, it simply mentions the security check, but nothing much.
Has anyone had the same issue?
THanks
By the way, the error that I have encountered is the following:
[14-Feb-2023 17:09:24 UTC] PHP Fatal error: Uncaught SoapFault exception: [ns1:SecurityError] A security error was encountered when verifying the message in
Stack trace:
#0 /Users/mymac/Sites/cboxform/api-call/index.php(55): SoapClient->__soapCall('ReadEnterprise', Array)
#1 {main}
thrown in /Users/mymac/Sites/cboxform/api-call/index.php on line 55
Related
I wanted to consume Navision 2016 soap web services from either PHP or jquery.
I have tried this solution PHP with Dynamics NAV webservices
I have the following code for soap PHP:
<?php
if (extension_loaded('soap'))
{
// Request parameters :
// Exemple is a Nav Code unit GetSalesPrices, method GetPrice(CodPCustomerNo, CodPItemNo)
$NavUsername = "superUser";
$NavAccessKey = "passworddrowssap";
$CodeunitMethod = "CallMethod";
$params = array(
"employeeNo" => "CUSTOMER_1",
"leaveType" => "ITEM_1",
);
// SOAP request header
$url = "http://DESKTOP-H5GFAKH:7047/DynamicsNAV100/WS/MyCompany/Codeunit/webportals";
$options = array(
'authentication' => SOAP_AUTHENTICATION_BASIC,
'login' => $NavUsername,
'password' => $NavAccessKey,
'trace' => 1,
'exception' => 0,
);
try
{
$client = new SoapClient(trim($url), $options);
$soap_response = $client->__soapCall($CodeunitMethod, array('parameters' => $params));
echo "SOAP REQUEST SUCESS :";
var_dump($soap_response);
}
catch (SoapFault $soapFault)
{
echo "SOAP REQUEST FAILED :<br>";
var_dump($soapFault);
echo "Request :<br>" . htmlentities($soap_client->__getLastRequest()) . "<br>";
echo "Response :<br>" . htmlentities($soap_client->__getLastResponse()) . "<br>";
}
}
else
{
echo "Php SOAP extention is not available. Please enable/install it to handle SOAP communication.";
}
?>
With this I get:
SOAP-ERROR: Parsing WSDL: Couldn't load from
'http://DESKTOP-H5GFAKH:7047/DynamicsNAV100/WS/MyCompany/Codeunit/webportals'
: failed to load external entity
For starters, you can use POSTMAN and you can get the code that you should use. Having said that, see my code below. You don't have to use SoapClient, just use cURL in PHP. Make sure to use Basic Auth authentication in Navision. The below example is of a request to NAV to get a data from a NAV list
$curl = curl_init();
curl_setopt_array($curl, array(
CURLOPT_URL => "https://URL:PORT/WebService/WS/COMPANY%20NAME/Page/WebService",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 0,
CURLOPT_FOLLOWLOCATION => true,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "GET",
CURLOPT_POSTFIELDS =>"<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<Envelope xmlns=\"http://schemas.xmlsoap.org/soap/envelope/\">\n<Body>\n<Read xmlns=\"urn:microsoft-dynamics-schemas/page/WebService\">\n<No>" .$entry_no. "</No>\n</Read>\n</Body>\n</Envelope>",
CURLOPT_HTTPHEADER => array(
"Content-Type: text/xml; charset=utf-8",
"SoapAction: urn:microsoft-dynamics-schemas/page/WebService",
"Authorization: Basic " .base64_encode('username:password'). ""
),
));
$response = curl_exec($curl);
$err = curl_error($curl);
$xml = simplexml_load_string($response, NULL, NULL, "http://schemas.xmlsoap.org/soap/envelope/");
$xml->registerXPathNamespace('soapenv', 'http://schemas.xmlsoap.org/soap/envelope/');
$xml->registerXPathNamespace('xmlns', 'urn:microsoft-dynamics-schemas/page/webservice');
$xmlinfo = $xml->xpath('Soap:Body');
User Wizdler from Chrome Store or Firefox extensions to enable you parse the WSDL and generate the SOAP messages.
For jQuery, you can use POSTMAN to generate the required code or you should consider using AJAX
I use SoapClient wsdl to retrive some data. It works fine if response is not too large, but if the response is too large, in my case 25 mb, it returns null.
Can anyone help me please?
Here's my code:
$opt = array('http' => array(
'header' => "MyIdClient:" . $idclient . "\r\nMySecret:" . $mysecret .
"\r\nContent-Type:text/xml; charset=utf-8"
));
$ctx = stream_context_create($opt);
$options = array(
'cache_wsdl' => WSDL_CACHE_NONE,
'stream_context' => $ctx,
'soap_version'=>SOAP_1_1,
'keep_alive' => 1,
"features" => SOAP_WAIT_ONE_WAY_CALLS
);
$client = new SoapClient($wsdl, $options);
$search_result = $client->__doRequest($request, $endpoint, $action, 1, 0);
I wondered if someone can help?
I've purchased a web theme for a client but can't get the twitter widget working. It's probably something really simple but as I'm not a web developer I'm struggling to figure out what's preventing it form working.
Here's the webpage http://www.blackrocksearch.co.uk/new/ - the twitter feed should display in the footer. It works on the templates demo site but I notice in the item comments other customers having the same issue so think there could be a glitch somewhere.
Demo where it's working here:http://vasterad.com/themes/sensation/index.html
Here's the snippet of code from the twitter.php file which is apparently the only area I need to configure (I've left out the actual access token numbers for security):
<?php
/**
* Usage:
* Send the url you want to access url encoded in the url paramater, for example (This is with JS):
* /twitter-proxy.php?url='+encodeURIComponent('statuses/user_timeline.json?screen_name=MikeRogers0&count=2')
*/
// The tokens, keys and secrets from the app you created at https://dev.twitter.com/apps
$config = array(
'oauth_access_token' => 'token-here',
'oauth_access_token_secret' => 'token-here',
'consumer_key' => 'token-here',
'consumer_secret' => 'token-here',
'use_whitelist' => true, // If you want to only allow some requests to use this script.
'base_url' => 'http://api.twitter.com/1.1/'
);
/*
* Ok, no more config should really be needed. Yay!
*/
// We'll get the URL from $_GET[]. Make sure the url is url encoded, for example encodeURIComponent('statuses/user_timeline.json?screen_name=MikeRogers0&count=10&include_rts=false&exclude_replies=true')
if(!isset($_GET['url'])){
die('No URL set');
}
$url = $_GET['url'];
if($config['use_whitelist'] && !isset($whitelist[$url])){
die('URL is not authorised');
}
// Figure out the URL parmaters
$url_parts = parse_url($url);
parse_str($url_parts['query'], $url_arguments);
$full_url = $config['base_url'].$url; // Url with the query on it.
$base_url = $config['base_url'].$url_parts['path']; // Url with the query.
/**
* Code below from http://stackoverflow.com/questions/12916539/simplest-php-example-retrieving-user-timeline-with-twitter-api-version-1-1 by Rivers
* with a few modfications by Mike Rogers to support variables in the URL nicely
*/
function buildBaseString($baseURI, $method, $params) {
$r = array();
ksort($params);
foreach($params as $key=>$value){
$r[] = "$key=" . rawurlencode($value);
}
return $method."&" . rawurlencode($baseURI) . '&' . rawurlencode(implode('&', $r));
}
function buildAuthorizationHeader($oauth) {
$r = 'Authorization: OAuth ';
$values = array();
foreach($oauth as $key=>$value)
$values[] = "$key=\"" . rawurlencode($value) . "\"";
$r .= implode(', ', $values);
return $r;
}
// Set up the oauth Authorization array
$oauth = array(
'oauth_consumer_key' => $config['consumer_key'],
'oauth_nonce' => time(),
'oauth_signature_method' => 'HMAC-SHA1',
'oauth_token' => $config['oauth_access_token'],
'oauth_timestamp' => time(),
'oauth_version' => '1.0'
);
$base_info = buildBaseString($base_url, 'GET', array_merge($oauth, $url_arguments));
$composite_key = rawurlencode($config['consumer_secret']) . '&' . rawurlencode($config['oauth_access_token_secret']);
$oauth_signature = base64_encode(hash_hmac('sha1', $base_info, $composite_key, true));
$oauth['oauth_signature'] = $oauth_signature;
// Make Requests
$header = array(
buildAuthorizationHeader($oauth),
'Expect:'
);
$options = array(
CURLOPT_HTTPHEADER => $header,
//CURLOPT_POSTFIELDS => $postfields,
CURLOPT_HEADER => false,
CURLOPT_URL => $full_url,
CURLOPT_RETURNTRANSFER => true,
CURLOPT_SSL_VERIFYPEER => false
);
$feed = curl_init();
curl_setopt_array($feed, $options);
$result = curl_exec($feed);
$info = curl_getinfo($feed);
curl_close($feed);
// Send suitable headers to the end user.
if(isset($info['content_type']) && isset($info['size_download'])){
header('Content-Type: '.$info['content_type']);
header('Content-Length: '.$info['size_download']);
}
echo($result);
?>
Hope someone can help!
By looking on your site on PHP file that doing a request to Twitter's response, it appears that your request needs to do a secure connection. So, my guesses are:
1. Connecting through https
Change your base_url key on $config variable to https.
$config = array(
'oauth_access_token' => 'token-here',
'oauth_access_token_secret' => 'token-here',
'consumer_key' => 'token-here',
'consumer_secret' => 'token-here',
'use_whitelist' => true,
'base_url' => 'https://api.twitter.com/1.1/' //was http://api.twitter.com/1.1/
);
2. Adding CA (Certificate Authority) cert file
In case my first guess doesn't resolve anything, adding CA cert on cURL request might help. First, get your own cacert.pem from here. Save it on some path you could recognize. Then simply set cURL option CURLOPT_SSL_VERIFYPEERto true and optionally you can also explicitly set CURLOPT_SSL_VERIFYHOST to its default value which is 2.
In example, according to your snippet, saving in a same path as your Twitter cURL PHP file.
$options = array(
CURLOPT_CAINFO => __DIR__ . '/cacert.pem', //or dirname(__FILE__) . '/cacert.pem' for PHP < 5.3
CURLOPT_HTTPHEADER => $header,
//CURLOPT_POSTFIELDS => $postfields,
CURLOPT_HEADER => false,
CURLOPT_URL => $full_url,
CURLOPT_RETURNTRANSFER => true,
CURLOPT_SSL_VERIFYHOST => 2,
CURLOPT_SSL_VERIFYPEER => true,
);
As an option you can also predefine the cacert.pem in your php.ini configuration file. Just add/edit following line and don't forget about the path too
curl.cainfo = "some/path/cacert.pem"
Let me know
Formerly i used XML way to get data from external API. Now, internal company policy orders to use JSON to communicate with API. I know what data i should send in request and how data i'll get back but i have no idea how to call with API by JSON.
My PHP server is localhost.
Let JSON API be located https://api.example.com/service-api and i'm sure it works fine.
Request
{"action":"authorization", "args":{"username":"firstname#dev.com","password":"qpujy676"}}
Callback
{"status":"OK", "token":"8hsa77hh687y3sbdha7ah3dajknfa93"}
I found example but i dont know what is Http_client(), what is it role and what it will do.
$http = new Http_Client();
$http->setUri('https://api.example.com/service-api');
$postdata = array(
'action' => 'authorization',
'args' => array(
'username' => 'firstname#dev.com',
'password' => 'qpujy676',
)
);
if (CRYPT_KEY_API) { //if encrypted data
$postdata ['rand'] = md5(time() . rand(2303, 85500));
$postdata = json_encode($postdata);
$postdata = Crypt::encrypt($postdata);
} else {
$postdata = json_encode($postdata);
}
$http->setRawData($postdata, 'application/json');
$response = $http->request(POST);
if ($response->isSuccessful()) {
$responseData = $response->getBody();
if (CRYPT_KEY_API) { //if encrypted data
$responseData = Crypt::decrypt($responseData);
}
$results = json_decode($responseData, true);
} else {
$error_message = "<p>Error</p>\n";
$error_message .= "HTTP Status: " . $response->getStatus() . "\n";
$error_message .= "HTTP Headers:\n";
$responseHeaders = $response->getHeaders();
foreach ($responseHeaders as $responseHeaderName => $responseHeaderValue) {
$error_message .= "$responseHeaderName: $responseHeaderValue\n";
}
throw new Exception($error_message);
}
Practically i need only exemplary http_client class to solve my problem :-) Especially
setRawData($postdata, 'application/json')
request(POST)
getBody()
I creared method autorization_test(), that supposedly should response with external API. Supposedly, because it output is:
Warning:
file_get_contents(https://api.example.com/service-api):
failed to open stream: HTTP request failed! HTTP/1.1 404 Not Found in
C:\xampp\htdocs\prestashop1611\modules\miniwa\miniwa.php on line 180
Error
public function authorization_test()
{
$domain = MINIWA_DOMAIN;
$username = 'tester#user.com';
$password = '12345';
$postData = array(
'action' => 'authorization',
'args' => array(
'domain' => $domain,
'username' => $username,
'password' => $password,
),
);
$postData = json_encode($postData);
//$postData = Crypt::encrypt($postData);
$context = stream_context_create(array(
'http' => array(
// http://www.php.net/manual/en/context.http.php
'method' => 'POST',
'header' => 'Content-Type: application/json',
'content' => $postData,
)
));
// Send the request
$response = file_get_contents('https://api.example.com/service-api', FALSE, $context);
// Check for errors
if($response === FALSE){
die('Error');
}
//$response= Crypt::decrypt($response);
// Decode the response
$responseData = json_decode($response, TRUE);
// send the output data to view
$smarty->assign(array(
'json_decoded_output' => $responseData,
));
return $smarty;
Why there's no positive output?
Here you have whole documentation:
https://pear.php.net/manual/en/package.http.http-client.http-client-summary.php
API was disabled, now is OK, code is right.
I tried to send a post request using this PHP code but throw me 401 Unauthorized error:
$username = 'MyDomain\testuser';
$password = '123456';
$url = 'http://10.20.30.40:8080/TargetPage.aspx';
$data = array(
'username' => $username,
'password' => $password,
'postdata' => 'InputParameter1=Test1&InputParameter2=Test2'
);
$options = array(
'http' => array
(
'method' => 'POST',
'header' => "Content-type: application/x-www-form-urlencoded\r\n",
'content' => http_build_query($data)
)
);
$context = stream_context_create($options);
$result = file_get_contents($url, false, $context);
You're not doing proper basic auth. You have to build the authenticate header yourself:
$options = array(
'http' => array(
'header' => 'Authorization: Basic ' . base64_encode("$username:$password")
)
);
You can't just shove a username/password elements into the array and expect it to work. PHP doesn't know you're building a stream to HTTP basic auth... you have to provide EVERYTHING yourself.