SimpleXML to get specific data from an XML file - php

I am making a plugin for JomSocial that will display billing information for a logged-in user, based on an XML file. I have made good headway creating the plugin, I just cant seem to get the syntax right to create php statements so I can populate data in various places on the page. Here is the XML file:
<Inquiry>
<Billing>
<Version>4.5.1</Version>
<startTime><![CDATA[4/15/2014 11:09 PM]]></startTime>
<endTime><![CDATA[4/15/2014 11:12 PM]]></endTime>
<Date>20140415</Date>
<MemberId ID="0ESING">
<BillingInfo>
<StatementEndDate>20140430</StatementEndDate>
<BillingSubAccount>
</BillingSubAccount>
<BalanceForward>628.32</BalanceForward>
<BalanceDue>372</BalanceDue>
<Payments>-300</Payments>
</MemberId>
<MemberId ID="F00421">
</BillingInfo>
<BillingInfo>
<StatementEndDate>20140430</StatementEndDate>
<BillingSubAccount>
</BillingSubAccount>
<BalanceForward>1158.36</BalanceForward>
<BalanceDue>93.45</BalanceDue>
<Payments>-1158.36</Payments>
Here is the PHP so far:
$user =& CFactory::getRequestUser();
$cuser = CFactory::getUser();
$owner = CFactory::getUser($row->user->id);
$ptype = $cuser->getProfileType();
$billingid = $owner->getInfo('FIELD_BILLINGID');
$lastname = $owner->getInfo('FIELD_FAMILYNAME');
$uname = $cuser->username;
$memid = $cuser->id;
$name = $cuser->getDisplayName();
$isMine = COwnerHelper::isMine($cuser->id, $user->id);
$config = CFactory::getConfig();
$source = file_get_contents('data/201404.xml');
$xml = new SimpleXMLElement($source);
$balance = $xml->Billing->MemberId->BillingInfo->BalanceDue;
$BalanceForward = $xml->Billing->MemberId->BillingInfo->BalanceForward;
$Payments = $xml->Billing->MemberId->BillingInfo->Payments;
ob_start();
if( $isMine ) {
if($ptype == '2') {
if(strcasecmp($uname, $billingid) == 0) {
Then, in page to call the fields:
<?php echo "<div>Balance Due: $". $balance ." | Balance Forward: $" . $BalanceForward . " | Payment: $" . $Payments . "</div>"; ?>
This pulls in the first record of the XML file. I was trying something like this for hours:
$source = file_get_contents('data/201404.xml');
$xml = new SimpleXMLElement($source);
$balance = $xml->Billing->MemberId[.$uname.]->BillingInfo->BalanceDue;
$BalanceForward = $xml->Billing->MemberId[.$uname.]->BillingInfo->BalanceForward;
$Payments = $xml->Billing->MemberId[.$uname.]->BillingInfo->Payments;
to no avail. I would like to 'pull' the child node from the XML where the MemberId ID= "yadayada" is equal to the $uname. I hope I am being clear, this is my first post on Stackoverflow!

Using the square bracket notation accesses the attribute by it's name, so you are asking for member[0ESING] which isn't right because the attribute is named ID.
You can iterate of the members to find the match like so:
foreach($xml->Billing->MemberId as $member){
if($member['ID'] == $uname){
$balance = $member->BillingInfo->BalanceDue;
$BalanceForward = $member->BillingInfo->BalanceForward;
$Payments = $member->BillingInfo->Payments;
}
}

Why are you not using simplexml_load_file() instead? It saves you the hassle in loading the file manually and putting it in a simplexml_element instead. Furthermore, I think your issues arrise because the XML file itself is invalid, it need 1 root element but instead seems to contain zero (or multiple, depends on how one would read the file).

Related

How to output the amount of comments left by a user with JComments / Joomla 3?

JoomlaTune - developers of the JComments extension - offers the following code to display comments anywhere:
<?php
$comments = JPATH_SITE . '/components/com_jcomments/jcomments.php';
if (file_exists($comments)) {
require_once($comments);
$options = array();
$options['object_id'] = $this->item->id;
$options['object_group'] = 'com_content';
$options['published'] = 1;
$count = JCommentsModel::getCommentsCount($options);
echo ('<span>'. $count .'</span>');
}
?>
by substituting the id of the article into $this->item->id you can get the number of materials for this article.
Is it possible to somehow adapt this code to display the number of comments left by specific users by his id. Or maybe this variable already exists somewhere in the component code?
Thanks a lot in advance!
all you need to do is add the following code:
use Joomla\CMS\Factory;
$user = Factory::getUser();
$options['userid'] = $user->id;
just before:
$count = JCommentsModel::getCommentsCount($options);

PHP Website Crawler Data Extraction Multiple Loop Error 404

I am looking to crawl multiple gig listing websites to compile a ultimate listing guide with links back to the original websites.
A lot of these websites don't have an API so I have to use a rather crudely put together php script that will extract the data I require. (eg date, venue, country etc)
Most sites have a fairly easy to use directory of gigs, but on certain sites, they require manually inputting information to get "relevant" shows to you.
So to get around this, I created a loop that worked on the basis of:
page.php?id=$counter+1
So it finds the last inserted gig into the db and carries on getting data for the next 100 or so.
BUT this only works on the condition that the gigs on the site will continue numerically accurately, and of course, they don't due to cancellations etc.
This leaves me with the wonderful
Warning: file_get_contents(http://www.domain.com/show/page.php?id=123456) [function.file-get-contents]: failed to open stream: HTTP request failed! HTTP/1.1 404 Not Found in...
How is it possible to create a loop that will be able to skip these errors and carry on rather than just sitting on them?
Below is the entire code (Limit of +5 at the moment for testing)
include_once('simple_html_dom.php');
$cntqry = mysql_query("SELECT * FROM `gigs_tbl` ORDER BY `counter` DESC LIMIT 1");
$cntnum = mysql_num_rows($cntqry);
if($cntnum!=0)
{
$cntget = mysql_fetch_assoc($cntqry);
$start = $cntget['counter'];
}
else {
$start = 10767799;
}
$counter = 0;
$limit = $start +5;
for($start; $start < $limit; $start++) {
$counter = $start + 1;
$target_url = "http://www.domain.com/show/page.php?id=$counter";
$html = new simple_html_dom();
$html->load_file($target_url);
foreach($html->find('div[class=vevent]') as $showrow){
$artist = strip_tags($showrow->find('h2',0));
$genre = strip_tags($html->find('span[class=genre]',0));
$venue = strip_tags($showrow->find('span[class=location]',0));
$street = strip_tags($html->find('span[itemprop=streetAddress]',0));
$locality = strip_tags($html->find('span[itemprop=addressLocality]',0));
$postcode = strip_tags($html->find('span[itemprop=postalCode]',0));
$country = strip_tags($html->find('span[itemprop=addressRegion]',0));
$originalDate = strip_tags($html->find('meta[itemprop=startDate]',0)->content);
$newDate = date("U", strtotime($originalDate));
// INSERT
mysql_query("INSERT INTO `gigs_tbl` VALUES('','$counter','$newDate','$venue','$street','$locality','$postcode','$country','$gen re','$artist','reverbnation')");
}
}
Ten virtual high fives to anyone who can guess which website is causing this issue ;)
find() returns NULL if nothing found... So, a way to do what you want is to exploit this :)
Since your didnt provide the real link, here's an example explaining how:
$start = 'u';
for($start; $start < 'x'; $start++) {
// The only correct url is => http://sourceforge.net/p/mingw/bugs/
$target_url = "http://sourceforge.net/p/ming".$start."/bugs/";
echo "<br/> Link: $target_url";
// #: supresses the errors when the page doesnt exist
$data_string = #file_get_contents($target_url);
$html = new simple_html_dom();
// Load HTML from a string
$html->load($data_string);
// Find returns NULL if nothing found
$search_elements = $html->find('#nav_menu_holder h1');
if($search_elements) {
echo "<br/> Page FOUND. Title => " . $search_elements[0]->plaintext;
}
else {
echo "<br/> Page NOT FOUND !!";
}
echo "<hr>";
// Clear DOM object
$html->clear();
unset($html);
}
PHP-Fiddle DEMO

How to select attributes in XML based on an ID?

I am trying to get a group of attributes from an XML file based on the ID. I have looked around and haven't found a solution that works.
Here is my XML:
<data>
<vico>2</vico>
<vis>
<vi>
<id>1</id>
<name>Vill1</name>
<att>2</att>
<hp>100</hp>
<xp>10</xp>
</vi>
<vi>
<id>2</id>
<name>Vill2</name>
<att>3</att>
<hp>120</hp>
<xp>12</xp>
</vi>
</vis>
</data>
What I am looking to do is create a script that takes the value of vico and does mt_rand(0,vico) (Already created this part of the code), and based on the number that comes up, it pulls that node.
For instance, if the number is 2, I would like it to pull all of the attributes where the id in the xml file is 2. I am thinking I have to make the ID a parent of the other attributes, but I am not sure. For the life of me I can't figure this out. I also want to make sure this is even possible before I invest anymore time.
I do realize this can be done very easily with mySQL but I have chose not to do it that way for portability as I am working off a thumb drive. Any help would be greatly appreciated.
Working code for pulling based on ID:
$xml = simplexml_load_file("vi.xml")
or die("Error: Cannot create object");
$vc = $xml->vico;
$select = mt_rand()&$vc;
if ($select == 0) {
$select = $select + 1;
}
$result = $xml->xpath("/data/vis/vi/id[.='".$select."']/parent::*");
if ($result) {
$node = $result[0];
$name = $node->name;
$att = $node->att;
$hp = $node->hp;
$xp = $node->xp ;
} else {
// nothing found for this id
}
Using xpath to retrieve the node where id=your value (it is based on the value).
$result = $xml->xpath("/data/vis/vi/id[.='".$select."']/parent::*");
if ($result) {
$node = $result[0];
$name = $node->name;
$att = $node->att;
$hp = $node->hp;
$xp = $node->xp ;
} else {
// nothing found for this id
}
If you're using SimpleXML:
$name = $xml->vis->vi[$vico]->name;
$att = $xml->vis->vi[$vico]->att;
$hp = $xml->vis->vi[$vico]->hp;
$xp = $xml->vis->vi[$vico]->xp;

(Redbean) Unable to access linked table values

I am testing out the Redbean ORM. I like how it works, less work for me :) I am using the redbean books example, from their website. I have been able to create new books with authors and titles, and display them to the page with no problem. I added another dimension to learn how to link pages to my books.
I am able to add an entry into the book table, as well as add an entry into the page table using the following code:
----------- dbmgmt.php ---------------------------------
function AddNewBook($FORMINFO){
$newBook = R::dispense('book');
$newBook->title = $FORMINFO['title'];
$newBook->author = $FORMINFO['author'];
$newBook->create_date = R::isoDateTime();
$newPage = R::dispense('page');
$newPage->pagetext = $FORMINFO['pagetext'];
$newBook->ownPage = $newPage;
$id = R::store($newBook);
return R::load('book', $id);
}
Both tables show the proper entries (new ids and populated fields). However, I am having a hard time accessing the pagetext field from the page table. This is the code I have been using for that:
----------- dbmgmt.php ---------------------------------
function GetBooks($id){
if($id == ""){
return R::find('book');
}
else{
return R::find('book','id = ?', array($id));
}
}
----------- GetBooks.php ---------------------------------
$id = "";
if(isset($_GET['id'])){
$id = $_GET['id'];
}
$books = GetBooks($id);
$booklist = "";
foreach($books as $book){
$pagetext = "";
foreach($book->ownPage as $page){
$pagetext .= $page->pagetext; //Errors with "Notice: Trying to get property of non-object"
}
$booklist .= "<tr id='$book->id'><td><a class='linkEdit' href='edit.php?id=$book->id'><img src='http://cdn1.iconfinder.com/data/icons/ledicons/page_white_edit.png' /></a> <span class='book-title'>$book->title</span></td><td><span class='book-author'>$book->author</span></td><td><span class='page-text'>$pagetext</span></td></tr>";
}
echo $booklist;
------------------------------------------------------------
When I print_r($book->ownPage), I don't even see the page entry that I can clearly see in the page table via phpmyadmin. I have tried many different ways of accessing the pagetext field via my script above, but can't get anywhere with it.
Any insight would be most welcome. Otherwise I will have to try a different, albeit bigger and more cumbersome, ORM.
Thanks in advance.
I am not 100% sure as I haven't encountered this problem yet myself, but I am almost positive, $book->ownPage needs to be an array:
$newPage = R::dispense('page');
$newPage->pagetext = $FORMINFO['pagetext'];
$newBook->ownPage[] = $newPage;
$id = R::store($newBook);

ExpressionEngine: how to get the path of a page given its entry_id (with the structure plug-in)

I'm trying to build an extension that would create pages for automatic redirections of short URLs, and to make it short, I need to get the path of a page given its entry_id.
Say, I have a page with the path: http://server.tld/index.php/path/to/my/page
But, in the code, I only know the entry_id of this page.
If I look on the exp_channel_titles table, I can get the url_title field. But it will only contain "page". And I'd like to get "/path/to/my/page". And there doesn't seem to be any API for this.
Do you know how I could proceed?
Thanks a lot.
I can't remember exactly where in the documentation it is, but I think your issue is coming from the fact that the page uris are not retrieved directly from the database.
They are instead located in the Expressionengine global configuration variables. I've been able to do a url lookup using the entry_id using the following code:
Note: This assumes you are using structure, pages module, etc.
<?php
$this->EE =& get_instance(); // Get global configuration variable
$site_id = $this->EE->config->item('site_id'); // Get site id (MSM safety)
$site_pages = $this->EE->config->item('site_pages'); // Get pages array
/** The array is indexed as follows:
* $site_pages[{site_id}]['url'] = '{site_url}
* $site_pages[{site_id}]['uris']['entry_id'] = {page_uri}
**/
$page_url = $site_pages[$site_id]['uris'][$entry_id];
?>
EDIT:
I initially stated that the uris are not in the database which is not strictly speaking true... Pages are actually stored as a hashed string in exp_sites.site_pages indexed by site id.
I did not find anything better than the following code:
//
//
// Don't look the following code just yet . . .
//
//
// You'll be pulling your hair out of your head. Just read me first.
// Following is a huge SQL query, that assume that pages are not nested
// than 9 times. This is actually a hard limitation of EE, and I'm using
// that to get the information I need in only one query instead of nine.
//
// The following code is just to get the path of the current entry we are
// editing, so the redirect page will know where to redirect. And I did
// not find any function or API to get this information. Too bad.
//
// If you find any solution to that, please answer
// http://stackoverflow.com/questions/8245405/expressionengine-how-to-get-the-path-of-a-page-given-its-entry-id-with-the-str
// it might save other people all the trouble.
// S
//
// P
//
// O
//
// I
//
// L
//
// E
//
// R
// First, we get all the entry_id of all the elements that are parent to
// the current element in the structure table (created by the Structure
// plugin).
$q = $this->EE->db->query(
"SELECT
S1.entry_id AS entry9,
S2.entry_id AS entry8,
S3.entry_id AS entry7,
S4.entry_id AS entry6,
S5.entry_id AS entry5,
S3.entry_id AS entry4,
S7.entry_id AS entry3,
S8.entry_id AS entry2,
S9.entry_id AS entry1
FROM
exp_structure AS S1,
exp_structure AS S2,
exp_structure AS S3,
exp_structure AS S4,
exp_structure AS S5,
exp_structure AS S6,
exp_structure AS S7,
exp_structure AS S8,
exp_structure AS S9
WHERE
S1.entry_id = $entry_id AND
S1.parent_id = S2.entry_id AND
S2.parent_id = S3.entry_id AND
S3.parent_id = S4.entry_id AND
S4.parent_id = S5.entry_id AND
S5.parent_id = S6.entry_id AND
S6.parent_id = S7.entry_id AND
S7.parent_id = S8.entry_id AND
S8.parent_id = S9.entry_id");
// Then, we construct a similar query to get all the url_title attributes
// for these pages.
$path = array();
$sql = array("SELECT" => "SELECT", "FROM" => " FROM", "WHERE" => " WHERE");
$j = 1;
for($i = 1; $i <= 9; ++$i){
$id = $q->row("entry$i");
if($id > 0){
$sql['SELECT'] .= " CT$j.url_title AS title$j,";
$sql['FROM'] .= " exp_channel_titles as CT$j,";
$sql['WHERE'] .= " CT$j.entry_id = $id AND";
$j++;
}
}
$sql['SELECT'] = rtrim($sql['SELECT'], ",");
$sql['FROM'] = rtrim($sql['FROM'], ",");
$sql['WHERE'] = preg_replace("/ AND$/", "", $sql['WHERE']);
$sql = $sql['SELECT'] . $sql['FROM'] . $sql['WHERE'];
$q = $this->EE->db->query($sql);
// Finally, we can construct the path for the current page
$path = "/";
for($i = 1; $i < $j; ++$i){
$path .= $q->row("title$i") . '/';
}
//
// Blood and bloody ashes.
//
May I suggest asking the Structure devs via their support forum?

Categories