Solved

PHP: simpleXMLElement--checking for nodes

Posted on 2013-06-04
17
292 Views
Last Modified: 2013-07-02
Hello,

I am passing in an XML string from another page and loading into a SimpleXMLElement.  I suspect that occasionally the page that is sending the string sends data that is corrupt and I would like to check for children/nodes before building a SQL string that will execute a Delete statement in the database.  My code is below.  Basically I want to stop the execution of the Delete statement if there are no elements or if $myevents does not have elements.  

The third-party plugin I am using loads appointments from the database and allows the user to make changes on the screen.  When they click "save" the latest set of appointments is sent via Post to the PHP file.  I thought the code would only delete the records that are in the database but no longer in the latest XML string sent from the app.  However, occasionally it wipes out all appointments for the time range which leads me to believe that the SimpleXMLElement is either not formed correctly or the 'Post" didn't work correctly and I would like to stop the deleting process in this case....

Any ideas?  I hope I have explained myself so that you can follow.  Thanks in advance!

 

$myevents = new simpleXMLElement($xml_str);

$query3 = "DELETE FROM dbo.Vacations WHERE EXISTS (SELECT * FROM dbo.Vacations WHERE dbo.Vacations.VacationID <> 10000000 AND ";
	
if($myevents->event->id && $myevents->event->id != ''){

foreach($myevents->event as $e){ 
	$numdigits = strlen($e->id);
		If ($numdigits < 13){
			$query3 = $query3." DBO.VACATIONS.VACATIONID <> CONVERT(INT,'".$e->id."') AND ";
			
		}
...

Open in new window

0
Comment
Question by:1Cougar
[X]
Welcome to Experts Exchange

Add your voice to the tech community where 5M+ people just like you are talking about what matters.

  • Help others & share knowledge
  • Earn cash & points
  • Learn & ask questions
  • 8
  • 8
17 Comments
 
LVL 110

Expert Comment

by:Ray Paseur
ID: 39218621
The key data element appears to be $xml_str.  Can we please have a sample of this data to work with?

The class constructor is documented here.
http://php.net/manual/en/simplexmlelement.construct.php

Excerpt from the man page:
Errors/Exceptions

Produces an E_WARNING error message for each error found in the XML data and additionally throws an Exception if the XML data could not be parsed.
Tip

Use libxml_use_internal_errors() to suppress all XML errors, and libxml_get_errors() to iterate over them afterwards.
0
 

Author Comment

by:1Cougar
ID: 39218638
Here is a sample of the XML sent via "POST".  It generally works fine, but occasionally (and I am wondering if it might be due to the user returning to the page after a long period of time where they look still logged on but the data has expired...I think I need to force logout after x minutes...not sure how to do this) the XML seems to be either empty, corrupt or not parsable and the delete statement gets executed...meaning it deletes all appointments instead of only deleting the appointments that are no longer in the latest XML being sent to page.

<data><event>
<id><![CDATA[35520]]></id>
<start_date><![CDATA[2013-05-23 15:30]]></start_date>
<end_date><![CDATA[2013-05-23 17:00]]></end_date>
<text><![CDATA[Belkebir / Lebigre - #1782]]></text>
<activityID><![CDATA[1636]]></activityID>
<color><![CDATA[#7DF5DF]]></color>
<textColor><![CDATA[Black]]></textColor>
<thisType><![CDATA[1]]></thisType>
</event>
<event>
<id><![CDATA[35726]]></id>
<start_date><![CDATA[2013-05-28 11:00]]></start_date>
<end_date><![CDATA[2013-05-28 12:30]]></end_date>
<text><![CDATA[Belkebir / Lebigre - #1782]]></text>
<activityID><![CDATA[1636]]></activityID>
<color><![CDATA[#7DF5DF]]></color>
<textColor><![CDATA[Black]]></textColor>
<thisType><![CDATA[1]]></thisType>
</event>
<event>
<id><![CDATA[35728]]></id>
<start_date><![CDATA[2013-06-05 15:30]]></start_date>
<end_date><![CDATA[2013-06-05 17:00]]></end_date>
<text><![CDATA[Belkebir / Lebigre - #1782]]></text>
<activityID><![CDATA[1636]]></activityID>
<color><![CDATA[#7DF5DF]]></color>
<textColor><![CDATA[Black]]></textColor>
<thisType><![CDATA[1]]></thisType>
</event>
<event>
<id><![CDATA[35859]]></id>
<start_date><![CDATA[2013-05-14 14:00]]></start_date>
<end_date><![CDATA[2013-05-14 15:30]]></end_date>
<text><![CDATA[Besnard / Galopin - #1783]]></text>
<activityID><![CDATA[1637]]></activityID>
<color><![CDATA[#7DF5DF]]></color>
<textColor><![CDATA[Black]]></textColor>
<thisType><![CDATA[1]]></thisType>
</event>
<event>
<id><![CDATA[35860]]></id>
<start_date><![CDATA[2013-05-21 14:00]]></start_date>
<end_date><![CDATA[2013-05-21 15:30]]></end_date>
<text><![CDATA[Besnard / Galopin - #1783]]></text>
<activityID><![CDATA[1637]]></activityID>
<color><![CDATA[#7DF5DF]]></color>
<textColor><![CDATA[Black]]></textColor>
<thisType><![CDATA[1]]></thisType>
</event>
<event>
<id><![CDATA[35519]]></id>
<start_date><![CDATA[2013-05-23 14:00]]></start_date>
<end_date><![CDATA[2013-05-23 15:30]]></end_date>
<text><![CDATA[Cimbe / Lefevre - #1786]]></text>
<activityID><![CDATA[1640]]></activityID>
<color><![CDATA[#7DF5DF]]></color>
<textColor><![CDATA[Black]]></textColor>
<thisType><![CDATA[1]]></thisType>
</event>
<event>
<id><![CDATA[35729]]></id>
<start_date><![CDATA[2013-06-07 11:00]]></start_date>
<end_date><![CDATA[2013-06-07 12:30]]></end_date>
<text><![CDATA[Cimbe / Lefevre - #1786]]></text>
<activityID><![CDATA[1640]]></activityID>
<color><![CDATA[#7DF5DF]]></color>
<textColor><![CDATA[Black]]></textColor>
<thisType><![CDATA[1]]></thisType>
</event></data>

Open in new window

0
Give Your Engineering Team a Productivity Boost

Learn why container technology is so powerful and how it can provide your team with productivity gains and other benefits.

 
LVL 110

Expert Comment

by:Ray Paseur
ID: 39218643
user returning to the page after a long period of time...
That's interesting.  Is any important data kept in the PHP session?  If so, you've always got that risk.  Client logs in, client clicks a link that sets some session data, client gets distracted, client clicks a link... Poof!
0
 

Author Comment

by:1Cougar
ID: 39218695
Well, I am using DHTMLX Scheduler.  I am not sure I understand how/where the appointments are being stored....I was thinking if I force logout for inactivity after 10 minutes that would cover that base.  But, being a rather newbie to PHP not sure how to do this.

Do you think that could be the issue?
0
 
LVL 110

Accepted Solution

by:
Ray Paseur earned 500 total points
ID: 39218754
See line 77, et seq.  It might be possible to simplify this query.  Just use a straight DELETE instead of the compound DELETE and SELECT, maybe?

<?php // RAY_temp_1cougar.php
error_reporting(E_ALL);

$xml = <<<EOD
<data><event>
<id><![CDATA[35520]]></id>
<start_date><![CDATA[2013-05-23 15:30]]></start_date>
<end_date><![CDATA[2013-05-23 17:00]]></end_date>
<text><![CDATA[Belkebir / Lebigre - #1782]]></text>
<activityID><![CDATA[1636]]></activityID>
<color><![CDATA[#7DF5DF]]></color>
<textColor><![CDATA[Black]]></textColor>
<thisType><![CDATA[1]]></thisType>
</event>
<event>
<id><![CDATA[35726]]></id>
<start_date><![CDATA[2013-05-28 11:00]]></start_date>
<end_date><![CDATA[2013-05-28 12:30]]></end_date>
<text><![CDATA[Belkebir / Lebigre - #1782]]></text>
<activityID><![CDATA[1636]]></activityID>
<color><![CDATA[#7DF5DF]]></color>
<textColor><![CDATA[Black]]></textColor>
<thisType><![CDATA[1]]></thisType>
</event>
<event>
<id><![CDATA[35728]]></id>
<start_date><![CDATA[2013-06-05 15:30]]></start_date>
<end_date><![CDATA[2013-06-05 17:00]]></end_date>
<text><![CDATA[Belkebir / Lebigre - #1782]]></text>
<activityID><![CDATA[1636]]></activityID>
<color><![CDATA[#7DF5DF]]></color>
<textColor><![CDATA[Black]]></textColor>
<thisType><![CDATA[1]]></thisType>
</event>
<event>
<id><![CDATA[35859]]></id>
<start_date><![CDATA[2013-05-14 14:00]]></start_date>
<end_date><![CDATA[2013-05-14 15:30]]></end_date>
<text><![CDATA[Besnard / Galopin - #1783]]></text>
<activityID><![CDATA[1637]]></activityID>
<color><![CDATA[#7DF5DF]]></color>
<textColor><![CDATA[Black]]></textColor>
<thisType><![CDATA[1]]></thisType>
</event>
<event>
<id><![CDATA[35860]]></id>
<start_date><![CDATA[2013-05-21 14:00]]></start_date>
<end_date><![CDATA[2013-05-21 15:30]]></end_date>
<text><![CDATA[Besnard / Galopin - #1783]]></text>
<activityID><![CDATA[1637]]></activityID>
<color><![CDATA[#7DF5DF]]></color>
<textColor><![CDATA[Black]]></textColor>
<thisType><![CDATA[1]]></thisType>
</event>
<event>
<id><![CDATA[35519]]></id>
<start_date><![CDATA[2013-05-23 14:00]]></start_date>
<end_date><![CDATA[2013-05-23 15:30]]></end_date>
<text><![CDATA[Cimbe / Lefevre - #1786]]></text>
<activityID><![CDATA[1640]]></activityID>
<color><![CDATA[#7DF5DF]]></color>
<textColor><![CDATA[Black]]></textColor>
<thisType><![CDATA[1]]></thisType>
</event>
<event>
<id><![CDATA[35729]]></id>
<start_date><![CDATA[2013-06-07 11:00]]></start_date>
<end_date><![CDATA[2013-06-07 12:30]]></end_date>
<text><![CDATA[Cimbe / Lefevre - #1786]]></text>
<activityID><![CDATA[1640]]></activityID>
<color><![CDATA[#7DF5DF]]></color>
<textColor><![CDATA[Black]]></textColor>
<thisType><![CDATA[1]]></thisType>
</event></data>
EOD;

// MAKE AN OBJECT AND HANDLE ERRORS
libxml_use_internal_errors(TRUE);
$obj = SimpleXML_Load_String($xml, 'SimpleXMLElement', LIBXML_NOCDATA);

// IF THE OBJECT IS EMPTY OR FALSE
if (!$obj)
{
    // IF THE OBJECT IS FALSE, XML FAILURE OCCURRED
    if ($obj === FALSE)
    {
        echo PHP_EOL . "XML FAIL";
        foreach(libxml_get_errors() as $error)
        {
            echo PHP_EOL . $error->message;
        }
        trigger_error('XML FAILURE', E_USER_ERROR());
    }

    // IF THE XML WAS EMPTY, THE OBJECT IS EMPTY
    else
    {
        echo PHP_EOL . "XML EMPTY";
    }
}

// IF THE OBJECT IS USEFUL, CONSTRUCT THE QUERY
else
{
    $query3 = "DELETE FROM dbo.Vacations WHERE EXISTS (SELECT * FROM dbo.Vacations WHERE dbo.Vacations.VacationID <> 10000000 AND ";
    foreach($obj->event as $e)
    {
        $numdigits = strlen($e->id);
        if ($numdigits < 13)
        {
            $query3 = $query3." DBO.VACATIONS.VACATIONID <> CONVERT(INT,'$e->id') AND ";
        }
    }

    // SHOW THE QUERY STRING
    var_dump($query3);
}

Open in new window

0
 
LVL 110

Expert Comment

by:Ray Paseur
ID: 39218765
I don't know DHTMLX Scheduler.  PHP sessions "expire" after 24 minutes of inactivity.  The whole session process is rather complicated since it involves HTML cookies, and a garbage collector scheme.  The PHP session cookie is set with an expiration time of zero, which means "discard the cookie when the browser is closed."  Inactivity is defined as an absence of HTTP requests.

You can find out what is in the PHP session by executing these two instructions:

session_start();
var_dump($_SESSION);

That said, your PHP installation may have other settings for the session, including auto-start and a different garbage collection cycle.  I don't think the difference between 24 minutes of inactivity and 10 minutes of inactivity is very great.

This article might be helpful...
http://www.experts-exchange.com/Web_Development/Web_Languages-Standards/A_11271-Understanding-Client-Server-Protocols-and-Web-Applications.html
0
 

Author Comment

by:1Cougar
ID: 39218901
Hello,

Thank you for your time and detailed answer.  Your code works (in that appointments get updated/deleted/added with it) however it does through this error:

Call to undefined function E_USER_ERROR()

Also, I was searching for how to automatically log someone out and someone else said this:

For inactivity, however, I prefer the timer/javascript version.
At login, I set a timer for 10 minutes.
Each time the user clicks something of presses a key, I call a small function "reset_timer" (for another 10 minutes).
IF and when the timer expires, I do an call to Php and cancel the login, then reload the not-logged home page, with a javascript "alert" informing that the user has been logged-off for inactivity.
This also allows me to supervise user's activities, as these log-in, log-off are timed and recorded in DB.
(Particularly useful in ADMIN or backend, to prevent an admin user to go to lunch without logging off, and a passer's by to access forbidden areas...)


I am not exactly sure how to implement this but was going to give it a try.  However, with your code even if a user comes back after long inactivity where the session has expired and the screen looks fine but when they hit 'save' data actually is not being sent, then your code will prevent any updates (basically)??

Thanks so much,
0
 
LVL 110

Expert Comment

by:Ray Paseur
ID: 39218962
Sorry... a typo.  Please change line 92 to this:

trigger_error('XML FAILURE', E_USER_ERROR);

I think your synopsis is what my code intended.  If there is not valid XML, it should not do any updates.  You may want to work out how to handle the failure to convert the XML into an object - perhaps some smart error handling (more than just trigger_error() might be needed.)
0
 

Author Comment

by:1Cougar
ID: 39218986
Thanks a lot.  At least I shouldn't have data disappearing anymore!  One question...since the another page POSTs the data to this page, the user (and me) never actually sees the errors...is there a way to handle this or write it to a error log?  I don't know the best practice for handling this.

Thanks again....
0
 
LVL 110

Expert Comment

by:Ray Paseur
ID: 39219103
trigger_error() should write to an error log if there is one defined for PHP.
0
 

Author Comment

by:1Cougar
ID: 39220005
Great I will check it out!

Thanks a lot for all of your help!
0
 
LVL 110

Expert Comment

by:Ray Paseur
ID: 39220494
Thanks for the points and good luck with your project, ~Ray
0
 

Author Comment

by:1Cougar
ID: 39228091
@Ray : one question regarding your code that I added....I see that you have a check for XML being empty but I am not sure I follow how you are checking for this as I think the delete statement ran again and wiped out the records, so I am trying to figure out why this is happening since users are starting to enter appointments.

If the POST sends <data></data> is that considered to be empty?

I know this question is technically closed, so I could open another one but thought it would be logical to respond here since all of the code is here.

Thanks again if you can help...
0
 

Author Comment

by:1Cougar
ID: 39228276
Nevermind.  I think I know why it happened.  I will repost if it continues.
0
 
LVL 110

Expert Comment

by:Ray Paseur
ID: 39228848
OK, we will be here!
0
 

Author Comment

by:1Cougar
ID: 39293507
@Ray_Paseur:

I know the question is closed, but so much was already written here that I hesitate to start another topic....

I am still having data disappear!  I don't know why--I am using your code but somehow I think an empty (or no element) XML string is getting through and then the DELETE string gets built to delete everything for that person within the time range.  Is there a way to test for an XML string (obj) that has at least an element?

I am having trouble recreating exactly what triggers this to occur---but just happened again this morning.....

Thanks again if you have any ideas--I would be happy to open this as another question so you get the points---

Cheers,
0

Featured Post

MS Dynamics Made Instantly Simpler

Make Your Microsoft Dynamics Investment Count  & Drastically Decrease Training Time by Providing Intuitive Step-By-Step WalkThru Tutorials.

Question has a verified solution.

If you are experiencing a similar issue, please ask a related question

Nothing in an HTTP request can be trusted, including HTTP headers and form data.  A form token is a tool that can be used to guard against request forgeries (CSRF).  This article shows an improved approach to form tokens, making it more difficult to…
There are times when I have encountered the need to decompress a response from a PHP request. This is how it's done, but you must have control of the request and you can set the Accept-Encoding header.
Explain concepts important to validation of email addresses with regular expressions. Applies to most languages/tools that uses regular expressions. Consider email address RFCs: Look at HTML5 form input element (with type=email) regex pattern: T…
The viewer will learn how to create a basic form using some HTML5 and PHP for later processing. Set up your basic HTML file. Open your form tag and set the method and action attributes.: (CODE) Set up your first few inputs one for the name and …

631 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question