Avatar of Dreammonkey
Dreammonkey
Flag for Belgium asked on

Write a PHP script that manipulates an XML file

Hi all,
I made a flash movie that reads in data from an XML file
There is a form in the movie that the user can fill out, when the user clicks the SAVE button the data gets sent out through variables to a php file. The php file receives the data and generates an XML file.

This is actually working, but,
I want the PHP file to read in the old XML file first and then adding the new Vars to it, and that 's where you guys could help me, I found some exampes on the net, but I can't figure out how they actually work.

My XML is strucured like this :

<?xml version="1.0" encoding="ISO-8859-1"?>
<gigs>
<gig       day="07" month="06" year="2008"
      venue="Kavka"
      time="20.00u"
      info="met La Femme Belge"
      address="Oudaan 14"
      location="Antwerpen"
      moreInfo="Dubbelconcert, met The Valerie Solanas & La Femme Belge."
      link1="www.myspace.com/lafemmebelge"
      link2="www.kavka.be"
/>
</gigs>

As you would have guessed I want to add a child like this <gig day="**" month="**" ... /> between the <gigs> .... </gigs> Parent Nodes .

My current PHP script in the Snippet below...

PS: If this works I want to add a featue that can update/remove data as well, but hey, first things first !
PPS: I know this is sort of thing is usually done using databases, but I prefer getting it done this way...
PPS: here is a link to the Flash Movie : http://www.thevaleriesolanas.be/editgigs/editgigs.html 
I surely hope you can help me out !

Regards,
Dreammonkey
<?php
 
$day = $_POST['day'];
$month = $_POST['month'];
$year = $_POST['year'];
$venue = $_POST['venue'];
$time = $_POST['time'];
$info = $_POST['info'];
$address = $_POST['address'];
$location = $_POST['location'];
$moreInfo = $_POST['moreInfo'];
$link1 = $_POST['link1'];
$link2 = $_POST['link2'];
 
 
$myFile = "test.xml";
$fh = fopen($myFile, 'w') or die("can't open file");
 
$stringData = "<?xml version=\"1.0\" encoding=\"ISO-8859-1\"?><gigs><gig day=\"" . $day . "\" month=\"" . $month . "\" year=\"" . $year . "\" venue=\"" . $venue . "\" time=\"" . $time . "\" info=\"" . $info . "\" address=\"" . $address . "\" location=\"" . $location . "\" moreInfo=\"" . $moreInfo . "\" link1=\"" . $link1 . "\" link2=\"" . $link2 . "\"/></gigs>";
 
fwrite($fh, $stringData);
 
 
if($fh) {  
echo "&verify=success&"; 
} else {  
echo "&verify=fail&"; 
}
 
fclose($fh);
 
?>

Open in new window

PHPAdobe FlashXML

Avatar of undefined
Last Comment
Dreammonkey

8/22/2022 - Mon
bslorence

Just a tip which isn't directly related to the question but could save you a lot of headaches in the future: validate your input data and escape the data that you write to the XML file. Maybe the code you posted above is skeletal and you're planning to add validation and escaping later, but if not, you should be. Since the data is user-supplied it could be anything, and it's crucial for application security that you make sure that the data actually conforms to the specs you expect of it.

E.g., if you're assuming that the value of $_POST['day'] is a 2-digit numeric string, make sure it is before you write it to your XML file. If you're assuming that $_POST['link2'] is a well-formed URL, make sure it is.

And then wrap each variable in a call to PHP's htmlentities() before you concatenate it into the XML string. This will help avoid injection vulnerabilities and it will also help keep your XML valid.

For your question... are you familiar at all with PHP's XML libraries? Maybe a bit much for what you're trying to do and the learning curve might be a bit steep, but if you want to make your script more complex in the future it might pay off to handle the XML abstractly from the beginning rather than "hand-coding" it in your PHP:

http://us2.php.net/manual/en/refs.xml.php
Dreammonkey

ASKER
Hi bsLorence,

Let me put it this way, I do appreciate your remark, however I subscribed to Experts-Exchange to learn, so yes, I do want to make my script more stable ! But then I need it to make it work first, don't you think?

I'm an amature myself, I'm already amazed by what I did, although I'm sure you think it's a big laugh...

Nevertheless, if you could put me on my way... You think the DOMDocument is the right way to go here?

Regards
D
Dreammonkey

ASKER
Actually the input fileld in the movie for the day-field only accepts 2 characters, I should maybe find a way to make it accept only digits as well?...
All of life is about relationships, and EE has made a viirtual community a real community. It lifts everyone's boat
William Peck
bslorence

I don't think it's a big laugh, everyone has to start somewhere. Application security is extremely important and probably not as well-understood as it ought to be. So I'm happy to point some things out that are obvious to me, but might not be to everyone else. Here's a good blog for PHP security ideas; you can learn a huge amount by browsing through the archives:

http://shiflett.org/

Adjusting your Flash to accept only digits would be helpful for well-intentioned users, but it doesn't solve the security problem, because anyone can send a POST request to your PHP script, without even using the Flash. So you absolutely have to do the validation on the server-side, no matter how much validation you might also do on the client-side.

DOMDocument might be overkill; it's geared more toward manipulating standardized XML dialects. Maybe SimpleXML would be better:

http://uk2.php.net/manual/en/book.simplexml.php

I'm sure there are other libraries that would work as well; I actually don't have much experience manipulating XML in PHP -- just know that it can be done via an API rather than directly and that in the long run that approach may serve you better than trying to manipulate XML as raw strings of data. If you just want to insert a <gig>...</gig> record and nothing else, you could just do something very simple like the attached. But as you mentioned in the first post, you have bigger plans for the script so it would probably pay off to learn how to use an XML API.


/*
 * Assume that the variable $original_xml contains a raw XML string
 * with a <gigs> element.
 */
 
$new_gig = "<gig>...</gig>";
$new_xml = str_replace("<gigs>", "<gigs>$new_gig", $original_xml);
 
/*
 * Now $new_xml contains the raw XML with the additional <gig> element
 * inserted at the top of the <gigs> element.
 */ 

Open in new window

bslorence

Oops, didn't notice that your <gig> element doesn't need a closing tag. Replace line 6 in my sample with what's below. The "..." is where your gig data would go, of course.
$new_gig = "<gig ... />";

Open in new window

bslorence

I just looked at the Flash and it made me think of one more security pointer: if you're going to allow HTML in the "info" attribute, read up on XSS vulnerabilities. You'll find plenty of good information on Chris Shiflett's blog. Here again PHP's htmlentities() function is your friend. ;-)
⚡ FREE TRIAL OFFER
Try out a week of full access for free.
Find out why thousands trust the EE community with their toughest problems.
Dreammonkey

ASKER
Hey man, thanks for all the tips, I'll certainly look into those, unfortunately, I still haven't cracked this one...

the <gig  ...  /> issue I saw right away, but there mustr be something else, what about the "<?xml version=\"1.0\" encoding=\"ISO-8859-1\"?> bit...?

also the writing method w, a ,w+ a+ ?

code below anyway...
<?php
 
$day = $_POST['day'];
$month = $_POST['month'];
$year = $_POST['year'];
$venue = $_POST['venue'];
$time = $_POST['time'];
$info = $_POST['info'];
$address = $_POST['address'];
$location = $_POST['location'];
$moreInfo = $_POST['moreInfo'];
$link1 = $_POST['link1'];
$link2 = $_POST['link2'];
 
 
$myFile = "test.xml";
$fh = fopen($myFile, 'w') or die("can't open file");
 
$new_gig = "<gigs><gig day=\"" . $day . "\" month=\"" . $month . "\" year=\"" . $year . "\" venue=\"" . $venue . "\" time=\"" . $time . "\" info=\"" . $info . "\" address=\"" . $address . "\" location=\"" . $location . "\" moreInfo=\"" . $moreInfo . "\" link1=\"" . $link1 . "\" link2=\"" . $link2 . "\"/></gigs>"
 
$subject = "<gigs>"
 
$stringData = str_replace("<gigs>", $new_gig, $subject);
 
 
fwrite($fh, $stringData);
 
 
if($fh) {  
echo "&verify=success&"; 
} else {  
echo "&verify=fail&"; 
}
 
fclose($fh);
 
?>

Open in new window

Dreammonkey

ASKER
Ok maybe you can help me out on this one then ...

I found some great code at : http://mysrc.blogspot.com/2007/02/php-xml-to-array-and-backwards.html 

I implemented the code and it seems to work fine but
when I try to change an attributes value only the first Character changes the rest of the value stays as the original value, very strange...

PS, I changed the structure of the XML back  to :

<?xml version='1.0' encoding='ISO-8859-1'?>
<gigs>
<gig id="1" day="01" month="01" year="2000" venue="New York" />
<gig id="2" day="02" month="01" year="2000" venue="Berlin" />
</gigs>

<?php
$xml=xml2ary(file_get_contents('gig.xml'));
 
print_r($xml);
 
$venue = "HOTELLLLLLLLLLLLLLLLLLLLLLLLL";
 
$xml['gigs']['_c']['gig']['1']['_a']['venue']['_v']= $venue ;
 
print_r($xml);
 
/*	
<ddd>    
	<onemore dd="55">
	        <tt>333</tt>
	        <tt ss="s1">555</tt>
	        <tt>777</tt>
	    </onemore>    
	<two>sdf rr</two>
</ddd>
 
 
 
 
Working with XML. Usage:
    $xml=xml2ary(file_get_contents('1.xml'));
    $link=&$xml['ddd']['_c'];
    $link['twomore']=$link['onemore'];
    // ins2ary();// dot not insert a link, and arrays with links inside!
    echo ary2xml($xml);
*/
// XML to Array
function xml2ary(&$string) {
    $parser = xml_parser_create();
    xml_parser_set_option($parser, XML_OPTION_CASE_FOLDING, 0);
    xml_parse_into_struct($parser, $string, $vals, $index);
    xml_parser_free($parser);
    $mnary=array();
    $ary=&$mnary;
    foreach ($vals as $r) {
        $t=$r['tag'];
        if ($r['type']=='open') {
            if (isset($ary[$t])) {
                if (isset($ary[$t][0])) $ary[$t][]=array();
 else $ary[$t]=array($ary[$t], array());
                $cv=&$ary[$t][count($ary[$t])-1];
            } else $cv=&$ary[$t];
            if (isset($r['attributes'])) {foreach ($r['attributes'] as $k=>$v) $cv['_a'][$k]=$v;
}            $cv['_c']=array();
            $cv['_c']['_p']=&$ary;
            $ary=&$cv['_c'];
        } elseif ($r['type']=='complete') {
            if (isset($ary[$t])) {// same as open
                if (isset($ary[$t][0])) $ary[$t][]=array();
 else $ary[$t]=array($ary[$t], array());
                $cv=&$ary[$t][count($ary[$t])-1];
            } else $cv=&$ary[$t];
            if (isset($r['attributes'])) {foreach ($r['attributes'] as $k=>$v) $cv['_a'][$k]=$v;}
            $cv['_v']=(isset($r['value']) ? $r['value'] : '');
        } elseif ($r['type']=='close') {
            $ary=&$ary['_p'];
        }
    }
    _del_p($mnary);
    return $mnary;
}
// _Internal: Remove recursion in result array
function _del_p(&$ary) {
    foreach ($ary as $k=>$v) {
        if ($k==='_p') unset($ary[$k]);
        elseif (is_array($ary[$k])) _del_p($ary[$k]);
    }
}
// Array to XML
function ary2xml($cary, $d=0, $forcetag='') {
    $res=array();
    foreach ($cary as $tag=>$r) {
        if (isset($r[0])) {
            $res[]=ary2xml($r, $d, $tag);
        } else {
            if ($forcetag) $tag=$forcetag;
            $sp=str_repeat("\t", $d);
            $res[]="$sp<$tag";
            if (isset($r['_a'])) {foreach ($r['_a'] as $at=>$av) $res[]=" $at=\"$av\"";}
            $res[]=">".((isset($r['_c'])) ? "\n" : '');
            if (isset($r['_c'])) $res[]=ary2xml($r['_c'], $d+1);
            elseif (isset($r['_v'])) $res[]=htmlspecialchars($r['_v']);
            $res[]=(isset($r['_c']) ? $sp : '')."</$tag>\n";
        }
      
    }
    return implode('', $res);
}
// Insert element into array
function ins2ary(&$ary, $element, $pos) {
    $ar1=array_slice($ary, 0, $pos); $ar1[]=$element;
    $ary=array_merge($ar1, array_slice($ary, $pos));
}
?> 

Open in new window

ASKER CERTIFIED SOLUTION
Dreammonkey

THIS SOLUTION ONLY AVAILABLE TO MEMBERS.
View this solution by signing up for a free trial.
Members can start a 7-Day free trial and enjoy unlimited access to the platform.
See Pricing Options
Start Free Trial
GET A PERSONALIZED SOLUTION
Ask your own question & get feedback from real experts
Find out why thousands trust the EE community with their toughest problems.