PHP Put variable in SimpleXML - php

I have a problem with simpleXML and variable
$num = $categorie['id'];
echo $num; /*return value is 1 or 0*/
$fav = $xml->categorie[$num]->addChild("fav"," ");
I want to put $num in categorie[$num] but not work. How i can do this?
My XML
<?xml version="1.0" encoding="ISO-8859-1"?>
<data>
<categorie id="0" name="Search">
<fav>
<link>Google</link>
<desc>www.google.fr</desc>
</fav>
<fav>
<link>Orange</link>
<desc>www.orange.fr</desc>
</fav>
</categorie>
<categorie id="1" name="Social">
<fav>
<link>Facebook</link>
<desc>www.facebook.com</desc>
</fav>
<fav>
<link>Youtube</link>
<desc>www.youtube.com</desc>
</fav>
</categorie>
</data>
MY php complete php code. And the problem is in the foreach loop. i compare the categorie name to get the id and put the new favorite in the correct categorie.
<?php
$link = $_POST['link'];
$desc= $_POST['desc'];
$cat = $_POST['cat'];
$xml = simplexml_load_file('../data/data.xml');
foreach($xml->categorie as $categorie)
{
if (strcmp($categorie['name'], $cat) == 0)
{
$num = $categorie['id'];
echo $num;
$fav = $xml->categorie[$num]->addChild("fav"," ");
$fav->addChild("link", $link);
$fav->addChild("desc", $desc);
$xml->asXML('../data/data.xml');
}
}
?>
Thanks

The solution is to convert an object to integer with intval()
$num = intval($categorie['id']);
$fav = $xml->categorie[$num]->addChild("fav"," ");
$fav->addChild("link", $link);
$fav->addChild("desc", $desc);
$xml->asXML('../data/data.xml');

Related

PHP Array Comparison using If

I am having a hard time trying to understand why I can't compare the values of two arrays in PHP. If I echo both of these during the loop using "echo $description->ItemDesriptionName;" and "echo $item->ItemName;" the values seem to show as the same, but when I try to compare them using if, nothing works. What am I missing?
<?php
$xml=simplexml_load_file("test.xml") or die("Error: Cannot create object");
$categories = $xml->Menu->Categories;
$items = $xml->Menu->Categories->Items->ItemObject;
$itemdescription = $xml->Menu->Options->Description->DescriptionObject;
foreach($items as $item) {
echo $item->ItemName . ' - ' . $item->Price . '</br>';
foreach ($itemdescription as $description) {
if ($description->ItemDescriptionName == $item->ItemName) {
echo 'We have a match!';
//where I would echo $description->ItemDescription;
}
}
}
?>
Here is the XML file
<?xml version="1.0" encoding="utf-8"?>
<Root>
<Menu>
<Categories>
<Name>Category 1</Name>
<Items>
<ItemObject>
<ItemName>Item 1</ItemName>
<Price>1</Price>
</ItemObject>
<ItemObject>
<ItemName>Item 2</ItemName>
<Price>3</Price>
</ItemObject>
</Items>
</Categories>
<Options>
<Description>
<DescriptionObject>
<ItemDescriptionName>Item 1</ItemDescriptionName>
<ItemDescription>A Great item</ItemDescription>
</DescriptionObject>
<DescriptionObject>
<ItemDescriptionName>Item 2</ItemDescriptionName>
<ItemDescription>A Great item as well</ItemDescription>
</DescriptionObject>
</Description>
</Options>
</Menu>
</Root>
compare as string
and you have typo in ItemDescriptioName (ItemDescriptionName)
if ( (string)$description->ItemDescriptionName == (string)$item->ItemName) {
Convert to string and then compare
<?php
$xml=simplexml_load_file("test.xml") or die("Error: Cannot create object");
$menu = $xml->Menu;
$categories = $xml->Menu->Categories;
$items = $xml->Menu->Categories->Items->ItemObject;
$itemdescription = $xml->Menu->Options->Description->DescriptionObject;
foreach($items as $item) {
$itemname = $item->ItemName;
foreach ($itemdescription as $description) {
$descriptionname = $description->ItemDescriptionName ;
echo $itemname." ---- ".$descriptionname."<br/>";
if((string)$itemname === (string)$descriptionname){
echo "Yes its matched";
}
}
}
?>
Working fine for me
The properties like $description->ItemDescriptionName are SimpleXMLElement objects. So you do not compare strings but two objects.
SimpleXMLElement objects implement the magic method __toString(). They can be cast to string automatically, but a compare between to objects will not trigger that. You can force it:
if ((string)$description->ItemDescriptionName === (string)$item->ItemName) {
...
Can you access them directly instead using an accordant index?
...
$items = $xml->Menu->Categories->Items->ItemObject;
$itemdescription = $xml->Menu->Options->Description;
$i = 0;
foreach ($items as $item) {
echo $i.' '.$item->ItemName . ' - ' . $item->Price;
echo $itemdescription->DescriptionObject[$i]->ItemDescriptionName[0];
echo ' ';
echo $itemdescription->DescriptionObject[$i]->ItemDescription[0];
echo '</br>';
$i++;
}

How to Create a secured API using PHP in xml format?

I have an ecommerce website in which regularly transactions keeps happening. Now we are developing an android app for the same. So I was asked to build an API using PHP. The API that i made was in xml format. But now since i will be sending he login credentials through it I am scared that someone would hack it. So can someone help me with it.
here is the way i had created the xml API using php..
<?php
include 'config.php';
include 'database.php';
$sqlCat = "select category_id,image,name from table" ;
$categories = DatabaseHandler::GetAll($sqlCat);
$xml = new DomDocument("1.0","UTF-8");
$content = $xml->createElement("content");
$content = $xml->appendChild($content);
foreach($categories as $category) {
$item = $xml->createElement("item");
$catName = $xml->createElement("catName",htmlspecialchars($category['name']));
$catName = $item->appendChild($catName);
$catImage = $xml->createElement("catImage",htmlspecialchars($category['image']));
$catImage = $item->appendChild($catImage);
$sql = "select image,name,model,price,quantity from table;
$results = DatabaseHandler::GetAll($sql);
foreach($results as $key=>$result) {
$product = $xml->createElement("product");
$product->setattribute('id',$key);
$model = $xml->createElement("model",$result['model']);
$model = $product->appendChild($model);
$name = $xml->createElement("name",htmlspecialchars($result['name']));
$name = $product->appendChild($name);
$image = $xml->createElement("image",htmlspecialchars($result['image']));
$image = $product->appendChild($image);
$price = $xml->createElement("price",$result['price']);
$price = $product->appendChild($price);
$product = $item->appendChild($product);
}
$item = $content->appendChild($item);
}
$xml->FormatOutput = true;
$output = $xml->saveXML();
$xml->save("categories.xml");
?>
and I get the xml in this form..
<content>
<item>
<catName>Comp</catName>
<catImage/>
<product id="0">
<model>156443</model>
<name>CD</name>
<image>109.jpg</image>
<price>48</price>
</product>
<product id="1">
<model>46876</model>
<name>memory card</name>
<image>81.jpg</image>
<price>12</price>
</product>
<product id="2">
<model>865793</model>
<name>drive</name>
<image>51.png</image>
<price>2</price>
</product>
</item>
</content>
Can someone tell whether the way i have generated API in XML format correct.
Dont make think too complex make it simple like following code
$con = mysql_connect("localhost","root","root") or die("could not connect".mysql_error());
//select your database table
mysql_select_db("android_maps", $con) or die("Could not select database".mysql_error());
//get your results with a mysql query
$result = mysql_query("SELECT gmaps.*, urls.* FROM gmaps, urls WHERE urls.idgmaps = gmaps.idgmaps") or die(mysql_error());
//run a while loop get your data.
while($location = mysql_fetch_array($result)) {
$output = '<?xml version="1.0" encoding="utf-8"?>';
$output .= '<data>';
$output .= "<lat>".$location['lat']."</lat>";
$output .= "<long>.".$location['lon']."</long>";
$output .= "<description>.".$location['description']."</description>";
$output .= '</data>';
print $output;
}
mysql_close($con);
}else{
echo "<h1>No results to show for you query</h1>";
}
for more info
http://teachingyou.net/php/php-api-development-dreaming-of-your-own-api-make-it-possible-today/

How to edit my code to save to mySQL from the beginning of XML?

I have this XML feed below I am trying to import into MySQL for all the products.
For example, inside the table XML_FEED I want something like
shop - product_id - product_name - product_link - .......
mywebstore - 322233 - MadBiker 600 - .........
mywebstore - 324633 - Samsung S4 - .........
The code until now it works only if the XML begins from <products> and not from <mywebstore>
How to change my code to do this ?
$xml = simplexml_load_file("test.xml");
foreach($xml->product as $product)
{
$columns = array();
$data = array();
foreach($product->children() as $child)
{
echo $child->getName() . ": " . $child . "<br />";
$columns[] = $child->getName();
$data[] = mysql_real_escape_string((string)$child);
}
$col = '`'. implode('`,`',$columns) .'`';
$val = "'". implode("','",$data)."'";
$query = "INSERT INTO XML_FEED ($col) VALUES ($val)";
echo $query;
mysql_query($query);
}
Here is the XML:
<?xml version="1.0" encoding="UTF-8"?>
<mywebstore>
<created_at>2010-04-08 12:32</created_at>
<products>
<product>
<id>322233</id>
<name><![CDATA[MadBiker 600]]></name>
<link><![CDATA[http://www.mywebstore.co.uk/product/322233]]></link>
<image><![CDATA[http://www.mywebstore.co.uk/product/322233.jpg]]></image>
<category><![CDATA[Outdor > Extreme Sports]]></category>
<price_with_vat>322.33</price_with_vat>
</product>
...
...
...
</products>
</mywebstore>
Use This code:
<?php
$xml = simplexml_load_file('test.xml');
foreach($xml->products->product as $product)
{
$columns = array();
$data = array();
foreach($product->children() as $child)
{
echo $child->getName() . ": " . $child . "<br />";
$columns[] = $child->getName();
$data[] = mysql_real_escape_string((string)$child);
}
$col = '`'. implode('`,`',$columns) .'`';
$val = "'". implode("','",$data)."'";
$query = "INSERT INTO XML_FEED ($col) VALUES ($val)";
echo $query;
mysql_query($query);
}
?>
This should work for you:
<?php
//Xml stuff
$xml = simplexml_load_file("file.xml");
//Database stuff
$hostname = "localhost";
$username = "root";
$password = "";
try {
//DB Connection
$dbh = new PDO("mysql:host=$hostname;dbname=dbname", $username, $password);
$dbh->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
echo "Connected to Database<br/>";
foreach($xml->products->product as $data) {
$sql = "INSERT INTO XML_FEED (shop, product_id, product_name, product_link, product_image, product_category, product_price_with_vat)
VALUES (:SHOP, :ID, :NAME, :LINK, :IMAGE, :CATEGORY, :PRICE)";
$stmt = $dbh->prepare($sql);
$params = array(
"SHOP" => $xml->getName(),
"ID" => $data->id ,
"NAME" => $data->name,
"LINK" => $data->link,
"IMAGE" => $data->image,
"CATEGORY" => $data->category,
"PRICE" => $data->price_with_vat
);
$stmt->execute($params);
}
//Close Connection
$dbh = null;
} catch(PDOException $e) {
echo $e->getMessage();
}
?>
Site Note:
Add error reporting to the top of your file(s) which will help during production testing.
<?php
error_reporting(E_ALL);
ini_set('display_errors', 1);
?>
Also if you want to show/see the data in html you can use this:
<?php
//Xml stuff
$xml = simplexml_load_file("file.xml");
echo "<table border='1'>";
echo "<tr>
<td>Shop</td>
<td>Product ID</td>
<td>Product Name</td>
<td>Product Link</td>
<td>Product Image</td>
<td>Product Category</td>
<td>Product Price with vat</td>
</tr>";
foreach($xml->products->product as $data) {
echo "<tr>
<td>" . $xml->getName() . "</td>
<td>" . $data->id . "</td>
<td>" . $data->name . "</td>
<td>" . $data->link . "</td>
<td>" . $data->image . "</td>
<td>" . $data->category . "</td>
<td>" . $data->price_with_vat. "</td>
</tr>";
}
echo "</table>";
?>
You are not able to get data because of missing or invalid parent node.
While working with XML needs to handle parent and child(children) node
relationship carefully. Unfortunately you have missed the exact same
thing.
When you use mywebstore node as a parent then its intermediate child node is products and products child node is product.
But when you use products node as a parent then its child node is product.
In your code you have handled the second condition. You have to handle the both conditions or you can use the first condition in your code.
Example:
<?php
$file = 'test.xml';
$xml = simplexml_load_file($file, null, LIBXML_NOCDATA);
if($xml === false){
echo "Failed to load '$file'.\n";
}else{
$productsArr = Array();
if(isset($xml->products)){
$productsArr = $xml->products;
}else if(isset($xml->product)){
$productsArr = $xml;
}
if(sizeof($productsArr) > 0){
foreach($productsArr->product as $productArr){
$productArr = (array) $productArr;
$id = null;
if(isset($productArr['#attributes'])){
$id = $productArr['#attributes']['id'];
unset($productArr['#attributes']);
}
if(!isset($productArr['id']) && !empty($id)){
$productArr['id'] = $id;
}
array_walk_recursive($productArr, function (&$value) {
$value = htmlentities($value,ENT_QUOTES,'UTF-8');
$value = mysql_real_escape_string($value);
});
$col = '`'. implode('`,`',array_keys($productArr)) .'`';
$val = "'". implode("','",array_values($productArr))."'";
$query = "INSERT INTO projectx ($col) VALUES ($val)";
echo "$query \n";
mysql_query($query);
}
}else{
echo "Invalid XML Format.Missing parent node '<mywebstore> or <products>'. \n";
}
}
XML:
Format with <mywebstore> as parent node XML with attribute ID:
`
<?xml version="1.0" encoding="UTF-8"?>
<mywebstore>
<created_at>2010-04-08 12:32</created_at>
<products>
<product id="322233">
<name><![CDATA[MadBiker' 600]]></name>
<link><![CDATA[http://www.mywebstore.co.uk/product/322233]]></link>
<image><![CDATA[http://www.mywebstore.co.uk/product/322233.jpg]]></image>
<category><![CDATA[Outdor > Extreme Sports]]></category>
<price_with_vat>322.33</price_with_vat>
</product>
<product>
<id>322234</id>
<name><![CDATA[MadBiker 700]]></name>
<link><![CDATA[http://www.mywebstore.co.uk/product/322233]]></link>
<image><![CDATA[http://www.mywebstore.co.uk/product/322233.jpg]]></image>
<category><![CDATA[Outdor > Extreme Sports]]></category>
<price_with_vat>344.00</price_with_vat>
</product>
</products>
</mywebstore>
Format with <mywebstore> as parent node XML without attribute ID (Same as Question XML):
`
<?xml version="1.0" encoding="UTF-8"?>
<mywebstore>
<created_at>2010-04-08 12:32</created_at>
<products>
<product>
<id>322233</id>
<name><![CDATA[MadBiker 600]]></name>
<link><![CDATA[http://www.mywebstore.co.uk/product/322233]]></link>
<image><![CDATA[http://www.mywebstore.co.uk/product/322233.jpg]]></image>
<category><![CDATA[Outdor > Extreme Sports]]></category>
<price_with_vat>322.33</price_with_vat>
</product>
</products>
</mywebstore>
`
Format with <products> as parent node XML with attribute ID:
`
<?xml version="1.0" encoding="UTF-8"?>
<products>
<product id="322233">
<name><![CDATA[MadBiker' 600]]></name>
<link><![CDATA[http://www.mywebstore.co.uk/product/322233]]></link>
<image><![CDATA[http://www.mywebstore.co.uk/product/322233.jpg]]></image>
<category><![CDATA[Outdor > Extreme Sports]]></category>
<price_with_vat>322.33</price_with_vat>
</product>
<product>
<id>322234</id>
<name><![CDATA[MadBiker 700]]></name>
<link><![CDATA[http://www.mywebstore.co.uk/product/322233]]></link>
<image><![CDATA[http://www.mywebstore.co.uk/product/322233.jpg]]></image>
<category><![CDATA[Outdor > Extreme Sports]]></category>
<price_with_vat>344.00</price_with_vat>
</product>
</products>
`
Format with <products> as parent node XML without attribute(ID):
`
<?xml version="1.0" encoding="UTF-8"?>
<products>
<product>
<id>322233</id>
<name><![CDATA[MadBiker 600]]></name>
<link><![CDATA[http://www.mywebstore.co.uk/product/322233]]></link>
<image><![CDATA[http://www.mywebstore.co.uk/product/322233.jpg]]></image>
<category><![CDATA[Outdor > Extreme Sports]]></category>
<price_with_vat>322.33</price_with_vat>
</product>
</products>
Conclusion: In valid handling of parents & child node relationship.
Simply change this:
foreach($xml->product as $product)
{
with this:
foreach($xml->products[0] as $product)
{
In order to get the different products you should use xpath
Code:
$xml = simplexml_load_file("xml.xml");
// will search for array of products no matter what it is nested inside of
$products = $xml->xpath('//product');
foreach($products as $product)
{
$columns = array();
$data = array();
foreach($product->children() as $child)
{
echo $child->getName() . ": " . $child . "<br />";
$columns[] = $child->getName();
$data[] = mysql_real_escape_string((string)$child);
}
$col = '`'. implode('`,`',$columns) .'`';
$val = "'". implode("','",$data)."'";
$query = "INSERT INTO XML_FEED ($col) VALUES ($val)";
echo $query;
mysql_query($query);
}
Explanation:
Xpath for simplexml simply returns an array of the simple xml objects or here the product xml elements.
Since we want to return an array of all the products, we search "foreach" occurrence of the product using xpath.
Inside of the xpath string, A double slash (//) signals that all elements in the XML document that match the search criteria are returned, regardless of location/level within the document.
Firstly, simplexml_load_file() returns a pointer to the root element of the XML feed, i.e. the very first XML tag in the input file. In other words, when you write:
$xml = simplexml_load_file("test.xml");
if test.xml contains "<mywebstore> <products> <product> (...)" then $xml points at <mywebstore>
if test.xml contains "<products> <product> (...)" then $xml points at <products>
Secondly, $xml->[tagName] looks for direct children only, not recursively. Therefore $xml->product finds something only if a <product> tag exists as a child of the root element.
In general, it is better for the code to match the input structure exactly. Adapt your outer loop to the expected input:
foreach($xml->product as $product) {
...
}
or
foreach($xml->products->product as $product) {
...
}
If for some reason the <products> tag can be at various locations in the input XML feed, perhaps proceed in two steps:
// try to locate the <product> nodes
if (count($xml->product) !== 0) {
$productNodes = $xml->product;
} else if (count($xml->products->product) !== 0) {
$productNodes = $xml->products->product;
} else {
throw new Exception('No <product> node found');
}
// do the job
foreach($productNodes as $product){
...
}
Or for extreme flexibility, use an xpath. The below will return a list of all <product> nodes anywhere in the XML feed.
$productNodes = $xml->xpath('//product');
foreach($productNodes as $product){
...
}
I trust the MySQL part is not an issue, so I will just stick to the usual incantation:
Please, don't use mysql_* functions in new code. They are no longer maintained and are officially deprecated. See the red box? Learn about prepared statements instead, and use PDO or MySQLi - this article will help you decide which. If you choose PDO, here is a good tutorial.

XML parsing only some nodes - PHP

I have the following example XML:
<PRODUCTRATINGLIST>
<PRODUCT>
<VENDORREF>AC308A~</VENDORREF>
<RATING>100%</RATING>
<REVIEWCOUNT>7</REVIEWCOUNT>
</PRODUCT>
<PRODUCT>
<VENDORREF>AC308C~</VENDORREF>
<RATING>98%</RATING>
<REVIEWCOUNT>89</REVIEWCOUNT>
</PRODUCT>
</PRODUCTRATINGLIST>
I'm simply trying to extract each node under PRODUCT:
$ratings = simplexml_load_file("test.xml");
foreach ($ratings->PRODUCT as $rating){
$part = $rating->VENDORREF;
$rating = str_replace('%','',$rating->RATING);
$numReviews = $rating->REVIEWCOUNT;
}
If I then try to print each element e.g.
echo $part.' '.$rating.' '.$numReviews;
$numReviews is always blank and I have no idea why.
You are replacing the $rating array with a variable, fix it like this:
$part = $rating->VENDORREF;
$rating_string = str_replace('%','',$rating->RATING);
$numReviews = $rating->REVIEWCOUNT;
Check below code. You change the variable names.
$ratings = simplexml_load_file("test.xml");
foreach ($ratings->PRODUCT as $rating){
$part = $rating->VENDORREF;
$ratingVal = str_replace('%','',$rating->RATING);
$numReviews = $rating->REVIEWCOUNT;
}
echo $part.' '.$ratingVal.' '.$numReviews;

foreach shows attributes of first xml node only

I am trying to display attributes foreach global_ivr_variable:
$xml = '
<response method="switchvox.ivr.globalVariables.getList">
<result>
<global_ivr_variables>
<global_ivr_variable id="1" name="cid_name" value="Smith" />
<global_ivr_variable id="2" name="Q_ID_Global" value="COS" />
</global_ivr_variables>
</result>
</response>
';
$sxml = simplexml_load_string($xml);
foreach($sxml->result->global_ivr_variables->global_ivr_variable->attributes() as $a => $b)
{
echo $a .'=' . $b . "<br>";
}
All I get is the attributes of the first node:
id="1"
name="cid_name"
value="Smith"
I've also tried the following, which gives me no values at all...
foreach($sxml->result->global_ivr_variables as $xvar)
{
$a = $xvar->global_ivr_variable->id;
$b = $xvar->global_ivr_variable->name;
$c = $xvar->global_ivr_variable->value;
echo 'a='.$a.', b='.$b.', c='.$c.'<br>';
}
a=, b=, c=
Thank you all who step up to help the needy!
You almost had it but you need to iterate through each of the <global_ivr_variable> elements and then pull out the attributes:
foreach($sxml->result->global_ivr_variables->global_ivr_variable as $variable)
{
foreach($variable->attributes() as $a => $b)
{
echo $a .'=' . $b . "<br>";
}
}
If you make use of PHP variables, those problems normally easily disappear because your code is more readable.
Additionally you can access the attributes in SimpleXML via array-notation:
$variables = $sxml->result->global_ivr_variables->global_ivr_variable;
foreach ($variables as $variable)
{
printf("%s = %s\n", $variable['name'], $variable['value']);
}
This gives the following output:
cid_name = Smith
Q_ID_Global = COS
As you know upfront for which attributes you're looking for, your code is much more clear and stable by using those names.
However, if you're looking for just all attributes of the global_ivr_variable elements, then it's easier to iterate over them with XPath:
$allAttributes = $sxml->xpath('//global_ivr_variable/#*');
foreach ($allAttributes as $attribute) {
printf("%s = %s\n", $attribute->getName(), $attribute);
}
This then gives the following output:
id = 1
name = cid_name
value = Smith
id = 2
name = Q_ID_Global
value = COS
Here is the full code-example:
$xml = <<<XML
<response method="switchvox.ivr.globalVariables.getList">
<result>
<global_ivr_variables>
<global_ivr_variable id="1" name="cid_name" value="Smith" />
<global_ivr_variable id="2" name="Q_ID_Global" value="COS" />
</global_ivr_variables>
</result>
</response>
XML;
$sxml = simplexml_load_string($xml);
$variables = $sxml->result->global_ivr_variables->global_ivr_variable;
foreach ($variables as $variable)
{
printf("%s = %s\n", $variable['name'], $variable['value']);
}
echo "----\n";
$allAttributes = $sxml->xpath('//global_ivr_variable/#*');
foreach ($allAttributes as $attribute) {
printf("%s = %s\n", $attribute->getName(), $attribute);
}

Categories