PHP / CakePHP returning malformed XML - php

Basically I am trying to add Google Checkout order processing (level 2 integration) into a CakePHP app using the Google Checkout PHP sample code.
I can successfully create carts and receive notifications sent from Google to my app, however it cannot acknowledge these properly.
The function in google's code to do this echo's this:
<?xml version="1.0" encoding="UTF-8" ?><notification-acknowledgment xmlns="http://checkout.google.com/schema/2" serial-number="119963104284921-00001-7" />
However Google Checkout receives that code like this:
<?xml version=1.0 encoding=UTF-8 ?><notification-acknowledgment xmlns="http://checkout.google.com/schema/2" serial-number=119963104284921-00001-7 />
I can't work out what is causing this, I don't think it has anything to do with Cake and I've disabled PHP short tags so I can use inline XML but this makes no difference.
If I remove the first < from the string, the function echo's the rest of the code correctly, leave it in and it brakes (obviously this also applies for the ? and closing > symbol too, I just cant't have all of them at once!).
I have been able to replicate this myself in attempt to remove any unseen stuff being done in the Google Code using the function below. It does exactly the same thing but is contained within a (Cake) controller and hard codes the variables.
public function blank($tags = null) {
$schema = 'http://checkout.google.com/schema/2';
$serial = '119963104284921-00001-7';
if ($tags != null) {
$acknowledgment = '<?xml version="1.0" encoding="UTF-8" ?'.'>'.'<notification-acknowledgment xmlns="'.$schema.' '.'serial-number="'.$serial.'" />';
} else {
$acknowledgment = '?xml version="1.0" encoding="UTF-8" ?>'.'<notification-acknowledgment xmlns="'.$schema.' '.'serial-number="'.$serial.'" />';
}
$this->set('_ack', $acknowledgment);
}
The IF statement is used to show the difference the < symbol makes.
Calling it with nothing ($tags == null) gives this output:
<?xml version="1.0" encoding="UTF-8" ?><notification-acknowledgment xmlns="http://checkout.google.com/schema/2" serial-number="119963104284921-00001-7" />
Source.
Calling it with any other value ($tags != null) gives this output:
<?xml version=1.0 encoding=UTF-8 ?><notification-acknowledgment xmlns="http://checkout.google.com/schema/2" serial-number=119963104284921-00001-7 />
Source.
My question (finally!) is, why does this happen? and how can I get it output the XML correctly?
Sorry if I've missed something really obvious, but I'd rather have it pointed out here than faff around getting nowhere for another day!

this "problem" has to do with the PHP interpreter.
There are solutions but everything in View not in the Controlled.
//var
$questionmark = "?";
echo "<".$questionmark."xml version=\"1.0\" encoding=\"utf-8\"".$questionmark.">";
// separate
echo '<' . '?xml version="1.0" encoding="utf-8"?' . '>';

You forgot to close the quotes on the xmlns attribute, that's the probable cause. Try this:
$acknowledgment = '<?xml version="1.0" encoding="UTF-8" ?'.'>'.'<notification-acknowledgment xmlns="'.$schema.'" '.'serial-number="'.$serial.'" />';

Some XML parsers do not allow specifying the encoding in capital letters (e.g. UTF-8 is incorrect).
Try changing the encoding to "utf-8" to see if that fixes it.

Related

POST request XML malformed

I have a problem with an EPP XML request. I have been getting a Command Syntax Error response from the API for quite some time now. I've been in contact with the technical department who just recently responded that my XML is being received as malformed, being split in the middle. I don't know why.
I compile the PHP to XML using the DOMDocument class. I return every XML build method using __toString() which returns $this->saveXML(); which dumps the tree as string. I then send a POST request. Every other method works fine, but not this.
Code here:
https://github.com/OssiPesonen/epp_depo
I actually dump my XML using:
header('Content-type: text/plain');
echo $xml;
die();
And every time it gives me:
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<epp xmlns="urn:ietf:params:xml:ns:epp-1.0">
<command>
<create>
<contact:create xmlns:contact="urn:ietf:params:xml:ns:contact-1.0">
<contact:id>1</contact:id>
<contact:role>5</contact:role>
<contact:type>1</contact:type>
<contact:postalInfo type="loc">
<contact:isfinnish>1</contact:isfinnish>
<contact:firstname>Essi</contact:firstname>
<contact:lastname>Esimerkki Oy</contact:lastname>
<contact:name>HR</contact:name>
<contact:org>Esimerkki Oy</contact:org>
<contact:birthDate>2005-04-03T00:00:00.0Z</contact:birthDate>
<contact:identity>123423A123F</contact:identity>
<contact:registernumber>20824760</contact:registernumber>
<contact:addr>
<contact:street>Test Street</contact:street>
<contact:pc>00000</contact:pc>
<contact:cc>FI</contact:cc>
<contact:city>City</contact:city>
</contact:addr>
</contact:postalInfo>
<contact:voice x="1234">+358401234567</contact:voice>
<contact:email>testi#testi.fi</contact:email>
<contact:legalemail>testi#testi.fi</contact:legalemail>
<contact:disclose flag="0">
<contact:addr/>
<contact:email/>
</contact:disclose>
</contact:create>
</create>
<clTRID>E1144-588371f25ab80</clTRID>
</command>
</epp>
This doesn't look malformed, right? Yet, the technical support responded to me, that after <contact:city> was split before the closing tag:
contact:city>
<contact:sp>VA</contact:sp>
<contact:pc>20166-6503</contact:pc>
<contact:cc>US</contact:cc>
</contact:addr>
</contact:postalInfo>
<contact:voice x="1234">+3581231234</contact:voice>
<contact:fax>+04040as</contact:fax>
<contact:email>jdoe#example.com</contact:email>
<contact:legalemail>jdoe#example.com</contact:legalemail>
<contact:disclose flag="0">
<contact:addr/>
<contact:email/>
</contact:disclose>
</contact:create>
</create>
<clTRID>E1144-5867f93f6503a</clTRID>
</command>
</epp>
05-04-03T22:00:00.0Z</contact:birthDate>
<contact:identity>010188-123A</contact:identity>
<contact:registernumber>123456-7</contact:registernumber>
<contact:addr>
<contact:street>123 Example Dr.</contact:street>
<contact:street></contact:street>
<contact:street></contact:street>
<contact:city>Dulles</
Any ideas what might cause this? Because I can't see it.
Edit
After exhausting my options I've uploaded the code to Github to be viewed.
https://github.com/OssiPesonen/epp_depo
Well, the answer was simple, yet I cannot understand why it's the solution.
I basically removed all the failsafes from the send() method and leaving just this:
private function send($buffer)
{
if(fwrite($this->socket, $buffer)) {
return true;
}
return false;
}
I don't really know what it was that cut the XML string in the previous one, but this will do for our platform.

How can I load POST data into SimpleXML?

I need to post XML data from a textarea input to PHP so I can parse it and output a table.
I've tried a few methods and none seem to be working.
Currently I have this:
jQuery('#btnRegistrarXML').live('click', function(){
var xml;
if (jQuery('#txtRegXML').val() == ""){
AddMsg('You must paste XML from the excel export into the textarea.', 'error');
} else {
jQuery.post('registrar-xml-to-table.php', {xml:escape(jQuery('#txtRegXML').val())}, function(data){
jQuery('#regXMLasTable').empty();
jQuery('#regXMLasTable').append(data);
});
}
displayMsgs();
});
The PHP is:
$xmlraw = urldecode($_POST['xml']);
$dom = new DOMDocument;
$dom->preserveWhiteSpace = FALSE;
$dom->loadXML($xmlraw);
$dom->formatOutput = TRUE;
$xmlstr = $dom->saveXml();
$xml = simplexml_load_string($xmlstr);
echo "<p>xmlraw:</p>";
echo $xmlraw;
echo "<p>xml:</p>";
echo $xml;
foreach ($xml->document as $doc) {
echo '<p class="alert alert-error">'.$doc->title.'</p>';
}
The first echo $xmlraw is working - it outputs the XML string all on one line - the post is sending the data through properly.
The second echo $xml doesn't output anything and the foreach doesn't output anything either - something is not working in the PHP
I've also tried loading $xmlraw directly into simplexml_load_string($xmlraw) but it doesn't work - I'm assuming because it's not well formed?
The XML I'm using to test is:
<?xml version="1.0"?>
<document>
<title>
Foobar
</title>
</document>
You can paste the XML into the textarea on this ( http://tsdexter.com/webservice-testing/programs-list.php ) page and then if you inspect element underneath xmlraw: you can see that the raw xml string was echoed - however, underneath xml: there is nothing and also the foreach doesn't output anything either.
Here's a jsFiddle so you can see the HTML/JS - it doesn't actually do anything though because it can't ajax to the PHP page - so I included the PHP version above to test. http://jsfiddle.net/tsdexter/EDqQB/
Any ideas?
A few questions, which may or may not constitute an answer, but needed more space than a comment.
Why are you running urldecode on the $_POST variable? PHP should be doing that for you, unless you are double-escaping it somewhere.
Why are you loading into DOM and then SimpleXML? I know you said you tried without, but they use the same XML parser underneath, so there is no way this will help you rather than introducing more confusion.
What does var_dump(simplexml_load_string($rawxml)) give you? My guess would be FALSE, meaning an error. In which case, check you have warnings turned on (error_reporting(E_ALL); ini_set('display_errors', '1');) and detailed XML error handling turned off (libxml_use_internal_errors(false);).
In case it does give you a SimpleXMLElement object, don't spend too long looking at the var_dump output. Try one of these debugging functions instead.

Accessing data from an xml file

I want to perform an if check on an XML file I have loaded in using simplexml_load_file.
I have accessed the data when the output is as I want it to be, although as it's web services sometimes they may be a response which I need to cater for. The below is the XML I want to be able to check on:
<?xml version="1.0" encoding="utf-8"?>
<ProductSizes />
Can somebody help me out? I am using the below:
$xmlstock = simplexml_load_file($xmlfeed);
Assuming that the xml source looks something like the following when actually populated:
<?xml version="1.0" encoding="utf-8"?>
<ProductSizes>
<ProductSize />
<ProductSize />
<ProductSize />
</ProductSizes>
You can get a count using the count() api call:
$xmlstock = simplexml_load_file($xmlfeed);
$hasProductSizes = ($xmlstock->ProductSize->count() > 0) ? true : false;
More info on the count() API via PHP docs.

Ajax - responseText working but responseXML null

I am trying my first AJAX and having a problem with my xml receiving function.
I alert responseText and I can see the xml returned from my server, but when I try and get responseXML I get null and the error.
Here is the php function that builds my xml
header('Content-type: application/xml');
echo("<?xml version=\"1.0\" encoding=\"utf-8\"?>");
echo("<results>");
echo("<table><![CDATA[tablereererere]]></table>");
//echo("<ratedTable>".$_POST['ratedTable']."</ratedTable>\n");
//echo("<table>".$_POST['table']."</table>\n");
//echo("<post_id>".$_POST['post_id']."</post_id>\n");
//echo("<user_id>".$_POST['user_id']."</user_id>\n");
//echo("<rating>".$_POST['rating']."</rating>\n");
echo("</results>");
And here is my javascript function which is processing the returned xml
function ajaxReceiver(http_request) {
//this function continues to run until a result is returned and then it creates the new div
if(http_request.readyState == 4) {
response_xml = http_request.responseXML;
response_text = http_request.responseText;
alert(response_text);
alert(response_xml.getElementsByTagName("table")[0].textContent);
//document.getElementById('floatingNotification').innerHTML = response_text;
// alert(http_request.responseXML.getElementsByTagName("table")[0].textContent);
//ratedTable = responseXML.getElementsByTagName("table").value;
//alert(ratedTable);
//message = response.getElementsByTagName('table')[0].textContent;
//alert(message);
//alert(message);
//this response contains the xml document that was returned by the php function.You can get any values out of the xml document and
//use javascript dom to manipulate the contents on the page
}
}
It may be because, even though you're setting the content-type correctly, you need to have an <xml tag in the top of your response. Also, you aren't closing your last tag properly. This should work:
echo("<?xml version='1.0'?>");
echo("<results>");
echo("<ratedTable>".$_POST['ratedTable']."</ratedTable>");
echo("<table>".$_POST['table']."</table>");
echo("<post_id>".$_POST['post_id']."</post_id>");
echo("<user_id>".$_POST['user_id']."</user_id>");
echo("<rating>".$_POST['rating']."</rating>");
echo("<message>$message</message>");
echo("</results>");
For more info on how to define your XML: http://www.w3.org/TR/REC-xml/#sec-prolog-dtd
You are closing the parent node improperly (</results> not <results/>) and you should (after sanitizing it) wrap all the POSTDATA in <![CDATA[...]]> tags to be safe. Make sure it's UTF8 encoded, too (see utf8_encode())
EDIT: and what wajiw said about the <?xml version="1.0" encoding="UTF-8" ?> tag at the beginning.
Edit: Example CDATA Block Usage
<?xml version="1.0" encoding="UTF-8" ?>
<myNode>
<myData><![CDATA[
Now I just throw in my data, for fun and profit!
This way I can use special, reserved characters like <, > and &!
]]></myData>
</myNode>
Edit Yet Again:
Why not give Content-Type: text/xml, NOT application/xml, a go?
The answer is to put the asynchronous property in the function "open()" to false.
Like this:
ajaxObject.open("POST", "my_XML_Generator.php", false);
ajaxObject.setRequestHeader("Content-type", "text/xml");
ajaxObject.send();
I had the same problem and couldn't solve it until I put my results into subnodes, e.g.
header("Content-Type: text/xml; charset=utf-8");
echo("<?xml version='1.0' encoding='utf-8'?>\n");
echo("<summary>$summary</summary>\n");
echo("<content>$content</content>\n");
didn't work for me for some weird reason, but this does:
header("Content-Type: text/xml; charset=utf-8");
echo("<?xml version='1.0' encoding='utf-8'?>\n");
echo("<page>\n");
echo(" <summary>$summary</summary>\n");
echo(" <content>$content</content>\n");
echo("</page>\n");
My code retrieving the answer is
function retrieveRequest(title)
{
if (_xmlRequest.readyState == 4 && _xmlRequest.status == 200)
{
var xmlResponse = _xmlRequest.responseXML;
_divSummary.innerHTML = xmlResponse.getElementsByTagName("summary")[0].textContent;
_divContent.innerHTML = xmlResponse.getElementsByTagName("content")[0].textContent;
}
}
I had this error happen to our team once and it took me a long time before we realized that the problem was in our XML data returned from the server. In particular, PHP script that generated return XML string was the culprit.
My solution was to remove any white space from the beginning of the PHP script. I mean any spaces, new lines, and/or tabs need to be removed from the beginning of the script, so that the first thing in the script is the <?php tag itself. It turned out that the <?PHP tag was not the first thing on the first line of my PHP script; somehow I started my code on the second line and the first script line was simply an empty one.
It drove me mad and it took some time for me to figure this out, so I hope someone else can benefit from this solution. It is very simple and easy to try if all else fails.

PHP -> XML output is different on IE

I have been trying to output XML with PHP but encountered a strange(!) error in Internet Explorer.
The expected xml output is this:(simplified)
<root>
<match_id>12</match_id>
<stadium_id>43</stadium_id>
<tribune_id>2</tribune_id>
<fan_id>453</fan_id>
</root>
I am producing this output with the following PHP code:
echo "<?xml version='1.0' encoding='utf-8' ?>
<root>
<match_id>"; echo $match->getId(); echo "</match_id>
<stadium_id>43</stadium_id>
<tribune_id>2</tribune_id>
<fan_id>".$_SESSION['user_id']."</fan_id>
</root>";
In Firefox, the output is same as expected. However, in IE, the output is this:
<?xml version="1.0" encoding="utf-8" ?>
<root>
<match_id>0</match_id>
<stadium_id>43</stadium_id>
<tribune_id>2</tribune_id>
<fan_id />
</root>
This is a really annoying error. I have set the PHP header for XML output, and changed lots of other things but could not make it work.
The $match->getId() part is just returning an integer but IE always shows this value as 0. If I set <fan_id> and <match_id> manually, IE shows the values correctly.
By the way, I am using this XML output in Flash (AS3) and this also shows the same result with IE.
What am I doing wrong?
This looks like it's due to a session difference - the IE session isn't storing the user id. Similarly, $match->getId() is actually 0 - I imagine you'd get a similar result using Chrome or Safari or a web browser on any other computer.
One other thing: Flash may not be sending the PHP session cookie to the server on the request - which would match the IE behavior / no valid session.
Try:
header( "content-type: application/xml; charset=ISO-8859-15" );
OR
$doc = new DOMDocument;
$root = $doc->createElement('root');
$doc->appendChild($root);
$match_id = $doc->createElement('match_id', $match->getId());
$root->appendChild($match_id);
$stadium_id = $doc->createElement('stadium_id', '43');
$root->appendChild($stadium_id);
$tribune_id = $doc->createElement('tribune_id', '2');
$root->appendChild($tribune_id, '2');
$fan_id = $doc->createElement('fan_id', $_SESSION['user_id']);
$root->appendChild($fan_id);
echo $doc->saveXML();
//$doc->save('file.xml'); // if you want to write to file
What browser is used has no effect on how your PHP executes (because it's executed on server, not in browser). Notice that in the second example your fan_id is also empty, which indicates something's wrong with your session setup. Investigate this.
Having said all that: did you consider using simplexml() to output XML from PHP? It's much more fun to use than echoing tags.

Categories