Check if an xml is loaded with simplexml_load_string - php

I am querying an xml file with php like this :
public function trackOrderAction()
{
$request = Mage::getResourceModel( 'order/request' );
$request->setOrder($this->getRequest()->getParam('increment_id'));
$response = $request->submit(true);
$xml = simplexml_load_string($response);
$items = count($xml->OrderItems->OrderItem);
}
The xml is not ready immediately so if people try to use the function before it is ready there is an error because it is trying to get the property of a non-object. My question is what is the proper way to check the xml response to see if there is anything and stop the function if there is not?
I tried something simple like
if (empty($xml)){
die();
} else {
$items = count($xml->OrderItems->OrderItem);
}
But this does not help. Any ideas on how to check to see if the xml loaded?

From http://us.php.net/manual/en/function.simplexml-load-string.php
Returns an object of class SimpleXMLElement with properties containing
the data held within the xml document. On errors, it will return
FALSE.
public function trackOrderAction()
{
$request = Mage::getResourceModel( 'order/request' );
$request->setOrder($this->getRequest()->getParam('increment_id'));
$response = $request->submit(true);
$xml = simplexml_load_string($response);
if ( !$xml ) {
return false;
}
$items = count($xml->OrderItems->OrderItem);
}
It will return false if there was an error. So fail right away if simplexml_load_string fails and return false. Otherwise continue on with the rest of the function. Never die() in a function.

Related

Check a php variable contains a SimpleXMLObject

I need to check that the $model variable contains an object of type SimpleXMLObject.
$model = convertToSimpleXml($fileName, $filePath);
This is the end of the convertToSimpleXml method where the object is returned using simplexml_load_file
$simpleXml = simplexml_load_file($path);
return $simpleXml;
I've tried checking it as an array or something similar but no luck with that, have looked around for examples but can't find any clear cut answer to the question. Can anyone help?
You can simply check the class of your $simpleXml:
$simpleXml = simplexml_load_file($path);
if($simpleXml instanceof SimpleXMLElement) {
return $simpleXml;
} else {
return false;
}

PHP xpath won't return data

im trying to filter out some informations from an XML file using PHP xpath, somehow the response seems always to be empty. Does anyone have an idea what could cause this?
Xml example:
<account>
<a>Information1</a>
<b>Information2</b>
<c>Informatio3</c>
</account>
My actual code:
public static function user_cache($username) {
$xml = #file_get_contents('xmlfile');
$xml = #simplexml_load_string($xml);
if ( $xml ) {
$results = array(
"userid" => $xml->xpath('a')
);
}
else {
$results['message'] = 'Unable to get data.';
}
return $results;
}
{
"userid": []
}
This is more of a XPATH question. The correct syntax would be
$xml->xpath('//a')
You can find more information about XPATH's syntax here: http://www.w3schools.com/xsl/xpath_syntax.asp
On the other hand, xpath method returns an array of SimpleXMLElement, so take that into account.
http://php.net/manual/en/simplexmlelement.xpath.php

Amazon MWS (PHP) - Report Request API functions return without data, no error thrown

I am currently working with the Amazon MWS to integrate some features into wordpress via a plugin. I am using the client libraries provided by amazon found here:
https://developer.amazonservices.com/api.html?group=bde&section=reports&version=latest
Using these client libraries and the sample php files included I have set up my plugin to make two API calls. The first is requestReport
public function requestInventoryReport() {
AWI_Amazon_Config::defineCredentials(); // Defines data for API Call
$serviceUrl = "https://mws.amazonservices.com";
$config = array (
'ServiceURL' => $serviceUrl,
'ProxyHost' => null,
'ProxyPort' => -1,
'MaxErrorRetry' => 3,
);
$service = new MarketplaceWebService_Client(
AWS_ACCESS_KEY_ID,
AWS_SECRET_ACCESS_KEY,
$config,
APPLICATION_NAME,
APPLICATION_VERSION);
$request = new MarketplaceWebService_Model_RequestReportRequest();
$request->setMerchant(MERCHANT_ID);
$request->setReportType('_GET_MERCHANT_LISTINGS_DATA_');
self::invokeRequestReport($service, $request);
}
private function invokeRequestReport(MarketplaceWebService_Interface $service, $request) {
try {
$response = $service->requestReport($request);
if ($response->isSetRequestReportResult()) {
// Print Out Data
}
} catch (MarketplaceWebService_Exception $ex) {
// Print Out Error
}
}
and the second is getReportRequestList which has code similar to the first function. I am able to run these functions without any errors. The issue that I am having is that $response->isSetRequestReportResult() returns false. From my understanding and looking into the response object, this would suggest that the response object does not have the result. (Upon printing out the response object I can see that the FieldValue of the result array is NULL.) The call, however, does not throw an error but neither does it have the result.
I did some digging through the code and found that the result does actually get returned from the api call but never gets set to the return object when the library attempts to parse it from XML. I've tracked the error down to this block of code (This code is untouched by me and directly from the amazon mws reports library).
private function fromDOMElement(DOMElement $dom)
{
$xpath = new DOMXPath($dom->ownerDocument);
$xpath->registerNamespace('a', 'http://mws.amazonaws.com/doc/2009-01-01/');
foreach ($this->fields as $fieldName => $field) {
$fieldType = $field['FieldType'];
if (is_array($fieldType)) {
if ($this->isComplexType($fieldType[0])) {
// Handle Data
} else {
// Handle Data
}
} else {
if ($this->isComplexType($fieldType)) {
// Handle Data
} else {
$element = $xpath->query("./a:$fieldName/text()", $dom);
$data = null;
if ($element->length == 1) {
switch($this->fields[$fieldName]['FieldType']) {
case 'DateTime':
$data = new DateTime($element->item(0)->data,
new DateTimeZone('UTC'));
break;
case 'bool':
$value = $element->item(0)->data;
$data = $value === 'true' ? true : false;
break;
default:
$data = $element->item(0)->data;
break;
}
$this->fields[$fieldName]['FieldValue'] = $data;
}
}
}
}
}
The data that should go into the RequestReportResult exists at the beginning of this function as a node in the dom element. The flow of logic takes it into the last else statement inside the foreach. The code runs its query and returns $element however $element->length = 13 in my case which causes it to fail the if statement and never set the data to the object. I have also looked into $element->item(0) to see what was in it and it appears to be a dom object itself matching the original dom object but with a bunch of empty strings.
Now, I'm new to working with the MWS and my gut feeling is that I am missing a parameter somewhere in my api call that is messing up how the data is returned and is causing this weird error, but I'm out of ideas at this point. If anyone has any ideas or could point me in the right direction, I would greatly appreciate it.
Thanks for your time!
** Also as a side note, Amazon Scratchpad does return everything properly using the same parameters that I am using in my code **
These works for me, check if you are missing anything.
For RequestReportRequest i am doing this:
$request = new MarketplaceWebService_Model_RequestReportRequest();
$marketplaceIdArray = array("Id" => array($pos_data['marketplace_id']));
$request->setMarketplaceIdList($marketplaceIdArray);
$request->setMerchant($pos_data['merchant_id']);
$request->setReportType($this->report_type);
For GetReportRequestList i am doing this:
$service = new MarketplaceWebService_Client($pos_data['aws_access_key'], $pos_data['aws_secret_access_key'], $pos_data['config'], $pos_data['application_name'], $pos_data['application_version']);
$report_request = new MarketplaceWebService_Model_GetReportRequestListRequest();
$report_request->setMerchant($pos_data["merchant_id"]);
$report_type_request = new MarketplaceWebService_Model_TypeList();
$report_type_request->setType($this->report_type);
$report_request->setReportTypeList($report_type_request);
$report_request_status = $this->invokeGetReportRequestList($service, $report_request, $report_requestID);

PHP include external method and class

I'm new to PHP and I have an issue I can't seem to fix or find a solution to.
I'm trying to create a helper function that will return an 'object' filled with information pulled from an XML file. This helper function, named functions.php contains a getter method which returns a 'class' object filled with data from an SVN log.xml file.
Whenever I try to import this file using include 'functions.php'; none of the code after that line runs the calling function's page is blank.
What am I doing wrong?
Here is what the functions.php helper method and class declaration looks like:
<?php
$list_xml=simplexml_load_file("svn_list.xml");
$log_xml=simplexml_load_file("svn_log.xml");
class Entry{
var $revision;
var $date;
}
function getEntry($date){
$ret = new Entry;
foreach ($log_xml->logentry as $logentry){
if ($logentry->date == $date){
$ret->date = $logentry->date;
$ret->author = $logentry->author;
}
}
return $ret;
}
I'm not sure what the point of having a separate helper function from the class is, personally I'd combine the two. Something like this
other-file.php
require './Entry.php';
$oLogEntry = Entry::create($date, 'svn_log.xml');
echo $oLogEntry->date;
echo $oLogEntry->revision;
Entry.php
class Entry
{
public $revision;
public $date;
public $author;
public static function create($date, $file) {
$ret = new Entry;
$xml = simplexml_load_file($file);
foreach($xml->logentry as $logentry) {
if($logentry->date == $date) {
$ret->date = $logentry->date;
$ret->author = $logentry->author;
$ret->revision = $logentry->revision;
}
}
return $ret;
}
}
EDIT
In light of the fact OP is new to PHP, I'll revise my suggestion completely. How about ditching the class altogether here? There's hardly any reason to use a class I can see at this point; let's take a look at using an array instead.
I might still move the simplexml_load_file into the helper function though. Would need to see other operations to merit keeping it broken out.
entry-helper.php
function getEntry($date, $file) {
$log_xml = simplexml_load_file($file);
$entry = array();
foreach($log_xml->logentry as $logentry) {
if($logentry->date == $date) {
$entry['date'] = $logentry->date;
$entry['author'] = $logentry->author;
$entry['revision'] = $logentry->revision;
}
}
return $entry;
}
other-file.php
require './entry.php';
$aLogEntry = Entry::create($date, 'svn_log.xml');
echo $aLogEntry['date'];
echo $aLogEntry['revision'];
EDIT
One final thought.. Since you're seemingly searching for a point of interest in the log, then copying out portions of that node, why not just search for the match and return that node? Here's what I mean (a return of false indicates there was no log from that date)
function getEntry($date, $file) {
$log_xml = simplexml_load_file($file);
foreach($log_xml->logentry as $logentry) {
if($logentry->date == $date) {
return $logentry;
return false;
}
Also, what happens if you have multiple log entries from the same date? This will only return a single entry for a given date.
I would suggest using XPATH. There you can throw a single, concise XPATH expression at this log XML and get back an array of objects for all the entries from a given date. What you're working on is a good starting point, but once you have the basics, I'd move to XPATH for a clean final solution.

Error handling loading a URL

I'm using a library called Simple HTML DOM
One of it's methods, loads the url into a DOM object:
function load_file()
{
$args = func_get_args();
$this->load(call_user_func_array('file_get_contents', $args), true);
// Throw an error if we can't properly load the dom.
if (($error=error_get_last())!==null) {
$this->clear();
return false;
}
}
In order to test error handling, I created this code:
include_once 'simple_html_dom.php';
function getSimpleHtmlDomLoaded($url)
{
$html = false;
$count = 0;
while ($html === false && ($count < 10)) {
$html = new simple_html_dom();
$html->load_file($url);
if ($html === false) {
echo "Error loading url!\n";
sleep(5);
$count++;
}
}
return $html;
}
$url = "inexistent.html";
getSimpleHtmlDomLoaded($url);
The idea behind this code it's to try again if the url is failing to load, if after 10 attemps still fails, it should return false.
However it seems that with an inexistent url, the load_file method never returns false.
Instead I get the following warning message:
PHP Warning: file_get_contents(inexisten.html): failed to open stream
Any idea how to fix this?
Note: Preferably I would like to avoid hacking into the library.
Change your following code:
$html->load_file($url);
if ($html === false) {
for this one:
$ret = $html->load_file($url);
if ($ret === false) {
because you were checking object instance instead of the returned value from load_file() method.
By adding the # sign before a method call, any warnings get supressed. If you use this, always be sure to check for errors yourself as you do now and are sure no other methods are available to make sure no warnings and/or errors pop up.
You should check the actual data that is saved somewhere by the load() method if that equals FALSE instead of the object instance $html.

Categories