I am trying to connect the Nav Web Services in Php (followed by this Blog).
but it's returning an error:
SOAP-ERROR: Parsing WSDL: Couldn't load from
'http://NavIP.com:7047/DynamicsNAV/WS/SystemService' : Start tag
expected, '<' not found.
Could you tell me where I went wrong?
thanks in advance..
my code is:
//client.php
<?php
require_once("NTLMStream.php");
require_once("NTLMSoapClient.php");
try
{
// we unregister the current HTTP wrapper
stream_wrapper_unregister('http');
// we register the new HTTP wrapper
stream_wrapper_register('http', 'NTLMStream') or die("Failed to register protocol");
// Initialize Soap Client
$baseURL = 'http://NavIp.Com:7047/DynamicsNAVPMS/WS/';
$client = new NTLMSoapClient($baseURL.'SystemService');
// Find the first Company in the Companies
$result = $client->Companies();
$companies = $result->return_value;
echo "Companies:<br>";
if (is_array($companies)) {
foreach($companies as $company) {
echo "$company<br>";
}
$cur = $companies[0];
}
else {
echo "$companies<br>";
$cur = $companies;
}
}
catch(Exception $ex)
{
echo $ex->getMessage();
}
?>
I am dealing with the exact same problem, but have not found a solution because they all come back to this same script. Your problem is that you are getting no result back because of a 401 error code (could not authenticate), which is exactly I where I am stuck as well. The script ends up using CURL to connect, but somehow that fails.
Use this
$client = new NTLMSoapClient(null, $baseURL.'SystemService');
You are wrongly providing baseURL which is being taken as WSDL location. In your code, seems like you are trying to provide the service endpoint. Try that.
You could also use a packet sniffer like 'Wireshark' to see what response you are getting. The expected response is an xml, which seems like it is not returning. Maybe it is returning a 401 unauthorized? That's not an XML response, that also could be a cause.
Also, where is define('USERPWD','user:pass'); in your code? Didn't you use authentication? I have a strong feeling you just need to define it. Make sure you define the 'domain' part in the username field if you are using a domain. So, 'domain\user:pass'.
This post is good: http://blogs.msdn.com/b/freddyk/archive/2010/01/19/connecting-to-nav-web-services-from-php.aspx
Instead of using NTLM, try using Basic Authentication which is quite straight forward and then use cURL. It is easy peasy. See code below for a simple implementation. You can use SOAP or ODATA
You should also use a Chrome extension known as Wizdler
See sample code below for a Basic implementation
$curl = curl_init();
curl_setopt_array($curl, array(
CURLOPT_URL => "https://navdynamicsip.com:port/WebService/WS/COMPANY NAME/Page/webservice",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 0,
CURLOPT_FOLLOWLOCATION => true,
CURLOPT_SSL_VERIFYPEER => false,
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\"></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);
curl_close($curl);
Related
I built a custom Wordpress plugin. The plugin frontend is a Facebook React JS application that is embedded into a Wordpress page via a shortcode. It uses the Wordpress REST API exclusively to send and retrieve JSON between the client browser and Wordpress. Wordpress is acting as the middleman in this scenario. The REST routes handling the client requests just call a backend REST API and return the responses to the client from the other server.
I've just added a new feature to the app that allows the user to download a PDF file that's dynamically generated by a different backend server (not Wordpress). My plan was to just add another route on the Wordpress REST API that would call the backend server and return the PDF file generated by that other server. Wordpress would basically just proxy the request to the backend server and return the response back to the client browser.
However, when I try to do that the response body is a string instead of the raw byte array returned from the backend server. I can make the request to the backend server directly and it properly returns the PDF file (e.g. http://default-internal-backend-server.example.com/api/v1/quote/asdf123/pdf).
What's the proper way to have a Wordpress Plugin handle a REST request (e.g. https://example.com/wp-json/my-plugin/v1/quote/asdf123/pdf) and return the raw, untouched, response from an upstream server?
For example, I was doing this:
On the UI of the app I have a simple anchor tag like this:
<a href="http://example.com/wp-json/my-plugin/quote/asdf123/pdf" download="quote.pdf">
<span>Download PDF</span>
</a>
The above URL is registered in the REST Routes of the plugin as so:
class My_Plugin_REST_Controller extends WP_REST_Controller {
// ****
register_rest_route( 'my-plugin', '/quote/(?P<id>\w+)/pdf',
array(
array(
'methods' => WP_REST_Server::READABLE,
'callback' => array( $this, 'get_quote_pdf' ),
'args' => array()
)
)
);
public function get_quote_pdf( $request ) {
$api_service = API_Service::get_instance();
$response = $api_service->getQuotePdf( $request );
$http_response = new WP_REST_Response( $response, 200 );
$http_response->header('Content-Type', 'application/pdf');
return $http_response;
}
// ****
}
class API_Service {
public function getQuotePdf( $request ) {
$curl = curl_init();
$default_options = array(
'url' => 'http://default-internal-backend-server.example.com'
);
$api_options = get_option( 'my_plugin_api', $default_options );
$api_url = $api_options['url'] . '/api/v1/quote/' . $request['id'] . '/pdf'
curl_setopt_array($curl, array(
CURLOPT_URL => $api_url,
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => '',
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "GET",
CURLOPT_HTTPHEADER => array(
"Accept: application/pdf",
"Cache-Control: no-cache"
)
));
$response = curl_exec( $curl );
$err = curl_error( $curl );
curl_close( $curl );
if ( $err ) {
return null;
} else {
return $response;
}
}
}
Wordpress is properly handling the request from the client JavaScript application, the backend server is being called properly, the backend server is returning the PDF file.
However, with the above example, Wordpress is returning a string representation of the PDF instead of the raw bytes returned by the external server. I had to fight with the WP_Rest_Response to get it to set the Content-Type to appplication/pdf as well. If I set the Content-Length header it would change the Content-Type to application/json for no apparent reason.
How can I return the raw bytes instead of a string version of the response?
My next step is to just remove having Wordpress involved with this at all and link to a different URL in the browser (e.g. https://my.example.com/quote/asdf123/pdf) that uses a reverse proxy to get to the internal server directly.
I did read that PHP doesn't have a native data type of byte[] which could be the limiting factor.
Using Google App Engine, when calling my API using POST method, it shows as GET - why?
This is my code:
function call_api($client_id, $client_secret, $data) {
$api_url = 'http://myapp.com/api.php';
$options = array(
'http' => array(
'header' => "Authorization: Basic " . Base64_encode("$client_id:$client_secret") . "\r\nContent-type: application/x-www-form-urlencoded\r\n",
'method' => 'POST',
'content' => http_build_query($data)
)
);
$context = stream_context_create($options);
$result = file_get_contents($api_url, false, $context);
return $result;
}
The first line of api.php is:
echo "<pre>"; print_r($_SERVER); echo "</pre>";
And within that output, I see:
[REQUEST_METHOD] => GET
How/why could this be happening?
It's also worth mentioning that the method shows as POST when testing this code on GAE's SDK.
I worked it out and I need to answer my own question because it's a doozy!!
Whilst the url is http $api_url = 'http://myapp.com/api.php';, as per everything else, the GAE app.yaml file serves all scripts as https as per:
- url: /(.+\.php)$
script: \1
secure: always
This means that the page that calls my function above is https so the api call doesn't like the request because of Cross-orgin source sharing.
The solution was to simply change the $api_url to be https.
I want to fetch data from Third_party API called BirdEye. I was using Core PHP Inbuilt Functions of CURL to fetch data, it was working fine, Now When I switched to Library I am bit confused because it doesn't gives me any response in return.
I have Downloaded Curl Libray from Here : Curl Library Download and Example
I tried to create a demo just to check my Library is working fine or not, it worked. Now If I fetch data from Bird-Eye Api I don't know It gives me nothing in response.
My Code is here:
<?php
defined('BASEPATH') OR exit('No direct script access allowed');
class Welcome extends CI_Controller {
public function index()
{
$this->load->library('curl');
$get_url = "https://api.birdeye.com/resources/v1/business/147802929307762?api_key=ApiKeyGoesHere";
echo $this->curl->simple_get($get_url, false, array(CURLOPT_USERAGENT => true));
echo $this->curl->error_code;
$this->load->view('welcome_message');
}
}
I don't know where I am going wrong I am passing all the required parameters to the Api and when I try to echo error code it gives me 22. I even searched on birdeye documentation but nothing found.
Link to Api Documentation is : Link to BirdEye Api Documentation
So according to the BirdEye API your cURL script should be like the following:
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, "https://api.birdeye.com/resources/v1/business/businessId ");
curl_setopt($ch, CURLOPT_RETURNTRANSFER, TRUE);
curl_setopt($ch, CURLOPT_HEADER, FALSE);
curl_setopt($ch, CURLOPT_HTTPHEADER, array(
"Content-Type: application/json",
"Accept: application/json"
));
$response = curl_exec($ch);
curl_close($ch);
Now, when I'm comparing your library usage code to the example above, I see you're missing the definitions of several options.
Before adding those options to your code, try to follow this part:
In the example they're not using the APIKEY, but when you do use it, you might need to pass it as a parameter and not in the get_url variable.
Which means:
$get_url = "https://api.birdeye.com/resources/v1/business/147802929307762";
echo $this->curl->simple_get($get_url, array('api_key' => 'YourApiKeyGoesHere'), array(..));
If it still doesn't work, try to add the options to your code:
$this->load->library('curl');
$get_url = "https://api.birdeye.com/resources/v1/business/147802929307762?api_key=ApiKeyGoesHere";
echo $this->curl->simple_get($get_url, false, array(CURLOPT_USERAGENT => true, CURLOPT_RETURNTRANSFER => TRUE, CURLOPT_HEADER => FALSE, CURLOPT_HTTPHEADER => array("Content-Type: application/json", "Accept: application/json")));
echo $this->curl->error_code;
$this->load->view('welcome_message');
I'm setting up a Soap service using PHP's SoapServer. No matter what I do I get "rpc:ProcedureNotPresentProcedure not present."
I'm using curl to post to it. It looks like this.
$payload = $data['xml'];
try {
$soap = curl_init('http://localhost/Connector/index.php');
curl_setopt_array($soap, array (
CURLOPT_CONNECTTIMEOUT => 120,
CURLOPT_TIMEOUT => 120,
CURLOPT_RETURNTRANSFER => TRUE,
CURLOPT_SSL_VERIFYPEER => FALSE,
CURLOPT_SSL_VERIFYHOST => FALSE,
CURLOPT_POST => TRUE
));
curl_setopt_array($soap, array (
CURLOPT_POSTFIELDS => $payload,
CURLOPT_HTTPHEADER => array (
'Content-Type: text/xml; charset=utf-8',
'Content-Length: ' . strlen($payload)
)
));
$response = curl_exec($soap);
The $payload variable contains the xml that looks like this.
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<ns2:Envelope xmlns:ns2="http://www.w3.org/2003/05/soap-envelope" xmlns:ns3="http://localhost/Connector/">
<ns2:Body>
<ns3:addNewAccount>
<systemData>
<id>QWQ</id>
</systemData>
<customerData>
<id>666</id>
<name>ACME UNLIMITED</name>
<billCycleDay>1</billCycleDay>
</customerData>
</ns3:addNewAccount>
</ns2:Body>
</ns2:Envelope>
My Soap Server looks like this.
<?php
$soapoptions = array (
'classmap' => ConnectorService::$classmap,
);
$soapoptions['cache_wsdl'] = WSDL_CACHE_NONE;
$soapoptions['trace'] = TRUE;
file_put_contents('/tmp/debug', print_r(file_get_contents('php://input'), TRUE), FILE_APPEND);
$connectorService = new \SoapServer("/ConnectorService/wsdl/connector.wsdl", $soapoptions);
$connectorService->setClass("ConnectorService");
file_put_contents('/tmp/debug', print_r($connectorService->getFunctions(), TRUE), FILE_APPEND);
$connectorService->handle();
I'm getting the xml in the request, it gets written to the /tmp/debug file, as does the functions available (addNewAccount).
The ConnectorService class looks like this.
class ConnectorService implements AccountInterface
{
public static $classmap = array(
'addNewAccount'=>'addNewAccount'
);
public function addNewAccount($mixed = NULL)
{
$args = func_get_args();
$response = new AccountResponse();
$handler = new AddNewAccountHandler();
$result = $handler->process($args[0]);
// return the result
return $result->getSoapVar();
}
}
I can't for the life of me figure out why I'm getting "rpc:ProcedureNotPresentProcedure not present."
UPDATE
If I don't rely on php://input to provide the xml to the SoapServer, but rather I load xml from the filesystem and pass it to the SoapServer->handle() method, I'm getting it to work.
If I dump the contents of php://input, it does have the xml in it. So why doesn't SoapServer pick it up. As I understand it, if you don't provide a parameter to SoapServer->handle() it supposed to check php://input for the xml.
What would cause php://input to not work or for SoapServer to not be reading it?
I figured it out.
I've got a new development stack setup on VirtualBox with Ubuntu 14.04 and I didn't have the php-soap package installed. I don't know what this package provides, without it I was able to instantiate SoapServer and SoapClient and I was able to make calls to methods in my wsdl, but it didn't read php://input when I wanted to just throw xml at the Soap server.
So I installed php-soap
apt-get install php-soap
It installed php-auth-sasl php-http-request php-mail php-mail-mime php-net-dime php-net-smtp php-net-socket php-net-url php-soap
I think that php-http-request is probably the one that I really needed. But either way, that's what you need to do if you run into this goofy problem. Total durp problem that I spent way too much time noodling around with.
I'm using this library for Facebook graph API access within my codeigniter project:
http://www.haughin.com/code/facebook/
My web app uses the Facebook JS SDK to authenticate users client-side, then immediately after a login is completed the user's user-id and session object are sent to my server via an AJAX request. I want to make a call to the graph API from the server to receive the user's basic information, so I'm wondering if there's a way I can bypass the need to call the facebook->login() method to receive a session via a redirect from facebook? Anyone know how to do this?
I don't recommend the Facebook SDK at all. You have a lot more control if you do things yourself and it becomes a lot simpler. Just set up a cURL function like:
function curl($url, $request = 'GET'){
$ch = curl_init();
$curlopt = array(
CURLOPT_URL => $url,
CURLOPT_CUSTOMREQUEST => $request,
CURLOPT_CONNECTTIMEOUT => 10,
CURLOPT_RETURNTRANSFER => true,
CURLOPT_TIMEOUT => 60,
CURLOPT_USERAGENT => 'facebook-php-2.0',
);
curl_setopt_array($ch, $curlopt);
$response = curl_exec($ch);
if($response === false)
trigger_error(curl_error($ch));
curl_close($ch);
return $response;
}
And then a Facebook api function like:
function fb_api($url, $access_token = false, $request = 'GET'){
$url = 'https://graph.facebook.com/'.$url;
if($access_token)
$url .= (strstr($url, '?') ? '&' : '?').'access_token='.$access_token;
return json_decode(curl($url, $request), true);
}
Then you can make your request to the graph api like:
fb_api('me', $access_token);
If, for somehow you dont have curl installed, you always can use my Proxy library : http://codeigniter.com/forums/viewthread/186250/