Solved

PHP: simpleXMLElement--checking for nodes

Posted on 2013-06-04
17
285 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
  • 8
  • 8
17 Comments
 
LVL 108

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
 
LVL 16

Expert Comment

by:Chris Harte
ID: 39218623
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
 
LVL 108

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 108

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 108

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
How to run any project with ease

Manage projects of all sizes how you want. Great for personal to-do lists, project milestones, team priorities and launch plans.
- Combine task lists, docs, spreadsheets, and chat in one
- View and edit from mobile/offline
- Cut down on emails

 
LVL 108

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 108

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 108

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 108

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

How to improve team productivity

Quip adds documents, spreadsheets, and tasklists to your Slack experience
- Elevate ideas to Quip docs
- Share Quip docs in Slack
- Get notified of changes to your docs
- Available on iOS/Android/Desktop/Web
- Online/Offline

Join & Write a Comment

Suggested Solutions

Developers of all skill levels should learn to use current best practices when developing websites. However many developers, new and old, fall into the trap of using deprecated features because this is what so many tutorials and books tell them to u…
Part of the Global Positioning System A geocode (https://developers.google.com/maps/documentation/geocoding/) is the major subset of a GPS coordinate (http://en.wikipedia.org/wiki/Global_Positioning_System), the other parts being the altitude and t…
The viewer will learn how to look for a specific file type in a local or remote server directory using PHP.
The viewer will learn how to create and use a small PHP class to apply a watermark to an image. This video shows the viewer the setup for the PHP watermark as well as important coding language. Continue to Part 2 to learn the core code used in creat…

743 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

Need Help in Real-Time?

Connect with top rated Experts

14 Experts available now in Live!

Get 1:1 Help Now