Send an array from Python to PHP - php

I am trying to consume with Python a WSDL created in PHP.
Fragment of the Service:
require_once('lib/nusoap.php');
date_default_timezone_set('America/Mexico_City');
function Sum($numbers){
return array_sum($numbers);
}
...
Client:
from suds.client import Client
def wsarchivo():
url = "http://localhost/PracticeSumArray/server.php?wsdl"
client = Client(url)
res = client.service.Sum([1,2,3])
print(res)
wsarchivo()
But when running it does not work to send the parameter in this way, unlike doing it with a client in PHP that the way to send the parameter would be 'numbers' => array (1, 2, 3) and works correctly .

I could solve my problem, I leave it here in case someone else is useful, the first mistake I made was to declare the input parameter as a whole xsd:int, so what I did was declare it as SOAP-ENC:Array on the server in PHP:
$server->register(
'Suma',
array('numbers' => 'SOAP-ENC:Array'),
array('return' => 'xsd:int'),
$ns
);
Now in the Python client I used the factory.create() method of the suds client to declare a variable with the type SOAP-ENC:Array
from suds.client import Client
def wsarchivo():
client = Client("http://localhost/PracticaSumaArray/server.php?wsdl")
request = client.factory.create('SOAP-ENC:Array')
request.numbers = [1,2,3]
res = client.service.Suma(request)
print(res)
wsarchivo()
When executing:
Output:
6

Related

Django 1.8 (on Python 3) - Make a SOAP request with pysimplesoap

Since one week I'm trying to retrieve some datas from a Dolibarr application including Dolibarr's webservices.
In few words, I'm trying to make a soap request to retrieve user's informations.
At first, I tried to instantiate SoapClient with 'wsdl' and 'trace' parameters, in vain.. SoapClient's object was never been create !
Secondly, I made a made a classical SoapClient's object without 'wsdl', however I used : 'location', 'action', 'namespace', 'soap_ns', 'trace'; It was a success (I think) but It did't work when I called Client's call method.. My dolibarrkey did't match my key on the webservice, but their keys are the same (copy & paste).
For more explanations take a look to dolibarr api (to retrieve datas) with the xlm dataformat.
Link to getUser web service (click on getUser to show parameters):
http://barrdoli.yhapps.com/webservices/server_user.php
Link to xml dataformat (for the SOAP request maybe):
http://barrdoli.yhapps.com/webservices/server_user.php?wsdl
from pysimplesoap.client import SoapClient, SoapFault
import sys
def listThirdParties():
# create a simple consumer
try:
# client = SoapClient(
# "[MyAppDomain]/webservices/server_user.php")
# print(client)
# client = SoapClient(wsdl="[MyAppDomain]/webservices/server_user.php?wsdl", trace=True)
client = SoapClient(
location = "[myAppDomain]/webservices/server_user.php",
action = '[myAppDomain]/webservices/server_user.php?wsdl', # SOAPAction
namespace = "[myAppDomain]/webservices/server_user.php",
soap_ns='soap',
trace = True,
)
print("connected bitch")
except:
print("error connect")
message = dict()
message['use'] = "encoded"
message["namespace"] = "http://www.dolibarr.org/ns/"
message["encodingStyle"] = "http://schemas.xmlsoap.org/soap/encoding/"
message["message"] = "getUserRequest"
parts = dict()
auth = dict()
auth['dolibarrkey'] = '********************************'
auth['sourceapplication'] = 'WebServicesDolibarrUser'
auth['login'] = '********'
auth['password'] = '********'
auth['entity'] = ''
parts["authentication"] = auth
parts["id"] = 1
parts["ref"] = "ref"
parts["ref_ext"] = "ref_ext"
message["parts"] = parts
# call the remote method
response = client.call(method='getUser', kwargs=message)
# extract and convert the returned value
# result = response.getUser
# return int(result)
print(response)
pass
I've "BAD_VALUE_FOR_SECURITY_KEY" into a xlm response, I think it's my request which made with a bad xml dataformat..
shell response :
-------- RESPONSE -------
b'<?xml version="1.0" encoding="UTF-8"?><SOAP-ENV:Envelope SOAP-ENV:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/" xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:SOAP-ENC="http://schemas.xmlsoap.org/soap/encoding/" xmlns:tns="http://www.dolibarr.org/ns/"><SOAP-ENV:Body><ns1:getUserResponse xmlns:ns1="http://barrdoli.yhapps.com/webservices/server_user.php"><result xsi:type="tns:result"><result_code xsi:type="xsd:string">BAD_VALUE_FOR_SECURITY_KEY</result_code><result_label xsi:type="xsd:string">Value provided into dolibarrkey entry field does not match security key defined in Webservice module setup</result_label></result><user xsi:nil="true" xsi:type="tns:user"/></ns1:getUserResponse></SOAP-ENV:Body></SOAP-ENV:Envelope>'
I really want to know how should I do to make a working soap request with a clean xlm dataformat.
Thanks
Did you try to setup WebService Security (WSSE) with client object? Following examples are taken from https://code.google.com/p/pysimplesoap/wiki/SoapClient
client['wsse:Security'] = {
'wsse:UsernameToken': {
'wsse:Username': 'testwservice',
'wsse:Password': 'testwservicepsw',
}
}
or try to Setup AuthHeaderElement authentication header
client['AuthHeaderElement'] = {'username': 'mariano', 'password': 'clave'}

Rails send four backslashes using Net::HTTP

My rails application need to send some data to a php application, which expects a POST call.
I use the folowing code:
uri = URI.parse(apiUrl)
req = Net::HTTP::Post.new(uri.to_s, initheader = {'Content-Type' =>'application/json'})
req.basic_auth(api_key, token)
req.set_form_data({"action" => action, "data" => data})
http = Net::HTTP.new(uri.host, uri.port)
response = http.request(req)
Where data is a hash converted to json:
data = {
:key1 => val1,
:key2 => val2
}.to_json
(it is a nested hash, i.e. some values are hash as well)
My problem is that the php application receives 4 backslashes before each quotation mark:
$data_json = $_POST['data'];
error_log($data_json);
and in error log I see:
'{\\\\"key1\\\\":val1,\\\\"key2\\\\":\\\\"val2\\\\"}'
Looks like rails add one of them, but even if I remove it and replace it with the following code:
a.gsub!(/\"/, '\'')
I still get many backslashes inside the php application, hence cannot convert the string to array.
Any idea??
By using set_form_data net/http is POSTing the form as urlencoded. Its NOT posting your request body as pure JSON.
If you want to POST raw JSON you will need to follow a pattern like:
uri = URI('https://myapp.com/api/v1/resource')
req = Net::HTTP::Post.new(uri, initheader = {'Content-Type' =>'application/json'})
req.body = {param1: 'some value', param2: 'some other value'}.to_json
res = Net::HTTP.start(uri.hostname, uri.port) do |http|
http.request(req)
end

Python WSDL function parameters are not accepted

I can send function arguments to a SOAP client in PHP like this (searchLinks is a method name):
$client = new SoapClient("https://linksearch.api.cj.com/wsdl/version2/linkSearchServiceV2.wsdl", array('trace'=> true));
$results = $client->searchLinks(array("developerKey" => $developerKey,
"token" => '',
"websiteId" => $websiteId,
"advertiserIds" => 'joined'));
If I want to do the same thing in Python, how can I do this? This is the present code:
server=WSDL.Proxy(url)
results=server.searchLinks({'developerkey':dev_key,'token':'','websiteId':website_id,'advertiserIds':'joined'})
When I try to run this Python script, it throws errors. Why is it not taking function parameters like in PHP?
Which library are you using,
Assuming that you are using SOAPpy, You can do .
#!/usr/bin/python
import SOAPpy
url= 'https://linksearch.api.cj.com/wsdl/version2/linkSearchServiceV2.wsdl'
proxy = SOAPpy.WSDL.Proxy(url)
results=proxy.searchLinks({'developerkey': 'dev_key','token':'','websiteId': 'website_id','advertiserIds':'joined'})

Read long value from webservice using SoapClient

I'm writing a soap consumer in PHP for a ws written in Java (Jax ws). The webservice exports a function listRooms() that returns an array of the complex data type Room which contains an id (64 bit long) and a description (string). Now whenever I consume the webservice using SoapClient, the id is converted to float (as there are no 64 bit integers in PHP) and I want to avoid it. As I will need the room id to consume other web services I would rather avoid this implicit conversion to float, keeping it in a string.
Does anyone know how to solve this problem?
This might help:
The long overflows because ext/soap maps it to an int, and you're on a 32bit arch. You can easily fix that problem by using a custom type mapper to override the internal handling of {http://www.w3.org/2001/XMLSchema }long:
function to_long_xml($longVal) {
return '<long>' . $longVal . '</long>';
}
function from_long_xml($xmlFragmentString) {
return (string)strip_tags($xmlFragmentString);
}
$client = new SoapClient('http://acme.com/products.wsdl', array(
'typemap' => array(
array(
'type_ns' => 'http://www.w3.org/2001/XMLSchema',
'type_name' => 'long',
'to_xml' => 'to_long_xml',
'from_xml' => 'from_long_xml',
),
),
));
Also check to see exactly what you get back from the SOAP call, as per the manual add 'trace' and use getLastRequest:
<?php
$client = SoapClient("some.wsdl", array('trace' => 1));
$result = $client->SomeFunction();
echo "REQUEST:\n" . $client->__getLastRequest() . "\n";
?>
Other way to do it, is just using the float() function before the data to sent as a long type.
In the example below I'm use a stdclass object to sent as a parameter:
<?php
if ($index == "Your_longtype_Field"){
$a->$index = (float) $value;
} else {
$a->$index = $value;
}
?>

How to recreate this PHP code in Python?

I've found a PHP script that lets me do what I asked in this SO question. I can use this just fine, but out of curiosity I'd like to recreate the following code in Python.
I can of course use urllib2 to get the page, but I'm at a loss on how to handle the cookies since mechanize (tested with Python 2.5 and 2.6 on Windows and Python 2.5 on Ubuntu...all with latest mechanize version) seems to break on the page. How do I do this in python?
require_once "HTTP/Request.php";
$req = &new HTTP_Request('https://steamcommunity.com');
$req->setMethod(HTTP_REQUEST_METHOD_POST);
$req->addPostData("action", "doLogin");
$req->addPostData("goto", "");
$req->addPostData("steamAccountName", ACC_NAME);
$req->addPostData("steamPassword", ACC_PASS);
echo "Login: ";
$res = $req->sendRequest();
if (PEAR::isError($res))
die($res->getMessage());
$cookies = $req->getResponseCookies();
if ( !$cookies )
die("fail\n");
echo "pass\n";
foreach($cookies as $cookie)
$req->addCookie($cookie['name'],$cookie['value']);
Similar to monkut's answer, but a little more concise.
import urllib, urllib2
def steam_login(username,password):
data = urllib.urlencode({
'action': 'doLogin',
'goto': '',
'steamAccountName': username,
'steamPassword': password,
})
request = urllib2.Request('https://steamcommunity.com/',data)
cookie_handler = urllib2.HTTPCookieProcessor()
opener = urllib2.build_opener(cookie_handler)
response = opener.open(request)
if not 200 <= response.code < 300:
raise Exception("HTTP error: %d %s" % (response.code,response.msg))
else:
return cookie_handler.cookiejar
It returns the cookie jar, which you can use in other requests. Just pass it to the HTTPCookieProcessor constructor.
monkut's answer installs a global HTTPCookieProcessor, which stores the cookies between requests. My solution does not modify the global state.
I'm not familiar with PHP, but this may get you started.
I'm installing the opener here which will apply it to the urlopen method. If you don't want to 'install' the opener(s) you can use the opener object directly. (opener.open(url, data)).
Refer to:
http://docs.python.org/library/urllib2.html?highlight=urllib2#urllib2.install_opener
import urlib2
import urllib
# 1 create handlers
cookieHandler = urllib2.HTTPCookieProcessor() # Needed for cookie handling
redirectionHandler = urllib2.HTTPRedirectHandler() # needed for redirection
# 2 apply the handler to an opener
opener = urllib2.build_opener(cookieHandler, redirectionHandler)
# 3. Install the openers
urllib2.install_opener(opener)
# prep post data
datalist_tuples = [ ('action', 'doLogin'),
('goto', ''),
('steamAccountName', ACC_NAME),
('steamPassword', ACC_PASS)
]
url = 'https://steamcommunity.com'
post_data = urllib.urlencode(datalist_tuples)
resp_f = urllib2.urlopen(url, post_data)

Categories