Check whether the searching attribute exists in a XML file using PHP - php

I have come across couple of similar answers for my question in this form, but could not solve my exact problem. Therefore I am posting this here:
I have an xml file as shown below:
<?xml version="1.0" encoding="ISO-8859-1"?>
<document>
<user>
<user_id>0121</user_id>
<name>Tim</name>
<file>0121.file</file>
</user>
<user>
<user_id>0178</user_id>
<name>Henry</name>
<file>0178.file</file>
</user>
<user>
<user_id>0786</user_id>
<name>Martin</name>
<file>0786.file</file>
</user>
<user>
<user_id>1239</user_id>
<name>Jan</name>
<file>1239.file</file>
</user>
</document>
I ask the user to input his user_id and post this user_id and perform a check on the entire xml file to check whether the entered user_id exists in the xml file or not. If exists then I go further if not echo a error message.
Can anybody pull me out of this?
Thanks

EDIT answer
Forget my previous answer :P
$user_id = '1239';
$xml = new SimpleXMLElement($xml);
$found = false;
foreach($xml->user AS $user) {
if ($user->user_id == $user_id) {
$found = true;
break;
}
}
if (!found) echo 'error';

You could use DOMDocument with DOMXpath query, an example :-
$doc = new DOMDocument;
$doc->load(...);
$xpath = new DOMXPath($doc);
$query = '//user/user_id[.="0121"]';
$entries = $xpath->query($query);
if ( $entries->length )
{
// found
}

Related

Webhook XML always empty

I'm using recurly webhooks to update contacts, but the XML is always empty, here's what I've tried:
$xmlString = file_get_contents('php://input');
$dom = new DomDocument();
$dom->loadXML($xmlString);
however when I look into the file, it is always empty:
$rsn = $dom->getElementsByTagName('successful_payment_notification');
if($rsn->length != 0){
//.. do something
}
but I've noticed that the $dom is always empty, here's what the XML recurly sends:
<?xml version="1.0" encoding="UTF-8"?>
<successful_payment_notification>
<account>
<account_code>89728427a3caa0b21b2ds31223c0fad6f443b82</account_code>
<first_name>Michael</first_name>
<last_name>Scott</last_name>
<company_name nil="true"></company_name>
<phone nil="true"></phone>
</account>
<transaction>
<id>467fc116288ab89c8d7c954bbca565a8</id>
<invoice_id>467fc11613dcd438d4410c4ca0bc03e8</invoice_id>
<invoice_number_prefix></invoice_number_prefix>
<invoice_number type="integer">1379</invoice_number>
<test type="boolean">false</test>
<voidable type="boolean">false</voidable>
<refundable type="boolean">true</refundable>
</transaction>
</successful_payment_notification>
allow_url_fopen is On, not sure what could be causing this, I'm using AWS Lightsail and Bitnami.
I've found the answer, I changed it to this:
$xml = new SimpleXMLElement(file_get_contents('php://input'));
$data = json_decode(json_encode($xml), true);
switch ($xml->getName()) {
case "renewed_subscription_notification":
sendEmail("renewed_subscription_notification");
break;
}

How do I edit an XML file in SimpleXML, based on the contents of the XML, if there are multiple values of the same tag?

Say I have an XML file like this.
<users>
<user>
<username>desbest</username>
<email>desbest#example.com</email>
<password>testpass1</password>
</user>
<user>
<username>demo</username>
<email>nobody#example.com</email>
<password>demo</password>
</user>
</users>
How do I use XPath to select the desbest user, then use php to edit the password under the desbest user, and save it as a file?
I have searched Google and Stack Overflow and I haven't found the answer.
Here is my current code.
// print_r($xml);
$newpass = "mynewpass";
// $newpass = password_hash($newpass, PASSWORD_DEFAULT);
$nodes = $xml->xpath(sprintf(" //users/user[(username = \"$myusername\")] "));
// print_r($nodes);
// $nodes[0]->password = "$newpass";
$domnode = dom_import_simplexml($nodes[0]);
$nodepath = $domnode->getNodePath();
// $xml = $xml->$nodepath->password = $newpass;
// $danodepath = $nodes[0]->getNodePath();
// print_r($nodes);
// $xml->users->user["(username = \"$myusername\")"] = "$newpass";
print_r($xml);
echo "<hr>";
print_r($nodepath);
You can achieve this just with SimpleXML - you don't need to involve DOMDocument at all.
The xpath method returns the <user> element you're looking for. You can then modify it simply by updating the password property (or add new ones, or attributes, etc). This updates the underlying SimpleXMLElement object, which you can then write back to the file as a string using asXML.
$filename = 'file.xml';
$sxml = simplexml_load_file($filename);
$username = "desbest";
$user = $sxml->xpath("./user[./username = '{$username}']")[0];
$user->password = 'testpassCHANGED';
file_put_contents($filename, $sxml->asXML());
See https://eval.in/923654 for an example
Example with DOMDocument:
$source = '<users>
<user>
<username>desbest</username>
<email>desbest#example.com</email>
<password>testpass1</password>
</user>
<user>
<username>demo</username>
<email>nobody#example.com</email>
<password>demo</password>
</user>
</users>';
$dom = new DOMDocument();
$dom->preserveWhiteSpace = false;
$dom->formatOutput = true;
$dom->loadXML($source);
$xpath = new DOMXPath($dom);
$myusername = htmlspecialchars("desbest", ENT_XML1 | ENT_QUOTES, 'UTF-8');
$expression = sprintf('/users/user[(username="%s")]', $myusername);
$users = $xpath->query($expression);
if($users->length) {
$user = $users->item(0);
$password = $xpath->query('password', $user)->item(0);
$password->nodeValue = 'new password';
}
file_put_contents('filename.xml', $dom->saveXML());

How to get second sibling with xpath from xml

This is my structure:
<Users>
<User>
<username>admin</username>
<server>10.xx.xx.xx</server>
<image>images/pic.png</image>
</User>
<User>
<username>bob</username>
<server>10.xx.xx.xx</server>
<image>images/pic2.png</image>
</User>
</Users>
Now I have this code that gets me a server value from node which has certain username that I am searching for.
$query = '//Users/User/username[. = "'.$_SESSION['SESS_FIRST_NAME'].'"]';
$entries = $xpath->query($query);
foreach ($entries as $entry) {
//Getting the "server" node value
$server=$entry->nextSibling->nextSibling->nodeValue;
//I wanted to have one more variable here which will save me the image string in the global php variable
$images=$entry->nextSibling->nextSibling->nextSibling->nodeValue; //this is giving me a server value instead of image value
}
Unless the schema of the document explicitly states otherwise I wouldn't rely on the order of elements but either query the elements via xpath by passing the user element as context node (see example) or iterate over the child elements of the user element and fetch what is needed (e.g. in an php array).
<?php
$doc = new DOMDOcument;
$doc->loadxml( getData() );
$xpath = new DOMXPath( $doc );
$query = '/Users/User[username= "'.'bob'.'"]';
foreach( $xpath->query($query) as $user ) {
$username = singleNodeValue($xpath->query('username', $user)); // ok, you already have this one....
$server = singleNodeValue($xpath->query('server', $user));
$image = singleNodeValue($xpath->query('image', $user));
printf("%s, %s, %s\r\n", $username, $server, $image);
}
function singleNodeValue($nodeset) {
// add tests here....
return $nodeset->item(0)->nodeValue;
}
function getData() {
return <<< eox
<Users>
<User>
<username>admin</username>
<server>10.xx.xx.xx</server>
<image>images/pic.png</image>
</User>
<User>
<username>bob</username>
<server>10.xx.xx.xx</server>
<image>images/pic2.png</image>
</User>
</Users>
eox;
}
prints
bob, 10.xx.xx.xx, images/pic2.png

PHP DOMDocument getting element data with particular attribute name

The XML
<?xml version="1.0"?>
<items version="1.5">
<item name="device">iphone</item>
<item name="affinity">testing</item>
</items>
I need to get the value 'iphone' and value 'testing' from device and affinity, how do I select them?
I've tried:
$xml = new DOMDocument();
$xml->loadXML($request);
$itemList = $xml->getElementsByTagName('item');
foreach($itemList as $install)
{
echo $install->getAttribute('device')->item(0)->nodeValue;
}
But that doesn't seem to work.
Thank you!
Something like this may do:
$Device;
$Affinity;
foreach($itemList as $install)
{
if($install->getAttribute('name') =='device'){
$Device = $install->nodeValue;
}
if($install->getAttribute('name')=='affinity'){
$Affinity = $install->nodeValue;
}
}

How do I remove a specific node using its attribute value in PHP XML Dom?

My question is best phrase as:
Remove a child with a specific attribute, in SimpleXML for PHP
except I'm not using simpleXML.
I'm new to XML for PHP so I may not be doing the best way
I have a xml created using the $dom->save($xml) for each individual user. (not placing all in one xml due to undisclosed reasons)
It gives me that xml declaration <?xml version="1.0"?> (no idea how to make it to others, but that's not the point, hopefully)
<?xml version="1.0"?>
<details>
<person>name</person>
<data1>some data</data1>
<data2>some data</data2>
<data3>some data</data3>
<category id="0">
<categoryName>Cat 1</categoryName>
<categorydata1>some data</categorydata1>
</category>
<category id="1">
<categoryName>Cat 2</categoryName>
<categorydata1>some data</categorydata1>
<categorydata2>some data</categorydata2>
<categorydata3>some data</categorydata3>
<categorydata4>some data</categorydata4>
</category>
</details>
And I want to remove a category that has a specific attribute named id with the DOM class in php when i run a function activated from using a remove button.
the following is the debug of the function im trying to get to work. Can i know what I'm doing wrong?
function CatRemove($myXML){
$xmlDoc = new DOMDocument();
$xmlDoc->load( $myXML );
$categoryArray = array();
$main = $xmlDoc->getElementsByTagName( "details" )->item(0);
$mainElement = $xmlDoc->getElementsByTagName( "details" );
foreach($mainElement as $details){
$currentCategory = $details->getElementsByTagName( "category" );
foreach($currentCategory as $category){
$categoryID = $category->getAttribute('id');
array_push($categoryArray, $categoryID);
if($categoryID == $_POST['categorytoremoveValue']) {
return $categoryArray;
}
}
}
$xmlDoc->save( $myXML );
}
Well the above prints me an array of [0]->0 all the time when i slot the return outside the if.
is there a better way? I've tried using getElementbyId as well but I've no idea how to work that.
I would prefer not to use an attribute though if that would make things easier.
Ok, let’s try this complete example of use:
function CatRemove($myXML, $id) {
$xmlDoc = new DOMDocument();
$xmlDoc->load($myXML);
$xpath = new DOMXpath($xmlDoc);
$nodeList = $xpath->query('//category[#id="'.(int)$id.'"]');
if ($nodeList->length) {
$node = $nodeList->item(0);
$node->parentNode->removeChild($node);
}
$xmlDoc->save($myXML);
}
// test data
$xml = <<<XML
<?xml version="1.0"?>
<details>
<person>name</person>
<data1>some data</data1>
<data2>some data</data2>
<data3>some data</data3>
<category id="0">
<categoryName>Cat 1</categoryName>
<categorydata1>some data</categorydata1>
</category>
<category id="1">
<categoryName>Cat 2</categoryName>
<categorydata1>some data</categorydata1>
<categorydata2>some data</categorydata2>
<categorydata3>some data</categorydata3>
<categorydata4>some data</categorydata4>
</category>
</details>
XML;
// write test data into file
file_put_contents('untitled.xml', $xml);
// remove category node with the id=1
CatRemove('untitled.xml', 1);
// dump file content
echo '<pre>', htmlspecialchars(file_get_contents('untitled.xml')), '</pre>';
So you want to remove the category node with a specific id?
$node = $xmlDoc->getElementById("12345");
if ($node) {
$node->parentNode->removeChild($node);
}
You could also use XPath to get the node, for example:
$xpath = new DOMXpath($xmlDoc);
$nodeList = $xpath->query('//category[#id="12345"]');
if ($nodeList->length) {
$node = $nodeList->item(0);
$node->parentNode->removeChild($node);
}
I haven’t tested it but it should work.
Can you try with this modified version:
function CatRemove($myXML, $id){
$doc = new DOMDocument();
$doc->loadXML($myXML);
$xpath = new DOMXpath($doc);
$nodeList = $xpath->query("//category[#id='$id']");
foreach ($nodeList as $element) {
$element->parentNode->removeChild($element);
}
echo htmlentities($doc->saveXML());
}
It's working for me. Just adapt it to your needs. It's not intended to use as-is, but just a proof of concept.
You also have to remove the xml declaration from the string.
the above funciton modified to remove an email from a mailing list
function CatRemove($myXML, $id) {
$xmlDoc = new DOMDocument();
$xmlDoc->load($myXML);
$xpath = new DOMXpath($xmlDoc);
$nodeList = $xpath->query('//subscriber[#email="'.$id.'"]');
if ($nodeList->length) {
$node = $nodeList->item(0);
$node->parentNode->removeChild($node);
}
$xmlDoc->save($myXML);
}
$xml = 'list.xml';
$to = $_POST['email'];//user already submitted they email using a form
CatRemove($xml,$to);

Categories