Go Premium for a chance to win a PS4. Enter to Win

x
  • Status: Solved
  • Priority: Medium
  • Security: Public
  • Views: 310
  • Last Modified:

PHP: simpleXMLElement--checking for nodes

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
1Cougar
Asked:
1Cougar
  • 8
  • 8
1 Solution
 
Ray PaseurCommented:
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
 
1CougarAuthor Commented:
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
Concerto Cloud for Software Providers & ISVs

Can Concerto Cloud Services help you focus on evolving your application offerings, while delivering the best cloud experience to your customers? From DevOps to revenue models and customer support, the answer is yes!

Learn how Concerto can help you.

 
Ray PaseurCommented:
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
 
1CougarAuthor Commented:
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
 
Ray PaseurCommented:
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
 
Ray PaseurCommented:
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
 
1CougarAuthor Commented:
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
 
Ray PaseurCommented:
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
 
1CougarAuthor Commented:
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
 
Ray PaseurCommented:
trigger_error() should write to an error log if there is one defined for PHP.
0
 
1CougarAuthor Commented:
Great I will check it out!

Thanks a lot for all of your help!
0
 
Ray PaseurCommented:
Thanks for the points and good luck with your project, ~Ray
0
 
1CougarAuthor Commented:
@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
 
1CougarAuthor Commented:
Nevermind.  I think I know why it happened.  I will repost if it continues.
0
 
Ray PaseurCommented:
OK, we will be here!
0
 
1CougarAuthor Commented:
@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

Hire Technology Freelancers with Gigs

Work with freelancers specializing in everything from database administration to programming, who have proven themselves as experts in their field. Hire the best, collaborate easily, pay securely, and get projects done right.

  • 8
  • 8
Tackle projects and never again get stuck behind a technical roadblock.
Join Now