Parse XML/PHP

All,

I need help getting this code to either respect the XML tree or somehow work around it. It sees all of the “name” tags as equal when in fact I would like the information from the third “name” tag. I tried to specific “/name” for the event name and “/venue/name” for the venue name, but the code does not like. If there was a way, if it is easier, to have it read the third name entry as “name[3]” or the like and defined as $item[event_name] in an effort to save some work, that would be great as I fear fixing it to read the tree properly may require a more complicated re-write. Something of which I am incapable. Any help is appreciated. Thank you.

XML Output:

<results>
 <head>
  <method>Events</method>
  <description>Access Meetup events using a group, member, or event id. Events in private groups are available only to authenticated members of those groups. To search events by topic or location, see [Open Events](/meetup_api/docs/2/open_events).</description>
  <count>5</count>
  <updated>Wed Sep 25 22:02:01 EDT 2013</updated>
  <lat/>
  <next/>
  <id/>
  <link>http://api.meetup.com/2/events</link>
  <title>Meetup Events v2</title>
  <total_count>5</total_count>
  <lon/>
 </head>
 <items>
  <item>
   <venue>
    <address_1>5204 Detroit Rd</address_1>
    <state>OH</state>
    <zip>44035</zip>
    <lat>41.424769</lat>
    <repinned>False</repinned>
    <phone>440-934-1713</phone>
    <name>Ctrl Alt Elite Gaming</name>
    <city>Sheffield Village</city>
    <id>1540018</id>
    <country>us</country>
    <lon>-82.081545</lon>
   </venue>
   <status>upcoming</status>
   <description>Cost: $5 USD</description>
   <maybe_rsvp_count>0</maybe_rsvp_count>
   <waitlist_count>0</waitlist_count>
   <updated>1379558505000</updated>
   <group>
    <who>North Coast Gamers</who>
    <join_mode>open</join_mode>
    <urlname>North-Coast-Gamers-Cleveland</urlname>
    <name>Games!  North Coast Gamers - Greater Cleveland Chapter</name>
    <id>319720</id>
    <group_lat>41.5</group_lat>
    <group_lon>-81.6699981689</group_lon>
   </group>
   <yes_rsvp_count>1</yes_rsvp_count>
   <created>1378692585000</created>
   <visibility>public</visibility>
   <name>Yu-Gi-Oh Traditional Format TCG Tournament</name>
   <id>dlhktgyrmblc</id>
   <headcount>0</headcount>
   <duration>14400000</duration>
   <utc_offset>-14400000</utc_offset>
   <time>1380398400000</time>
   <event_url>http://www.meetup.com/North-Coast-Gamers-Cleveland/events/139162192/</event_url>
  </item>
 </items>
</results>

PHP Source Code:
[php]

<?php class lastRSS { // ------------------------------------------------------------------- // Public properties // ------------------------------------------------------------------- var $default_cp = 'UTF-8'; var $CDATA = 'nochange'; var $cp = ''; var $items_limit = 0; var $stripHTML = False; var $date_format = ''; // ------------------------------------------------------------------- // Private variables // ------------------------------------------------------------------- var $resultstags = array ('title', 'description', 'link', 'pubDate', 'updated'); var $itemtags = array('title', 'link', 'description', 'name', 'time', 'event_url', 'venue', 'utc_offset', 'duration', 'updated'); var $imagetags = array('title', 'url', 'link', 'width', 'height'); var $textinputtags = array('title', 'description', 'link', 'name'); // ------------------------------------------------------------------- // Parse RSS file and returns associative array. // ------------------------------------------------------------------- function Get ($rss_url) { // If CACHE ENABLED if ($this->cache_dir != '') { $cache_file = $this->cache_dir . '/rsscache_' . md5($rss_url); $timedif = @(time() - filemtime($cache_file)); if ($timedif < $this->cache_time) { // cached file is fresh enough, return cached array $result = unserialize(join('', file($cache_file))); // set 'cached' to 1 only if cached file is correct if ($result) $result['cached'] = 1; } else { // cached file is too old, create new $result = $this->Parse($rss_url); $serialized = serialize($result); if ($f = @fopen($cache_file, 'w')) { fwrite ($f, $serialized, strlen($serialized)); fclose($f); } if ($result) $result['cached'] = 0; } } // If CACHE DISABLED >> load and parse the file directly else { $result = $this->Parse($rss_url); if ($result) $result['cached'] = 0; } // return result return $result; } // ------------------------------------------------------------------- // Modification of preg_match(); return trimed field with index 1 // from 'classic' preg_match() array output // ------------------------------------------------------------------- function my_preg_match ($pattern, $subject) { // start regullar expression preg_match($pattern, $subject, $out); // if there is some result... process it and return it if(isset($out[1])) { // Process CDATA (if present) if ($this->CDATA == 'content') { // Get CDATA content (without CDATA tag) $out[1] = strtr($out[1], array(''', ']]>'=>'')); } elseif ($this->CDATA == 'strip') { // Strip CDATA $out[1] = strtr($out[1], array(''', ']]>'=>'')); } // If code page is set convert character encoding to required if ($this->cp != '') //$out[1] = $this->MyConvertEncoding($this->rsscp, $this->cp, $out[1]); $out[1] = iconv($this->rsscp, $this->cp.'//TRANSLIT', $out[1]); // Return result return trim($out[1]); } else { // if there is NO result, return empty string return ''; } } // ------------------------------------------------------------------- // Replace HTML entities &something; by real characters // ------------------------------------------------------------------- function unhtmlentities ($string) { // Get HTML entities table $trans_tbl = get_html_translation_table (HTML_ENTITIES, ENT_QUOTES); // Flip keys<==>values $trans_tbl = array_flip ($trans_tbl); // Add support for ' entity (missing in HTML_ENTITIES) $trans_tbl += array(''' => "'"); // Replace entities by values return strtr ($string, $trans_tbl); } // ------------------------------------------------------------------- // Parse() is private method used by Get() to load and parse RSS file. // Don't use Parse() in your scripts - use Get($rss_file) instead. // ------------------------------------------------------------------- function Parse ($rss_url) { // Open and load RSS file if ($f = @fopen($rss_url, 'r')) { $rss_content = ''; while (!feof($f)) { $rss_content .= fgets($f, 4096); } fclose($f); // Parse document encoding $result['encoding'] = $this->my_preg_match("'encoding=[\'\"](.*?)[\'\"]'si", $rss_content); // if document codepage is specified, use it if ($result['encoding'] != '') { $this->rsscp = $result['encoding']; } // This is used in my_preg_match() // otherwise use the default codepage else { $this->rsscp = $this->default_cp; } // This is used in my_preg_match() // Parse RESULTS info - Previously CHANNEL preg_match("'(.*?)'si", $rss_content, $out_results);
        foreach($this->resultstags as $resultstag) 
        { 
            $temp = $this->my_preg_match("'<$resultstag.*?>(.*?)</$resultstag>'si", $out_results[1]); 
            if ($temp != '') $result[$resultstag] = $temp; // Set only if not empty 
        } 
        // If date_format is specified and lastBuildDate is valid 
        if ($this->date_format != '' && ($timestamp = strtotime($result['lastBuildDate'])) !==-1) { 
                    // convert lastBuildDate to specified date format 
                    $result['lastBuildDate'] = date($this->date_format, $timestamp); 
        } 

        // Parse TEXTINPUT info 
        preg_match("'<textinput(|[^>]*[^/])>(.*?)</textinput>'si", $rss_content, $out_textinfo); 
            // This a little strange regexp means: 
            // Look for tag <textinput> with or without any attributes, but skip truncated version <textinput /> (it's not beggining tag) 
        if (isset($out_textinfo[2])) { 
            foreach($this->textinputtags as $textinputtag) { 
                $temp = $this->my_preg_match("'<$textinputtag.*?>(.*?)</$textinputtag>'si", $out_textinfo[2]); 
                if ($temp != '') $result['textinput_'.$textinputtag] = $temp; // Set only if not empty 
            } 
        } 
        // Parse IMAGE info 
        preg_match("'<image.*?>(.*?)</image>'si", $rss_content, $out_imageinfo); 
        if (isset($out_imageinfo[1])) { 
            foreach($this->imagetags as $imagetag) { 
                $temp = $this->my_preg_match("'<$imagetag.*?>(.*?)</$imagetag>'si", $out_imageinfo[1]); 
                if ($temp != '') $result['image_'.$imagetag] = $temp; // Set only if not empty 
            } 
        } 
        // Parse ITEMS 
        preg_match_all("'<item(| .*?)>(.*?)</item>'si", $rss_content, $items); 
        $rss_items = $items[2]; 
        $i = 0; 
        $result['items'] = array(); // create array even if there are no items 
        foreach($rss_items as $rss_item) { 
            // If number of items is lower then limit: Parse one item 
            if ($i < $this->items_limit || $this->items_limit == 0) { 
                foreach($this->itemtags as $itemtag) { 
                    $temp = $this->my_preg_match("'<$itemtag.*?>(.*?)</$itemtag>'si", $rss_item); 
                    if ($temp != '') $result['items'][$i][$itemtag] = $temp; // Set only if not empty 
                } 
                // Strip HTML tags and other stuff from DESCRIPTION 
                if ($this->stripHTML && $result['items'][$i]['description']) 
                    $result['items'][$i]['description'] = strip_tags($this->unhtmlentities(strip_tags($result['items'][$i]['description']))); 

                // Strip HTML tags and other stuff from TITLE 
                if ($this->stripHTML && $result['items'][$i]['title']) 
                    $result['items'][$i]['title'] = strip_tags($this->unhtmlentities(strip_tags($result['items'][$i]['title']))); 

                // If date_format is specified and pubDate is valid 
                if ($this->date_format != '' && ($timestamp = strtotime($result['items'][$i]['pubDate'])) !==-1) { 
                    // convert pubDate to specified date format 
                    $result['items'][$i]['pubDate'] = date($this->date_format, $timestamp); 
                } 
                // Item counter 
                $i++; 
            } 
        } 

        $result['items_count'] = $i; 
        return $result; 
    } 
    else // Error in opening return False 
    { 
        return False; 
    } 
} 

}

?>
[/php]

PHP Output (Snippet):

//           echo "\tVenue: $item[name]<br>\n"; // This should be the event name, not its venue.
//           echo "\tEvent: $item[name]<br>\n"; // Need to create a parse for the third name entry in each item.

First off all you should prefix your class methods with public/private, and if following the Zend guidelines the private methods should also begin with an underscore. It just makes it easier for everyone as there is no confusion about methods like “Parse”.

A lot of great ideas/resources when it comes to guidelines and coding standards
http://framework.zend.com/manual/1.12/en/coding-standard.naming-conventions.html#coding-standard.naming-conventions.functions-and-methods

On topic:
$item[‘name’] in these two lines will have the same value. It seems like you are expecting them to give you different values, but they can’t.

[php]echo “\tVenue: $item[name]
\n”; // This should be the event name, not its venue.
echo “\tEvent: $item[name]
\n”; // Need to create a parse for the third name entry in each item.[/php]

Please run this and post back the output :slight_smile:
[php]echo ‘

’; var_dump($item);[/php]

Might also look at using json, its pretty nifty at working with xml.

^- this. JSON is much better to work with.

Hey guys,

Thanks for responding. I am working with code that I did not make as I am a PHP Newbie. Converting it to read JSON is not possible for me. I decided to post more of it in another topic (http://www.phphelp.com/forum/general-php-help/xml-to-php-tree-hierarchy-issue/msg74677/#msg74677).

In response to JimL’s initial comment, I am aware that naming the output the same twice does not work like that. I was leaving it set the only way the output worked and I did mention that in my comment. As far as the output that you have requested:

array(8) {
  ["description"]=>
  string(407) "Cost: $5"
  ["name"]=>
  string(21) "Ctrl Alt Elite Gaming"
  ["time"]=>
  string(13) "1380990600000"
  ["event_url"]=>
  string(68) "http://www.meetup.com/North-Coast-Gamers-Cleveland/events/141025002/"
  ["venue"]=>
  string(266) "5204 Detroit RdOH4403541.424769False440-934-1713Ctrl Alt Elite GamingSheffield Village1540018us-82.081545"
  ["utc_offset"]=>
  string(9) "-14400000"
  ["duration"]=>
  string(8) "12600000"
  ["updated"]=>
  string(13) "1380159785000"
}

Thanks in advance for any help that you can provide.

I can look at this tomorrow, but I need some more info.

Try this code
[php]<?php

echo ‘

’;

$xml = file_get_contents(‘data.xml’);
$results = new SimpleXMLElement($xml);

var_dump($results);[/php]

Output:

class SimpleXMLElement#1 (2) { public $head => class SimpleXMLElement#2 (11) { public $method => string(6) "Events" public $description => string(232) "Access Meetup events using a group, member, or event id. Events in private groups are available only to authenticated members of those groups. To search events by topic or location, see [Open Events](/meetup_api/docs/2/open_events)." public $count => string(1) "5" public $updated => string(28) "Wed Sep 25 22:02:01 EDT 2013" public $lat => class SimpleXMLElement#4 (0) { } public $next => class SimpleXMLElement#5 (0) { } public $id => class SimpleXMLElement#6 (0) { } public $link => string(30) "http://api.meetup.com/2/events" public $title => string(16) "Meetup Events v2" public $total_count => string(1) "5" public $lon => class SimpleXMLElement#7 (0) { } } public $items => class SimpleXMLElement#3 (1) { public $item => class SimpleXMLElement#7 (17) { public $venue => class SimpleXMLElement#6 (11) { ... } public $status => string(8) "upcoming" public $description => string(12) "Cost: $5 USD" public $maybe_rsvp_count => string(1) "0" public $waitlist_count => string(1) "0" public $updated => string(13) "1379558505000" public $group => class SimpleXMLElement#5 (7) { ... } public $yes_rsvp_count => string(1) "1" public $created => string(13) "1378692585000" public $visibility => string(6) "public" public $name => string(42) "Yu-Gi-Oh Traditional Format TCG Tournament" public $id => string(12) "dlhktgyrmblc" public $headcount => string(1) "0" public $duration => string(8) "14400000" public $utc_offset => string(9) "-14400000" public $time => string(13) "1380398400000" public $event_url => string(68) "http://www.meetup.com/North-Coast-Gamers-Cleveland/events/139162192/" } } }

Ok, so we got a lot of data.

Now what we are interested in is inside results->items->item, so let’s go there

[php]<?php

echo ‘

’;

$xml = file_get_contents(‘data.xml’);
$results = new SimpleXMLElement($xml);

foreach ($results->items->item as $item) {
print_r($item);
}[/php]

Output:

[code]SimpleXMLElement Object
(
[venue] => SimpleXMLElement Object
(
[address_1] => 5204 Detroit Rd
[state] => OH
[zip] => 44035
[lat] => 41.424769
[repinned] => False
[phone] => 440-934-1713
[name] => Ctrl Alt Elite Gaming
[city] => Sheffield Village
[id] => 1540018
[country] => us
[lon] => -82.081545
)

[status] => upcoming
[description] => Cost: $5 USD
[maybe_rsvp_count] => 0
[waitlist_count] => 0
[updated] => 1379558505000
[group] => SimpleXMLElement Object
    (
        [who] => North Coast Gamers
        [join_mode] => open
        [urlname] => North-Coast-Gamers-Cleveland
        [name] => Games!  North Coast Gamers - Greater Cleveland Chapter
        [id] => 319720
        [group_lat] => 41.5
        [group_lon] => -81.6699981689
    )

[yes_rsvp_count] => 1
[created] => 1378692585000
[visibility] => public
[name] => Yu-Gi-Oh Traditional Format TCG Tournament
[id] => dlhktgyrmblc
[headcount] => 0
[duration] => 14400000
[utc_offset] => -14400000
[time] => 1380398400000
[event_url] => http://www.meetup.com/North-Coast-Gamers-Cleveland/events/139162192/

)[/code]

Ok, now we’re talking. So let’s fetch the spesific data we actually want.

[php]<?php

echo ‘

’;

$xml = file_get_contents(‘data.xml’);
$results = new SimpleXMLElement($xml);

foreach ($results->items->item as $item) { ?>
Status: <?= $item->status ?>

Description: <?= $item->description ?>

Name: <?= $item->name ?>

URL: <?= $item->event_url ?>

Venue

Name: <?= $item->venue->name ?> (<?= $item->venue->id ?>)
Address: <?= $item->venue->address_1 ?>, <?= $item->venue->zip ?> <?= $item->venue->city ?>, <?= $item->venue->country ?>

Group

Who: <?= $item->group->who ?> (<?= $item->group->id ?>)
Name: <?= $item->group->name ?>
Join mode: <?= $item->group->join_mode ?> <?php } ?>[/php]

Output:

[code]Status: upcoming
Description: Cost: $5 USD
Name: Yu-Gi-Oh Traditional Format TCG Tournament
URL: http://www.meetup.com/North-Coast-Gamers-Cleveland/events/139162192/

Venue
Name: Ctrl Alt Elite Gaming (1540018)
Address: 5204 Detroit Rd, 44035 Sheffield Village, us

Group
Who: North Coast Gamers (319720)
Name: Games! North Coast Gamers - Greater Cleveland Chapter
Join mode: open[/code]

Is there anything apart from this you are doing? Because using the normal SimpleXMLElement-method seems way simpler…

JimL… Wow, you are good. All that is left is to work out the date and time codes. If I figure it out before you come back, I will post it there. Thanks a ton!

By the way… They reason why I use LastRSS is because for some feeds, I needed a work around that stores the XML locally since my server has remote inclusions disabled. I am happy that I can work around it for Meetup.Com.

[php]date_default_timezone_set(‘UTC’);

$xml = file_get_contents(‘data.xml’);
$results = new SimpleXMLElement($xml);

foreach ($results->items->item as $item) {
$duration = array();
list($duration[‘hours’], $duration[‘minutes’]) = explode(’:’, date(“H:i”, (float) $item->duration));
?>
Name: <?= $item->name ?>

Status: <?= $item->status ?>

Description: <?= $item->description ?>

Time: <?= date("F j, Y, g:i a", (float) $item->time / 1000) ?>

Duration: <?= $duration['hours'] ?> hours and <?= $duration['minutes'] ?> minutes

URL: <?= $item->event_url ?>

Venue

Name: <?= $item->venue->name ?> (<?= $item->venue->id ?>)
Address: <?= $item->venue->address_1 ?>, <?= $item->venue->zip ?> <?= $item->venue->city ?>, <?= $item->venue->country ?>

Group

Who: <?= $item->group->who ?> (<?= $item->group->id ?>)
Name: <?= $item->group->name ?>
Join mode: <?= $item->group->join_mode ?> <?php } ?>[/php]

Output

Name: Yu-Gi-Oh Traditional Format TCG Tournament Status: upcoming Description: Cost: $5 USD Time: September 28, 2013, 8:00 pm Duration: 16 hours and 00 minutes URL: http://www.meetup.com/North-Coast-Gamers-Cleveland/events/139162192/ Venue Name: Ctrl Alt Elite Gaming (1540018) Address: 5204 Detroit Rd, 44035 Sheffield Village, us Group Who: North Coast Gamers (319720) Name: Games! North Coast Gamers - Greater Cleveland Chapter Join mode: open

Wow… Just a few things… All of the time elements must be divided by 1,000. As listed, the time is 4 hours too late due to the lack of utc_offset and the duration was only four hours, which I am not sure why it is wrong. I assume it is because it is not divided by 1,000.

http://www.haslage.net/meetup/

This is where I was running my tests. The output shows the time format that I need.

http://www.haslage.net/meetup/test.php

This is where I have your code up at.

Thanks.

Okay, so I figured out the problem with using the date function… It was referring to my server time to set the time. It is in central while I am in eastern. Setting the default to UTC offsets it worse than I can fix it with what Meetup.Com provides. Thus, I set the date_default_timezone_set function to “America/New_York”. My worry is if I do it like this and I have an event outside of the timezone, I am not sure if it will display correctly. The timezone is based on the venue location. If I can resolve the below issue, I can remedy my concern with this one.

The problem is that I cannot figure out how to adapt the end time by adding the duration to the raw time without a problem, then converting it accordingly. When I go to divide $item->time by 1,000… It spits out an entirely wrong number. In the old code, it worked perfectly fine.

$item->time / 1,000 = 1380990600 (It should equal this.)
$item->time / 1,000 = 2147483.647 (But I get this.)

The timezone and duration seem to divide properly, but any combination where there is division with time causes the mathematical error.

What I was experimenting with as outputted on test.php:
[php]

<?php date_default_timezone_set('America/New_York'); $xml = file_get_contents('data.xml'); $results = new SimpleXMLElement($xml); foreach ($results->items->item as $item) { $mil = $item->time; $mila = $item->time / 1000; // Convert time from milliseconds to seconds $tz = $item->utc_offset; $tza = $item->utc_offset / 1000; // Convert timezone from milliseconds to seconds $length = $item->duration; $lengtha = $item->duration / 1000; // Convert duration from milliseconds to seconds $evend = $mil + $length; // Adds time and duration $evenda = $mila + $lengtha; // Adds time and duration ?>
<h4>Formulas</h4>

Time (MDYT): <?= date("M. j, Y @ g:i A", (float) $item->time / 1000) ?>

Time: <?= $mil ?>

Time (ADJ): <?= $mila ?> (This is wrong.)

Timzeone: <?= $tz ?>

Timzeone (ADJ): <?= $tza ?>

Duration: <?= $length ?>

Duration (ADJ): <?= $lengtha ?>

Length: <?= $evend ?> (Also wrong.)

Length (ADJ): <?= date("M. j, Y @ g:i A", (float) $evenda) ?>

  • <?= $item->name ?> - <?= date("M. j, Y @ g:i A", (float) $item->time / 1000) ?> to <?= $evend ?> (<?= $item->venue->name ?>) <?php } ?>

    [/php]

    Again, any help is appreciated. I just cannot seem to win one way or another. Thanks.

  • [php]<?php
    date_default_timezone_set(‘America/New_York’);

    $xml = file_get_contents(‘data.xml’);
    $results = new SimpleXMLElement($xml);

    foreach ($results->items->item as $item) {
    $time = (float) $item->time / 1000;
    $duration = (float) $item->duration / 1000 / 60 / 60;
    $evend = ((float) $item->time + (float) $item->duration) / 1000;
    ?>

    Formulas

    Time (MDYT): <?= date("M. j, Y @ g:i A", $time) ?>
    Duration: <?= $duration ?> hours
  • <?= $item->name ?> - <?= date("M. j, Y @ g:i A", $time) ?> to <?= date("M. j, Y @ g:i A", $evend) ?> (<?= $item->venue->name ?>) <?php } ?>[/php]

    Output:

    [php]

    Formulas


    Time (MDYT): Sep. 28, 2013 @ 4:00 PM

    Duration: 4 hours
  • Yu-Gi-Oh Traditional Format TCG Tournament - Sep. 28, 2013 @ 4:00 PM to Sep. 28, 2013 @ 8:00 PM (Ctrl Alt Elite Gaming)[/php]
  • You are awesome, JimL. You have solved an issue I have struggled with for a month. Thanks you so much!

    Wow, I spoke too soon. Loading the file itself works fine, but the moment I place the contents into a file with other inclusions, it gives me:

    Warning: file_get_contents() [function.file-get-contents]: URL file-access is disabled in the server configuration in /meetup/past.php on line 10
    
    Warning: file_get_contents(http://api.meetup.com/2/events?...) [function.file-get-contents]: failed to open stream: no suitable wrapper could be found in /meetup/past.php on line 10
    
    Fatal error: Uncaught exception 'Exception' with message 'String could not be parsed as XML' in /meetup/past.php:11 Stack trace: #0 /meetup/past.php(11): SimpleXMLElement->__construct('') #1 /past.php(4): include('/home/...') #2 {main} thrown in /meetup/past.php on line 11

    Lines 10 & 11:

      $xml = file_get_contents('http://api.meetup.com/2/events?...');
      $results = new SimpleXMLElement($xml);

    This is why I used the previously mentioned LastRSS program. It saves the file locally and then parses the data.

    Okay, so JimL did a great job coming up with code that did exactly what I needed to display. The problem is that it does not work around my server’s security settings. It seems that I still need to cache the raw data and then parse it. So, what we need to do is strip the old code, which frankly was inefficient in reading a XML tree, and implant Jiml’s code.

    I do apologize in advance of my ignorance of PHP. I do try for a number of hours to try to get things working on my own. Sometimes I succeed and other times I do not. As always, any help is appreciated. Thanks in advance.

    JimL’s code:
    [php]

    <?php date_default_timezone_set('America/New_York'); $xml = file_get_contents('data.xml'); $results = new SimpleXMLElement($xml); foreach ($results->items->item as $item) { $time = (float) $item->time / 1000; $duration = (float) $item->duration / 1000 / 60 / 60; $end = ((float) $item->time + (float) $item->duration) / 1000; ?>
    <h4>Formulas</h4>
    Time Begin: <?= date("M. j, Y @ g:i A", $time) ?><br />
    Duration: <?= $duration ?> hours<br />
    Time End: <?= date("g:i A", $end) ?><br />
    
    <h4>Event</h4>
    Name: <?= $item->name ?><br />
    Description: <?= $item->description ?><br />
    URL: <?= $item->event_url ?><br />
    Time:  <?= date("M. j, Y @ g:i A", (float) $item->time / 1000) ?><br />
    Timezone: <?= $item->utc_offset / 1000 ?><br />
    Duration: <?= $item->duration / 1000 ?><br />
    Duration: <?= $duration['hours'] ?> hours and <?= $duration['minutes'] ?> minutes<br />
    Status: <?= $item->status ?><br />
    
    <h4>Venue</h4>
    Name: <?= $item->venue->name ?> (<?= $item->venue->id ?>)<br />
    Address: <?= $item->venue->address_1 ?>, <?= $item->venue->zip ?> <?= $item->venue->city ?>, <?= $item->venue->country ?><br />
    
    <h4>Group</h4>
    Who: <?= $item->group->who ?> (<?= $item->group->id ?>)<br />
    Name: <?= $item->group->name ?><br />
    Join mode: <?= $item->group->join_mode ?><br>
    
    <li><a href="<?= $item->event_url ?>" target="newwindow" title="<?= $item->description ?>"><?= $item->name ?> - <?= date("M. j, Y @ g:i A", $time) ?> to <?= date("g:i A", $end) ?> (<?= $item->venue->name ?>)</a>
    
    <?php } ?>

    [/php]

    Original front end code (upcoming.php):
    [php]
    function ShowOneRSS($url)
    {
    global $rss;
    if ($rs = $rss->get($url))
    {
    // Original code
    echo “<a href=”$rs[link]" target=“newwindow” title="$rs[description]">$rs[title]
    \n";
    // New code - For testing purposes.
    // echo “Title: $rs[title]
    \n”;
    // echo “Description: $rs[description]
    \n”;
    // echo “Link: $rs[link]
    \n”;
    // echo “Updated: $rs[updated]
    \n”;
    // echo “

      \n”;
      foreach ($rs[‘items’] as $item)
      {

      // Original code
      echo “\t

    • <a href=”$item[link]" target=“newwindow” title="$item[description]">$item[title]
    • \n";
      // New code - For testing purposes.
      // echo “\tVenue: $item[name]
      \n”; // This should be the event name, not its venue.
      // echo “\tEvent: $item[event_name]
      \n”; // Need to create a parse for the third name entry in each item.
      // echo “\tDescription: $item[description]
      \n”;
      // echo “\tURL: $item[event_url]
      \n”;
      // echo “\tTime: $item[time]
      \n”;
      // echo “\tTimezone: $item[utc_offset]
      \n”;
      // echo “\tDuration: $item[duration]
      \n”;

      // New code - Desired output.
      echo “\t

    • <a href=”$item[event_url]" target=“newwindow” title="$item[description]">$item[event_name] - “;
      $mil = $item[time] / 1000; // Convert time from milliseconds to seconds
      $tz = $item[utc_offset] / 1000; // Convert timezone from milliseconds to seconds
      $duration = $item[duration] / 1000; // Convert duration from milliseconds to seconds
      $time = $mil + $tz; // Convert to U.S. Eastern Timezone
      $dt = new DateTime(”@$time"); // Convert UNIX timestamp to PHP DateTime
      echo $dt->format(‘M. j, Y @ g:i A’); // Event date and time start
      echo " to “;
      $event_length = $time + $duration; // Adds time and duration
      $event_end = new DateTime(”@$event_length"); // Convert UNIX timestamp to PHP DateTime
      echo $event_end->format(‘g:i A’); // Event time end
      echo “$item[event_datetime] ($item[name])
    • \n”; // Final Output Desired
      // echo “
    ”; var_dump($item); // For testing purposes.
    

    }
    if ($rs[‘items_count’] <= 0) { echo “

  • Sorry, no items found in the RSS file.
  • ”;
    }
    echo “\n”;
    }
    else
    {
    echo “Sorry, it is not possible to reach RSS file: $url\n
    ”;
    }
    }

    // ===============================================================================

    // include lastRSS
    include “meetup-src.php”;

    // List of RSS URLs
    $rss_left = array(
    ‘data.xml’
    );

    // Create lastRSS object
    $rss = new lastRSS;

    // Set cache dir and cache time limit
    // (don’t forget to chmod cache dir to 777 to allow writing)
    $rss->cache_dir = ‘/cache’;
    $rss->cache_time = 10; // Return to 3600 when done testing.

    // Show all rss files
    echo “<table cellpadding=“0” cellspacing=“0” border=“0”>

    <td width=“100%” valign=“top”>\n”;
    foreach ($rss_left as $url) {
    ShowOneRSS($url);
    }
    echo “”;
    ?>
    [/php]

    Original source code (meetup-src.php):
    [php]
    class lastRSS {
    // -------------------------------------------------------------------
    // Public properties
    // -------------------------------------------------------------------
    var $default_cp = ‘UTF-8’;
    var $CDATA = ‘nochange’;
    var $cp = ‘’;
    var $items_limit = 0;
    var $stripHTML = False;
    var $date_format = ‘’;

    // ------------------------------------------------------------------- 
    // Private variables 
    // ------------------------------------------------------------------- 
    var $resultstags = array ('title', 'description', 'link', 'pubDate', 'updated'); 
    var $itemtags = array('title', 'link', 'description', 'name', 'time', 'event_url', 'venue', 'utc_offset', 'duration', 'updated'); 
    var $imagetags = array('title', 'url', 'link', 'width', 'height'); 
    var $textinputtags = array('title', 'description', 'link', 'name'); 
    
    // ------------------------------------------------------------------- 
    // Parse RSS file and returns associative array. 
    // ------------------------------------------------------------------- 
    function Get ($rss_url) { 
        // If CACHE ENABLED 
        if ($this->cache_dir != '') { 
            $cache_file = $this->cache_dir . '/rsscache_' . md5($rss_url); 
            $timedif = @(time() - filemtime($cache_file)); 
            if ($timedif < $this->cache_time) { 
                // cached file is fresh enough, return cached array 
                $result = unserialize(join('', file($cache_file))); 
                // set 'cached' to 1 only if cached file is correct 
                if ($result) $result['cached'] = 1; 
            } else { 
                // cached file is too old, create new 
                $result = $this->Parse($rss_url); 
                $serialized = serialize($result); 
                if ($f = @fopen($cache_file, 'w')) { 
                    fwrite ($f, $serialized, strlen($serialized)); 
                    fclose($f); 
                } 
                if ($result) $result['cached'] = 0; 
            } 
        } 
        // If CACHE DISABLED >> load and parse the file directly 
        else { 
            $result = $this->Parse($rss_url); 
            if ($result) $result['cached'] = 0; 
        } 
        // return result 
        return $result; 
    } 
     
    // ------------------------------------------------------------------- 
    // Modification of preg_match(); return trimed field with index 1 
    // from 'classic' preg_match() array output 
    // ------------------------------------------------------------------- 
    function my_preg_match ($pattern, $subject) { 
        // start regullar expression 
        preg_match($pattern, $subject, $out); 
    
        // if there is some result... process it and return it 
        if(isset($out[1])) { 
            // Process CDATA (if present) 
            if ($this->CDATA == 'content') { // Get CDATA content (without CDATA tag) 
                $out[1] = strtr($out[1], array('<![CDATA['=>'', ']]>'=>'')); 
            } elseif ($this->CDATA == 'strip') { // Strip CDATA 
                $out[1] = strtr($out[1], array('<![CDATA['=>'', ']]>'=>'')); 
            } 
    
            // If code page is set convert character encoding to required 
            if ($this->cp != '') 
                //$out[1] = $this->MyConvertEncoding($this->rsscp, $this->cp, $out[1]); 
                $out[1] = iconv($this->rsscp, $this->cp.'//TRANSLIT', $out[1]); 
            // Return result 
            return trim($out[1]); 
        } else { 
        // if there is NO result, return empty string 
            return ''; 
        } 
    } 
    
    // ------------------------------------------------------------------- 
    // Replace HTML entities &something; by real characters 
    // ------------------------------------------------------------------- 
    function unhtmlentities ($string) { 
        // Get HTML entities table 
        $trans_tbl = get_html_translation_table (HTML_ENTITIES, ENT_QUOTES); 
        // Flip keys<==>values 
        $trans_tbl = array_flip ($trans_tbl); 
        // Add support for &apos; entity (missing in HTML_ENTITIES) 
        $trans_tbl += array('&apos;' => "'"); 
        // Replace entities by values 
        return strtr ($string, $trans_tbl); 
    } 
    
    // ------------------------------------------------------------------- 
    // Parse() is private method used by Get() to load and parse RSS file. 
    // Don't use Parse() in your scripts - use Get($rss_file) instead. 
    // ------------------------------------------------------------------- 
    function Parse ($rss_url) { 
        // Open and load RSS file 
        if ($f = @fopen($rss_url, 'r')) { 
            $rss_content = ''; 
            while (!feof($f)) { 
                $rss_content .= fgets($f, 4096); 
            } 
            fclose($f); 
    
            // Parse document encoding 
            $result['encoding'] = $this->my_preg_match("'encoding=[\'\"](.*?)[\'\"]'si", $rss_content); 
            // if document codepage is specified, use it 
            if ($result['encoding'] != '') 
                { $this->rsscp = $result['encoding']; } // This is used in my_preg_match() 
            // otherwise use the default codepage 
            else 
                { $this->rsscp = $this->default_cp; } // This is used in my_preg_match() 
    
            // Parse RESULTS info - Previously CHANNEL
            preg_match("'<results.*?>(.*?)</results>'si", $rss_content, $out_results); 
            foreach($this->resultstags as $resultstag) 
            { 
                $temp = $this->my_preg_match("'<$resultstag.*?>(.*?)</$resultstag>'si", $out_results[1]); 
                if ($temp != '') $result[$resultstag] = $temp; // Set only if not empty 
            } 
            // If date_format is specified and lastBuildDate is valid 
            if ($this->date_format != '' && ($timestamp = strtotime($result['lastBuildDate'])) !==-1) { 
                        // convert lastBuildDate to specified date format 
                        $result['lastBuildDate'] = date($this->date_format, $timestamp); 
            } 
    
            // Parse TEXTINPUT info 
            preg_match("'<textinput(|[^>]*[^/])>(.*?)</textinput>'si", $rss_content, $out_textinfo); 
                // This a little strange regexp means: 
                // Look for tag <textinput> with or without any attributes, but skip truncated version <textinput /> (it's not beggining tag) 
            if (isset($out_textinfo[2])) { 
                foreach($this->textinputtags as $textinputtag) { 
                    $temp = $this->my_preg_match("'<$textinputtag.*?>(.*?)</$textinputtag>'si", $out_textinfo[2]); 
                    if ($temp != '') $result['textinput_'.$textinputtag] = $temp; // Set only if not empty 
                } 
            } 
            // Parse IMAGE info 
            preg_match("'<image.*?>(.*?)</image>'si", $rss_content, $out_imageinfo); 
            if (isset($out_imageinfo[1])) { 
                foreach($this->imagetags as $imagetag) { 
                    $temp = $this->my_preg_match("'<$imagetag.*?>(.*?)</$imagetag>'si", $out_imageinfo[1]); 
                    if ($temp != '') $result['image_'.$imagetag] = $temp; // Set only if not empty 
                } 
            } 
            // Parse ITEMS 
            preg_match_all("'<item(| .*?)>(.*?)</item>'si", $rss_content, $items); 
            $rss_items = $items[2]; 
            $i = 0; 
            $result['items'] = array(); // create array even if there are no items 
            foreach($rss_items as $rss_item) { 
                // If number of items is lower then limit: Parse one item 
                if ($i < $this->items_limit || $this->items_limit == 0) { 
                    foreach($this->itemtags as $itemtag) { 
                        $temp = $this->my_preg_match("'<$itemtag.*?>(.*?)</$itemtag>'si", $rss_item); 
                        if ($temp != '') $result['items'][$i][$itemtag] = $temp; // Set only if not empty 
                    } 
                    // Strip HTML tags and other stuff from DESCRIPTION 
                    if ($this->stripHTML && $result['items'][$i]['description']) 
                        $result['items'][$i]['description'] = strip_tags($this->unhtmlentities(strip_tags($result['items'][$i]['description']))); 
    
                    // Strip HTML tags and other stuff from TITLE 
                    if ($this->stripHTML && $result['items'][$i]['title']) 
                        $result['items'][$i]['title'] = strip_tags($this->unhtmlentities(strip_tags($result['items'][$i]['title']))); 
    
                    // If date_format is specified and pubDate is valid 
                    if ($this->date_format != '' && ($timestamp = strtotime($result['items'][$i]['pubDate'])) !==-1) { 
                        // convert pubDate to specified date format 
                        $result['items'][$i]['pubDate'] = date($this->date_format, $timestamp); 
                    } 
                    // Item counter 
                    $i++; 
                } 
            } 
    
            $result['items_count'] = $i; 
            return $result; 
        } 
        else // Error in opening return False 
        { 
            return False; 
        } 
    } 
    

    }

    ?>
    [/php]

    The data (data.xml):

    <results>
       <head>
        <method>Events</method>
        <description>Access Meetup events using a group, member, or event id. Events in private groups are available only to authenticated members of those groups. To search events by topic or location, see [Open Events](/meetup_api/docs/2/open_events).</description>
        <count>5</count>
        <updated>Wed Sep 25 22:02:01 EDT 2013</updated>
        <lat/>
        <next/>
        <id/>
       <link>http://api.meetup.com/2/events</link>
       <title>Meetup Events v2</title>
       <total_count>5</total_count>
       <lon/>
      </head>
      <items>
       <item>
        <venue>
         <address_1>5204 Detroit Rd</address_1>
         <state>OH</state>
         <zip>44035</zip>
         <lat>41.424769</lat>
         <repinned>False</repinned>
         <phone>440-934-1713</phone>
         <name>Ctrl Alt Elite Gaming</name>
         <city>Sheffield Village</city>
         <id>1540018</id>
         <country>us</country>
         <lon>-82.081545</lon>
        </venue>
        <status>upcoming</status>
        <description>Cost: $5 USD</description>
        <maybe_rsvp_count>0</maybe_rsvp_count>
        <waitlist_count>0</waitlist_count>
        <updated>1379558505000</updated>
        <group>
         <who>North Coast Gamers</who>
         <join_mode>open</join_mode>
         <urlname>North-Coast-Gamers-Cleveland</urlname>
         <name>Games!  North Coast Gamers - Greater Cleveland Chapter</name>
         <id>319720</id>
         <group_lat>41.5</group_lat>
         <group_lon>-81.6699981689</group_lon>
        </group>
        <yes_rsvp_count>1</yes_rsvp_count>
        <created>1378692585000</created>
        <visibility>public</visibility>
        <name>Yu-Gi-Oh Traditional Format TCG Tournament</name>
        <id>dlhktgyrmblc</id>
        <headcount>0</headcount>
        <duration>14400000</duration>
        <utc_offset>-14400000</utc_offset>
        <time>1380398400000</time>
        <event_url>http://www.meetup.com/North-Coast-Gamers-Cleveland/events/139162192/</event_url>
       </item>
      </items>
     </results>

    Answered this in PM as well, I’m guessing the security problems is that file_get_contents isn’t allowed to open URLs. Have you tried the CURL-method I suggested?

    I responded that I would not even know how to implement it.

    google search: php curl

    first hit:
    http://www.jonasjohn.de/snippets/php/curl-example.htm

    let us know if you have any trouble with it :slight_smile:

    you should be able to use it like this:

    [php]$xmlString = curl_download(‘http://site.com/where/you/get/data.xml’);[/php]

    Hmm… I was looking at http://wiki.dreamhost.com/CURL_PHP_tutorial for a little step-by-step. I will let you know how things go. Thanks.

    Okay, it is working, but now I am to the point where it does not read anything beyond the main branch of the XML tree.

    [php]

    <?php $ch = curl_init("data.xml"); $fp = fopen("upcoming.html", "w"); curl_setopt($ch, CURLOPT_FILE, $fp); curl_setopt($ch, CURLOPT_HEADER, 0); curl_exec($ch); curl_close($ch); fclose($fp); $xml = simplexml_load_file('upcoming.html'); print "
    "; var_dump($item); // For testing purposes.
    }
        print "";
    
    ?>
    

    [/php]

    I figured it out. I am so proud of myself. Thanks JimL!

    [php]

    <?php $ch = curl_init("http://www.blahblahblah.com/data.xml"); $fp = fopen("data-output.html", "w"); curl_setopt($ch, CURLOPT_FILE, $fp); curl_setopt($ch, CURLOPT_HEADER, 0); curl_exec($ch); curl_close($ch); fclose($fp); $xml = file_get_contents('data-output.html'); $results = new SimpleXMLElement($xml); print ""; foreach ($results->items->item as $item) { $time = (float) $item->time / 1000; // Convert from milliseconds to seconds. $end = ((float) $item->time + (float) $item->duration) / 1000; // Add begin time and duration to produce end time, then convert from milliseconds to seconds. $tz = (float) $item->utc_offset / 1000; // Convert from milliseconds to seconds. $timetz = $time + $tz; // Add start time and timezone to correct offset. $endtz = $end + $tz; // Add end time and timezone to correct offset. $dt = new DateTime("@$timetz"); // Convert UNIX timestamp to PHP DateTime $newtime = $dt->format('M. j, Y @ g:i A'); // Display date and time begin $ee = new DateTime("@$endtz"); // Convert UNIX timestamp to PHP DateTime $newend = $ee->format('g:i A'); // Display time end $venue = $item->venue->name; // List venue since code does not like printing variables more than one level into XML tree. // For output testing purposes. // print "Time Begin: $time
    Time End: $end
    Timezone: $tz
    "; // print "Time (ADJ): $timetz
    Date Begin: $newtime
    Date End: $newend
    "; // print "Name: $item->name
    Description: $item->description
    URL: $item->event_url
    Location: $item->venue->name
    "; print "
  • event_url\" target=\"newwindow\" title=\"$item->description\">$item->name - $newtime to $newend ($venue)
  • \n"; // print "
    "; var_dump($item); // For variable testing purposes.
    }
        print "";
    
    ?>
    

    [/php]

    Sponsor our Newsletter | Privacy Policy | Terms of Service