How do I access XML-RPC data from PHP? - php

A remote server is POSTing XML to my server via RPC. I can see the XML in my Apache logs when I turn on mod security, but I can't access the XML from my PHP script. It's supposed to be a POST request, but the $_POST array is empty.
My understanding is that RPC is supposed to call my function with the data, but that doesn't seem to be happening.
This ridiculously simple script should write the XML to a log file, yet it does nothing:
include_once('xmlrpc/xmlrpc.inc');
include_once('xmlrpc/xmlrpcs.inc');
function ImportOrders($xml)
{
$FH=fopen('Log/In.txt','a');
fwrite($FH,'Package recieved:'.print_r($xml,true)."\n");
// set appropriate response code
$response = 0; // see defined response codes for this application
// send success or failure response code
if($response == 0)
return new xmlrpcresp(new xmlrpcval($response, "string"));
else
return new xmlrpcresp(0, $response, $error_message);
}
$Server = new xmlrpc_server(
array("ImportOrders"=>array("function"=>"ImportOrders")
)
);
They are sending me this:
<?xml version="1.0" encoding="ISO-8859-1" ?>
<methodCall>
<methodName>ImportOrders</methodName>
<params>
<param>
<value><int>2</int></value>
</param>
<param>
<value><struct>
<member><name>order_0</name>
<value><struct>
<member><name>order_id</name>
....
Why isn't my function being called?!?

Got it! Apparently the data is in "$GLOBALS['HTTP_RAW_POST_DATA']".
require 'kd_xmlrpc.php';
$xmlrpc_request = XMLRPC_parse($GLOBALS['HTTP_RAW_POST_DATA']);
$methodName = XMLRPC_getMethodName($xmlrpc_request);
$params = XMLRPC_getParams($xmlrpc_request);
ImportOrders($params);
function ImportOrders($params)
{
$FH=fopen('Log/In.txt','a');
fwrite($FH,'OrderDataRes has been loaded.'."\n");
fwrite($FH,'$params: '.print_r($params,true)."\n");
}
I'm also using a differnt library, from:
http://www.keithdevens.com/software/xmlrpc/source.php

Related

SoapClient replaces tags (inside some tag) to htmlentities

The issue: I am sending SOAP request to 3rd-party server and inside one of my tags I have all "<" ">" replaced with html-entities < >
The info:
Lets say I have this class(simplified and pseudocoded for clarity):
Class SoapSender {
private $session = 'sessionHash';
private $soap = new SoapClient(/* settings */);
public function create() {
try {
$agr = [];
$agr['SessionToken'] = $this->session;
$agr['Document'] = $this->prepareDocument();
$request = $this->soap->createRequest($agr); // 3rd-party call
} catch (SoapFault $f) {
/* handle exception */
}
}
The documentation of 3rd-party says that <Document> should be XML string so I do this:
private function prepareDocument() {
$arr = [
/* Create all sub-tags of <Document> */
];
$xml = Formatter::make($arr, 'array')->toXml();
// this operations required for valid structure
$xml = str_replace(array('<?xml version="1.0" encoding="utf-8"?>','<xml>','</xml>'), '', $xml);
$xml = str_replace(['Subject_1', 'Subject_2'], 'Subject', $xml);
$xml = str_replace(['Period_1', 'Period_2'], 'Period', $xml);
$xml = preg_replace('/Store_[1-9]/', 'Store', $xml);
return $xml;
Formatter is SoapBox/laravel-formatter.
Soo, when I send request and recieve response with errors I dump $this->soap->__getLastRequest() and see that:
<?xml version="1.0" encoding="UTF-8"?>
<SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/" xmlns:ns1="http://someurl.com">
<SOAP-ENV:Body><ns1:CreateRequest>
<Document>
<General><Product>Bread</Product><DateBeg>2016-04-04T00:00:00</DateBeg><DateEnd>2017-04-03</DateEnd><.....
...........blah-blah....
</Document>
<SessionToken>SessionTokeon</SessionToken></ns1:CreateRequest></SOAP-ENV:Body></SOAP-ENV:Envelope>
What I have so far: debuging prepareDocument says that I have valid xml string in utf-8 with all tags intact, so encoding them to html-entities happens on SOAP request. Only the Document tag gets encoded, others are ok.
All my other services that use same aproach but different 3rd-party works perfect. Sending this request (but decoded back to normal) by SOAP UI works as it should. All happens inside laravel project.
The issue again: I am sending request to 3rd-party server and inside one of my tags I have all "<" ">" replaced with html-entities < >
The question: What should I do to fix this issue?

Load the xml in php and return the data

i'm looking how to Load the XML file in PHP and Return the data not redirect. Preferably to hide the xml content from the end user as much as i can.
I've seen something like this, but i can not make it work, please if you can write out the complete code with a link example..
public function sendResponse($type,$cause) {
$response = '<?xml version="1.0" encoding="utf-8"?>';
$response .= '<response><status>'.$type.'</status>';
$response = $response.'<remarks>'.$cause.'</remarks></response>';
return $response;
}
....
....
header("Content-type: text/xml; charset=utf-8");
echo sendResponse($type,$cause);
Please help if you can.
Thank's in Advance,
SX
I'm not sure to understand your request, but first you can't call sendResponse() cause it's not a function but a method in a Class
You need to instantiate your class and after, call the method.
Example :
$yourObject = new YourClass();
$yourObject->sendResponse();
See the manual
For your case, see the manual for simpleXML and try that :
function sendResponse($type,$cause) {
$response = '<?xml version="1.0" encoding="utf-8"?>';
$response .= '<response><status>'.$type.'</status>';
$response = $response.'<remarks>'.$cause.'</remarks></response>';
return $response;
}
$type="type";
$cause="cause";
var_dump(simplexml_load_string(sendResponse($type,$cause)));
If your script is external, you can get it with file_get_contents
$xml = file_get_contents('http://yourTarget.com');
var_dump($xml);
You question misleads me to some extent, make sure if you want to load an external xml file and make your PHP code parse it. Try the following code
Assume the following is your xml content fo text.xml
<?xml version='1.0' encoding='UTF-8'?>
<note>
<to>Tove</to>
<from>Jani</from>
<heading>Reminder</heading>
<body>Don't forget me this weekend!</body>
</note>"
<-- PHP -->
$file = 'http://exmp.com/text.xml'; // give the path of the external xml file
if(!$xml = simplexml_load_file($file)) // this checks whether the file exists
exit('Failed to open '.$file); // exit when the path is wrong
print_r($xml); // prints the xml format in the form of array
your output will be this
SimpleXMLElement Object (
[to] => Tove
[from] => Jani
[heading] => Reminder
[body] => Dont forget me this weekend!
)
Hope this helps...

Implementing curl in ZF2

I am trying to establish a communication with two zf2 application via curl.The required response is in xml. So far I could establish the connection and xml is returned as response.
The problem
The problem is that,I can't iterate on my xml response.Whenever I var_dump and view source code of my $response->getContent,I get as
string(142) "<?xml version="1.0" encoding="UTF-8"?>
<myxml>
<login>
<status>success</status>
<Err>None</Err>
</login>
</myxml>
"
and when I simply var_dump my $response,I get an object(Zend\Http\Response)#440.
simplexml_load_string($response->getContent()) gives me a blank page.
Also print $data->asXML() gives me Call to a member function asXML() on a non-object error.What am I doing wrong here?
Curl request action
$request = new \Zend\Http\Request();
$request->getHeaders()->addHeaders([
'Content-Type' => 'application/x-www-form-urlencoded; charset=UTF-8'
]);
$request->setUri('http://localhost/app1/myaction');
$request->setMethod('POST'); //uncomment this if the POST is used
$request->getPost()->set('curl', 'true');
$request->getPost()->set('email', 'me#gmail.com');
$request->getPost()->set('password', '2014');
$client = new Client;
$client->setAdapter("Zend\Http\Client\Adapter\Curl");
$response = $client->dispatch($request);
var_dump($response);//exit;
//$response = simplexml_load_string($response->getContent());
//echo $response;exit;
return $response;
Curl response action
$php_array=array(
'login'=>array(
'status'=>'failed','Err'=>'Unauthorised Access'
)
);
$Array2XML=new \xmlconverter\Arraytoxml;
$xml = $Array2XML->createXML('myxml', $php_array);
$xml = $xml->saveXML();
//echo $xml;exit;
$response = new \Zend\Http\Response();
$response->getHeaders()->addHeaderLine('Content-Type', 'text/xml; charset=utf-8');
$response->setContent($xml);
return $response;
The Array2XML can be found here
Any ideas?
when I simply var_dump my $response,I get an object(Zend\Http\Response)#440
This is correct and it tells you the type of $response.
simplexml_load_string($response->getContent()) gives me a blank page.
This is correct because despite this function can return a value expressible to an empty string, it does not create any output on it's own and therefore the blank page is to be expected.
Any ideas?
First of all you should formulate a proper problem statement with your question. All you say so far therein is to be expected, so your question is not clear at best.
Second you need to do proper error handling and do some safe programming:
$buffer = $response->getContent();
if (!is_string($buffer) || !strlen($buffer) || $buffer[0] !== '<') {
throw new RuntimeException('Need XML string, got %s', var_export($buffer, 1));
}
$xml = simplexml_load_string($buffer);
if (false === $xml) {
throw new RuntimeException('Unable to parse response string as XML');
}
Which is: For every parameter you get, validate it. For every function or method result you receive check the post-conditions. Before you call a function or method, check the pre-conditions for each parameter.
Log errors to file and handle uncaught exceptions.
As an additional idea: Drop the use of the array to XML function and replace it with a library that is maintained. In your case it's perhaps easier to just use SimpleXML your own to create the XML.

XML signature differences between HEREDOC and DOMDocument

An API client I have developed works with XML messages and the messages are signed according to the XML Signature Syntax and Processing specification. After a long struggle, I finally got the signatures working.
At this moment I am building the XML with HEREDOC (simply php strings) and with a cleanup, I'd like to create the XML with DOMDocument directly. However, this causes the message to be invalidated by the server.
This is the current setup (server accepts this message when signed):
$xml = <<<EOT
<?xml version="1.0" encoding="UTF-8"?>
<DirectoryReq xmlns="http://www.idealdesk.com/ideal/messages/mer-acq/3.3.1" version="3.3.1">
<createDateTimestamp>$timestamp</createDateTimestamp>
<Merchant>
<merchantID>$merchantId</merchantID>
<subID>$subId</subID>
</Merchant>
</DirectoryReq>
EOT;
$document = new DOMDocument();
$document->loadXML($xml);
This is the OO approach (server rejects this message when signed):
$document = new DOMDocument('1.0', 'UTF-8');
$request = $document->createElement('DirectoryReq');
$xmlns = $document->createAttribute('xmlns');
$xmlns->value = 'http://www.idealdesk.com/ideal/messages/mer-acq/3.3.1';
$version = $document->createAttribute('version');
$version->value = '3.3.1';
$request->appendChild($xmlns);
$request->appendChild($version);
$merchant = $document->createElement('Merchant');
$merchant->appendChild($document->createElement('merchantID', $merchantId));
$merchant->appendChild($document->createElement('subID', $subId));
$request->appendChild($document->createElement('createDateTimestamp', $timestamp));
$request->appendChild($merchant);
$document->appendChild($request);
What can cause the difference as such the XML signature is invalidated by the server? The code to sign the message is exactly the same. The server is simply reporting "Invalid electronic signature".
If required I can show more code.
EDIT, more output and comparison of XML generated
To give some more information, this is the output of the first (HEREDOC) xml, generated via $document->saveXml():
<?xml version="1.0" encoding="UTF-8"?>
<DirectoryReq xmlns="http://www.idealdesk.com/ideal/messages/mer-acq/3.3.1" version="3.3.1">
<createDateTimestamp>2013-08-10T19:41:20.000Z</createDateTimestamp>
<Merchant>
<merchantID>0020XXXXXX</merchantID>
<subID>0</subID>
</Merchant>
</DirectoryReq>
This is the output ($document->saveXML()) for the second (direct DOMDocument generation) method:
<?xml version="1.0" encoding="UTF-8"?>
<DirectoryReq xmlns="http://www.idealdesk.com/ideal/messages/mer-acq/3.3.1" version="3.3.1">
<createDateTimestamp>2013-08-10T19:41:20.000Z</createDateTimestamp>
<Merchant>
<merchantID>0020XXXXXX</merchantID>
<subID>0</subID>
</Merchant>
</DirectoryReq>
In php, var_dump() gives the exact same string length. If I compare both strings (=== obviously) they are the same. Comparing both objects, then they are not the same.
Signing example
Signing occurs with the library xmlseclibs with this code (NB. both types are signed the same way!):
public function sign(DOMDocument $document, $fingerprint, $keyfile, $passphrase = null)
{
$dsig = new XMLSecurityDSig();
$dsig->setCanonicalMethod(XMLSecurityDSig::EXC_C14N);
$dsig->addReference($document, XMLSecurityDSig::SHA256,
array('http://www.w3.org/2000/09/xmldsig#enveloped-signature'),
array('force_uri' => true)
);
$key = new XMLSecurityKey(XMLSecurityKey::RSA_SHA256, array('type' => 'private'));
if ($passphrase !== null) {
$key->passphrase = $passphrase;
}
$key->loadKey($keyfile, true);
$dsig->sign($key);
$dsig->addKeyInfoAndName($fingerprint);
$dsig->appendSignature($document->documentElement);
}
If I dump the XML after it's signed, the <DigestValue> and <SignatureValue> values are different. So the server is correct the signature is invalid, but I cannot come up with a clue why method A works and B not.
You are overwriting $merchant when you create the Merchant element, so just rename the variable
$merchantElement = $document->createElement('Merchant');
I have now solved it by exporting and importing the XML again. It's quite ugly, but allows me to flexibly handle the DOMNodes.
protected function repairDOMDocument(DOMDocument $document)
{
$xml = $document->saveXML();
$document = new DOMDocument;
$document->loadXML($xml);
return $document;
}
If there is a suggestion how to stop doing this, I am pleased to hear so.

Strange problems with PHP SOAP (private variable not persist + variables passed from client not working)

I have a very strange problems in a PHP Soap implementation.
1) I have a private variable in the Server class which contains the DB name for further reference. The private variable name is "fromdb". I have a public function on the soap server where I can set this variable. $client->setFromdb. When I call it form my client works perfectly and the fromdb private variable can be set. But a second soap client call this private variable loses its value... Here is my soap server setup:
ini_set('soap.wsdl_cache_enabled', 0);
ini_set('session.auto_start', 0);
ini_set('always_populate_raw_post_data', 1);
global $config_dir;
session_start();
/*if(!$HTTP_RAW_POST_DATA){
$HTTP_RAW_POST_DATA = file_get_contents('php://input');
}*/
$server = new SoapServer("{$config_dir['template']}import.wsdl");
$server->setClass('import');
$server->setPersistence(SOAP_PERSISTENCE_SESSION);
$server->handle();
2) Problem is that I passed this to the server:
$client = new SoapClient('http://import.ingatlan.net/wsdl', array('trace' => 1));
$xml='<?xml version="1.0" encoding="UTF-8"?>';
$xml.='<xml>';
$xml.='<referens>';
$xml.='<original_id><![CDATA[DH-2]]></original_id>';
$xml.='<name>Valaki</name>';
$xml.='<email><![CDATA[valaki#example.com]]></email>';
$xml.='<phone><![CDATA[06-30/111-2222]]></phone>';
$xml.='</referens>';
$xml.='</xml>';
$tarray = array("type" => 1, "xml" => $xml);
try {
$s = $client->sendXml( $tarray );
print "$s<br>";
}
catch(SOAPFault $exception) {
print "<br>--- SOAP exception :<br>{$exception}<br>---<br>";
print "<br>LAST REQUEST :<br>";
var_dump($client->__getLastRequest());
print "<br>---<br>";
print "<br>LAST RESPONSE :<br>".$client->__getLastResponse();
}
So passed an Array of informations to the server. Then I got this exception:
LAST REQUEST :
<?xml version="1.0" encoding="UTF-8"?>
<SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/"><SOAP-ENV:Body><type>Array</type><xml/></SOAP-ENV:Body></SOAP-ENV:Envelope>
Can you see the Array word between the type tag? Seems that the client only passed a reference or something like this. So I totally missed :(
It seems the SOAP extension is expecting a string, but you're giving it an array. It then tries to convert the array into a string, resulting in "Array". I don't have time to check right now what the extension does you write $client->sendXml( $tarray );, but try to use instead:
$client->__soapCall("sendXml", $tarray);

Categories