PHP - SOAP request - nest xml as param? - php

I need to make the structure of my XML SOAP request to look like following:
<?xml version="1.0" encoding="UTF-8"?>
<SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/" xmlns:ns1="http://www.fines.pl/api/contract">
<SOAP-ENV:Body>
<ns1:newApplicationRequest>
<user_login>XYZ</user_login>
<user_password>XYZ</user_password>
<contract>
<?xml version="1.0" encoding="UTF-8"?>
<sof:Contract xmlns:s="http://www.fines.pl/simple" xmlns:sof="http://www.fines.pl/sof" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.fines.pl/sof model.xsd ">
<product>
<prefix>MOP</prefix>
</product>
<participants>
<customers>
<main_borrower>
<personal_data>
<pesel>85050949761</pesel>
<firstname>Anna</firstname>
<lastname>Test</lastname>
<firstname_father></firstname_father>
<firstname_mother></firstname_mother>
<secondname />
<sex>female</sex>
</personal_data>
<contact_data>
<addresses>
<address>
<type>registered</type>
<street_name>Grunwaldzka</street_name>
<block_number>11</block_number>
<flat_number>5</flat_number>
<postal_code>80-100</postal_code>
<city>GdaƄsk</city>
</address>
</addresses>
<phones_mobile>
<phone_mobile>
<type>personal</type>
<number>602200300</number>
</phone_mobile>
</phones_mobile>
</contact_data>
<incomes>
<income>
<type>employment</type>
<main_income>true</main_income>
<fixed_term_contract>false</fixed_term_contract>
<paychecks>
<paycheck>
<amount_net>
<amount>1444.00</amount>
<currency>PLN</currency>
</amount_net>
<type>base</type>
</paycheck>
</paychecks>
</income>
</incomes>
<household_pointer>/households.0</household_pointer>
</main_borrower>
</customers>
</participants>
</sof:Contract></contract></ns1:newApplicationRequest></SOAP-ENV:Body></SOAP-ENV:Envelope>
I've set my $params variable to contain user_login and user_password elements with their respective values, but I have no idea how may I set this contract param with required content.
Providing $contract variable with XML code (which i thought may be a workaround) poop the Fatal error: Uncaught SoapFault exception: [xml_structure] String could not be parsed as XML error.
Would be grateful for explaining how could this be done.

You have declared <?xml?> twice , one on the first line and second on the eight. That's the only error I see in the xml side of things.

Related

replace an invalid URI in the .xml file

how can i replace an invalid URI in xml file, i cannot parse the xml file because it gives an invalid URI error while trying to parse the file. How can i read the contents of the .xml file into a string so that the invalid URI can be replaced.
<?xml version="1.0" encoding="utf-8"?>
<soap:Envelope xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">
<soap:Body>
<Submit xmlns="http://localhost/....">
<Order>
<Components>
<Component>
<ocode> ABC</ocode>
</Component>
</Components>
</Order>
</Submit>
</soap:Body>
</soap:Envelope>
If you just want the content, use SimpleXML and XPath to fetch the body contents...
$xml=simplexml_load_file("NewFile.xml");
$content = $xml->xpath("//soap:Body/*");
echo $content[0]->Order->asXML();
will give...
<Order>
<Components>
<Component>
<ocode> ABC</ocode>
</Component>
</Components>
</Order>
Not sure what the namespace http://localhost/.... is supposed to be, but it should be a valid URI - even if it is http://localhost.
Edit:
To try and fix the URI, you can read the file to a string first and then replace the invalid string with a valid one...
$data = file_get_contents("NewFile.xml");
$data = str_replace("http://localhost/....", "http://localhost", $data);
$xml=simplexml_load_string($data);
Or you could also try removing all of the attributes...
$data = preg_replace("/<Submit.*?>/", "<Submit>", $data);

Prestashop webservice API creating cart rules

Have been trying to create a cart rule using Prestashop web-service with no luck.
Tried this https://github.com/PrestaShop/PrestaShop-webservice-lib/blob/master/examples/Create.php (with cart_rules value replaced away from customers).
But I always get the same error: Property CartRule->name is empty.
Request:
<?xml version="1.0" encoding="UTF-8"?>
<prestashop xmlns:xlink="http://www.w3.org/1999/xlink">
<cart_rule>
<id></id>
<id_customer>1</id_customer>
<date_from>2017-09-05 13:00:00</date_from>
<date_to>2020-06-30 13:00:00</date_to>
<description>1</description>
<quantity>1</quantity>
<quantity_per_user>1</quantity_per_user>
<priority>1</priority>
<partial_use>1</partial_use>
<code>11111111111111111111111111111111111111111111111111</code>
<minimum_amount>1</minimum_amount>
<minimum_amount_tax>1</minimum_amount_tax>
<minimum_amount_currency>1</minimum_amount_currency>
<minimum_amount_shipping>1</minimum_amount_shipping>
<country_restriction>1</country_restriction>
<carrier_restriction>1</carrier_restriction>
<group_restriction>1</group_restriction>
<cart_rule_restriction>1</cart_rule_restriction>
<product_restriction>1</product_restriction>
<shop_restriction>1</shop_restriction>
<free_shipping>1</free_shipping>
<reduction_percent>151</reduction_percent>
<reduction_amount>1</reduction_amount>
<reduction_tax>1</reduction_tax>
<reduction_currency>1</reduction_currency>
<reduction_product>1</reduction_product>
<reduction_exclude_special>1</reduction_exclude_special>
<gift_product>1</gift_product>
<gift_product_attribute>1</gift_product_attribute>
<highlight>1</highlight>
<active>1</active>
<date_add>1</date_add>
<date_upd>1</date_upd>
<name>TEST NAME</name>
</cart_rule>
</prestashop>
Response:
<?xml version="1.0" encoding="UTF-8"?>
<prestashop xmlns:xlink="http://www.w3.org/1999/xlink">
<errors>
<error>
<code><![CDATA[84]]></code>
<message><![CDATA[Validation error: "Property CartRule->name is empty."]]></message>
</error>
</errors>
</prestashop>
The cart rule name is a multi-language field, so you have to specify the language id.
Try this:
<cart_rule>
...
<name>
<language id="1">TEST NAME</language>
</name>
...
</cart_rule>
Obviously you have to use the right ID language

simplexml_load_file() giving error: Warning: simplexml_load_file()

I have XML document captured from a link and anytime I use simplexml_load_file(), it gives me an error saying *Warning: simplexml_load_file(): https://kga-dev.mirakl.net/api/shops?:1: parser error : Start tag expected, '<' not found in C:\wamp\www\merchants\get_merchants.php on line 6*
This is a part of my xml file
<body>
<shops>
<shop>...</shop>
<shop>
<approval_delay xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:nil="true"/>
<approval_rate xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:nil="true"/>
<order_messages_response_delay xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:nil="true"/>
<banner xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:nil="true"/>
<billing_info>
<bank_city xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:nil="true"/>
<bank_name xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:nil="true"/>
<bank_street xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:nil="true"/>
<zip_code xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:nil="true"/>
<bic xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:nil="true"/>
<iban xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:nil="true"/>
<owner xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:nil="true"/>
</billing_info>
And this is my simple php code
<?php
$apiLink = "https://kga-dev.mirakl.net/api/shops?";
$xml=simplexml_load_file($apiLink);
print_r($xml);
//echo $xml->shop_id;
?>
The solution for this problem is, that the API serves a JSON encoded string instead of an XML string. So the delivered content can not be parsed with SimpleXML. Try to get it with the following example
$content = file_get_contents($apiLink);
$data = json_decode($content);
In this case $data should be an object or array with all the data the api delivers.
Are you sure that this is the same XML as returned to the script? Note that you are not calling :1 - I cannot check as it requires authorization, yet in the example given by you there is no error up to line 7 so it would mean that possibly something else is returned as the code below works:
<?php
$s = '<body>
<shops>
<shop>...</shop>
<shop>
<approval_delay xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:nil="true"/>
<approval_rate xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:nil="true"/>
<order_messages_response_delay xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:nil="true"/>
<banner xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:nil="true"/>
</shop>
</shops>
</body>';
$xml=simplexml_load_string($s);
print_r($xml);
?>
Is not the authorization the problem your end? I need to authorize to your webservice: you handle that in a different way for your IP or something like that?
Your Code
<approval_rate xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:nil="true"/>
use single quotes
<?php
echo "<order_messages_response_delay xmlns:xsi='http://www.w3.org/2001/XMLSchema-instance' xsi:nil='true'/>";
?>

SoapClient XML return string with simpleXML

So I'm getting an xml file back from a soap service (of which I have no control over). It's returning back an xmlns which is causing simpleXML issues. I'm running a str_replace to get rid of that issue, however now simpleXML just returns an empty object. XML structure appears to be fine, no errors just an empty object.
$xmlString = $client->__getLastResponse();
$feed = str_replace(' xmlns="LMSWebservice"', '', $xmlString);
$sData= simplexml_load_string($feed);
print_r($sData);
Returns: SimpleXMLElement Object()
XML source before str replace is:
<?xml version="1.0" encoding="utf-8"?>
<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<soap:Body>
<GetUserInternalIDByPersonalIDResponse xmlns="LMSWebservice">
<GetUserInternalIDByPersonalIDResult>
<Response xmlns="">
<Timestamp date="24/10/2013" time="04:27:37" />
<User>
<UserInternalID>4907</UserInternalID>
</User>
</Response>
</GetUserInternalIDByPersonalIDResult>
</GetUserInternalIDByPersonalIDResponse>
</soap:Body>
</soap:Envelope>
After str replace:
<?xml version="1.0" encoding="utf-8"?>
<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<soap:Body>
<GetUserInternalIDByPersonalIDResponse>
<GetUserInternalIDByPersonalIDResult>
<Response xmlns="">
<Timestamp date="24/10/2013" time="04:27:37" />
<User>
<UserInternalID>4907</UserInternalID>
</User>
</Response>
</GetUserInternalIDByPersonalIDResult>
</GetUserInternalIDByPersonalIDResponse>
</soap:Body>
</soap:Envelope>
Any help would be greatly appreciated, this is driving me crazy!
----So if I don't get rid of the namespace attribute I get this error message:
Warning: simplexml_load_string() [function.simplexml-load-string]: Entity: line 1: parser warning : xmlns: URI LMSWebservice is not absolute in serviceTest2.php on line 16
Warning: simplexml_load_string() [function.simplexml-load-string]: LSchema"><soap:Body><GetUserInternalIDByPersonalIDResponse xmlns="LMSWebservice" in serviceTest2.php on line 16
Warning: simplexml_load_string() [function.simplexml-load-string]: ^ in serviceTest2.php on line 16
If I try using xPath to get at UserInternalID it returns an empty array. If what you're saying is correct and this is going into simpleXML correctly, then how do I access the UserInternalID node? Sorry, this is the first time using simpleXML and this is just perplexing me.
So just tried changing the NS
$feed = str_replace('xmlns="LMSWebservice"', 'xmlns="ns:LMSWebservice"', $xmlString);
which goes in without errors.
I tried this for the xPath
$ID = $sData->xpath('UserInternalID');
I understand this is probably completely wrong, but I haven't tried much else with this as it didn't seem to be going into simpleXML correctly in the first place. :/
So I've used
$ID = $sData->xpath('//UserInternalID');
echo $ID[0];
Which works perfectly. Thank you for all your help!
Through the extensive comments and your last edit finally the actual cause of your problem could be revealed, the xpath expression is wrong:
$ID = $sData->xpath('UserInternalID');
Wrong with it is the path, this matches no elements. Instead you could use:
$ID = (string) $xml->xpath('//UserInternalID')[0];
Or more verbose:
$ID = (string) $xml->xpath('//Response/User/UserInternalID')[0];
Key point here is that you write the correct path to the element you would like to query for.
Complete usage example:
<?php
/**
* SoapClient xml return string with simpleXML
*
* #link http://stackoverflow.com/q/19556414/367456
*/
$response = <<<RESPONSE
<?xml version="1.0" encoding="utf-8"?>
<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<soap:Body>
<GetUserInternalIDByPersonalIDResponse xmlns="LMSWebservice">
<GetUserInternalIDByPersonalIDResult>
<Response xmlns="">
<Timestamp date="24/10/2013" time="04:27:37" />
<User>
<UserInternalID>4907</UserInternalID>
</User>
</Response>
</GetUserInternalIDByPersonalIDResult>
</GetUserInternalIDByPersonalIDResponse>
</soap:Body>
</soap:Envelope>
RESPONSE;
$restore = libxml_use_internal_errors(TRUE);
$xml = simplexml_load_string($response);
libxml_use_internal_errors($restore);
echo $xml->xpath('//Response/User/UserInternalID')[0];
Output:
4907
Online Demo: https://eval.in/57149
$doc = new DOMDocument();
libxml_use_internal_errors(true);
$doc->loadHTML($response);
libxml_clear_errors();
$xml = $doc->saveXML($doc->documentElement);
$xml = simplexml_load_string($xml);
Use this helped me in a big way.

How to add an arbitrary namespace with PHP SoapClient?

How does one add an arbitrary namespace using PHP SoapClient? The namespace does not actually get used in the request, but I think it is preventing my message from being properly consumed.
The WSDL is here : http://abr.business.gov.au/abrxmlsearchRPC/ABRXMLSearch.asmx?WSDL
The documentation for the particular message I want to send is here : http://abr.business.gov.au/abrxmlsearchRPC/(nye2ok45xc42vy552b15dx3t)/FormGenerator/ABRSearchByNameSimpleProtocol.aspx. I'm doing the SOAP request.
In the soap:Envelope, you'll notice a namespace called xmlns:types="http://abr.business.gov.au/ABRXMLSearchRPC/encodedTypes", and you'll also notice it's not used in the soap:Body.
The message I'm sending is : (newlines and indenting added for readability, authenticationGuid obfuscated for security)
<?xml version="1.0" encoding="UTF-8"?>
<SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/" xmlns:ns1="http://abr.business.gov.au/ABRXMLSearchRPC/" 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/" SOAP-ENV:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/">
<SOAP-ENV:Body>
<ns1:ABRSearchByNameSimpleProtocol>
<name xsi:type="xsd:string">company</name>
<postcode xsi:type="xsd:string"></postcode>
<legalName xsi:type="xsd:string">Y</legalName>
<tradingName xsi:type="xsd:string">Y</tradingName>
<NSW xsi:type="xsd:string">Y</NSW>
<SA xsi:type="xsd:string">Y</SA>
<ACT xsi:type="xsd:string">Y</ACT>
<VIC xsi:type="xsd:string">Y</VIC>
<WA xsi:type="xsd:string">Y</WA>
<NT xsi:type="xsd:string">Y</NT>
<QLD xsi:type="xsd:string">Y</QLD>
<TAS xsi:type="xsd:string">Y</TAS>
<authenticationGuid xsi:type="xsd:string">aaaa</authenticationGuid>
</ns1:ABRSearchByNameSimpleProtocol>
</SOAP-ENV:Body>
</SOAP-ENV:Envelope>
The response I get back is :
<?xml version="1.0" encoding="utf-8"?>
<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/" xmlns:soapenc="http://schemas.xmlsoap.org/soap/encoding/" xmlns:tns="http://abr.business.gov.au/ABRXMLSearchRPC/" xmlns:types="http://abr.business.gov.au/ABRXMLSearchRPC/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<soap:Body soap:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/">
<types:ABRSearchByNameSimpleProtocolResponse><ABRSearchByNameSimpleProtocolResult href="#id1" /></types:ABRSearchByNameSimpleProtocolResponse>
<types:Payload id="id1" xsi:type="types:Payload">
<Request href="#id2" />
<Response href="#id3" />
</types:Payload>
<types:ExternalRequest id="id2" xsi:type="types:ExternalRequest">
<ExternalRequestBody href="#id4" />
</types:ExternalRequest>
<types:Response id="id3" xsi:type="types:Response">
<DateRegisterLastUpdated xsi:type="xsd:dateTime">0001-01-01T00:00:00.0000000+11:00</DateRegisterLastUpdated>
<DateTimeRetrieved xsi:type="xsd:dateTime">2011-05-26T09:31:06.2949724+10:00</DateTimeRetrieved>
<ResponseBody href="#id5" />
</types:Response>
<types:ExternalRequestNameSearch id="id4" xsi:type="types:ExternalRequestNameSearch">
<AuthenticationGUID xsi:type="xsd:string" />
<Name xsi:type="xsd:string" />
<Filters href="#id6" />
</types:ExternalRequestNameSearch>
<types:ResponseException id="id5" xsi:type="types:ResponseException">
<ExceptionDescription xsi:type="xsd:string">The GUID entered is not recognised as a Registered Party.
Search GUID: </ExceptionDescription>
<ExceptionCode xsi:type="xsd:string">WebServices</ExceptionCode>
</types:ResponseException>
<types:ExternalRequestFilters id="id6" xsi:type="types:ExternalRequestFilters">
<NameType href="#id7" />
<Postcode xsi:type="xsd:string" />
<StateCode href="#id8" />
</types:ExternalRequestFilters>
<types:ExternalRequestFilterNameType id="id7" xsi:type="types:ExternalRequestFilterNameType">
<TradingName xsi:type="xsd:string">Y</TradingName>
<LegalName xsi:type="xsd:string">Y</LegalName>
</types:ExternalRequestFilterNameType>
<types:ExternalRequestFilterStateCode id="id8" xsi:type="types:ExternalRequestFilterStateCode">
<QLD xsi:type="xsd:string">Y</QLD>
<NT xsi:type="xsd:string">Y</NT>
<SA xsi:type="xsd:string">Y</SA>
<WA xsi:type="xsd:string">Y</WA>
<VIC xsi:type="xsd:string">Y</VIC>
<ACT xsi:type="xsd:string">Y</ACT>
<TAS xsi:type="xsd:string">Y</TAS>
<NSW xsi:type="xsd:string">Y</NSW>
</types:ExternalRequestFilterStateCode>
</soap:Body>
</soap:Envelope>
It looks like the consumer has completely disregarded the content of the message. The only thing I can see that is missing from the example is the types namespace, which is included in the response.
Thus, I'm thinking that if I can arbitrarily add the types namespace to the request, it may have better luck.
If anyone could tell me how to do that, or offer some other suggestion why the consumer ignores the values I've given in the request, that would be greatly appreciated.
Update: Extending SoapClient and overriding __doRequest() to add the namespace might actually be the solution, but I'd like a confirmation from someone who knows better. It should be noted that the content of SoapClient::getLastRequest() is generated before modifications made by __doRequest(), so any modifications made via __doRequest() may need to be observed via a tcp dump.
Example code for this is
class ABRSoapClient extends SoapClient {
function __doRequest($request, $location, $action, $version) {
$dom = new DOMDocument('1.0', 'UTF-8');
$dom->preserveWhiteSpace = false;
$dom->loadXML($request);
$dom->documentElement->setAttribute
('xmlns:types', 'http://abr.business.gov.au/ABRXMLSearchRPC/encodedTypes');
$request = $dom->saveXML();
error_log('Request in class:'.$request);
return parent::__doRequest($request, $location, $action, $version);
}
}

Categories