problem calculating the position using php - php

I have a function below which gets name from a site. Below is the partial code, not complete. The values are passed thru a for loop using php.
function funct($$name,$page)
{
$url="http://testserver.com/client?list=$name&page=$page";
$ch=curl_init();
curl_setopt($ch,CURLOPT_URL,url);
$result=curl_exec($ch);
$dom = new DOMDocument();
#$dom->loadHTML($result);
$xpath=new DOMXPath($dom);
$elements = $xpath->evaluate("//div");
foreach ($elements as $element)
{
$name = $element->getElementsByTagName("name")->item(0)->nodeValue;
$position=$position +1;
echo $name.$position;
}
}
The code works fine but when i get a name i need to add a position and for each name it will be incremented by 1 to make it contentious. But when the values for the pages are passed, for an example when i move from page 1 to page 2. the count starts again from first, next page... same problem.
How can i make it continues on every page?

Either make $position a global variable (global $position;) or pass it to the function: function funct($name, $page, &$position). (What's with the variable variable $$name in your function signature?)

Use $_SESSION. It's designed specifically to maintain state.

Related

Recursive function for testing all links on the page

I am writing scraper links from all over the site, including subpages and encountered a small problem. I came up with the idea to use a recursive function because the page I want to scan has several levels. Its structure looks more or less like this:
Level 1 reference
- Second level reference
-- Third level reference
-- Third level reference
- Second level reference
-- Third level reference
-- Third level reference
-- Third level reference
--- Level four reference
It is never entirely clear whether there are more or less hidden under the tested link, hence I came up with the idea of a recursive function.
It takes a link to the main page, takes the first one and if the number of links in it is greater than one, it refers to the same function.
Unfortunately, something goes wrong and I get an empty whiteboard, how can I fix it?
function scanWebsite($url) {
$html = file_get_contents($url);
$dom = new DOMDocument();
#$dom->loadHTML($html);
$xpath = new DOMXpath($dom);
$nodes = $xpath->query("/html/body//a");
$output = [];
foreach($nodes as $node) {
$url = $node->getAttribute("href");
if(count($nodes) > 1) {
scanWebsite("http://samplewebsite.com" .$url);
} else {
if(preg_match("/\/title\/.*\//", $url)) {
array_push($output, $url);
}
continue;
}
}
return $output;
}
echo '<pre>';
print_r(scanWebsite("http://samplewebsite.com"));
echo '</pre>';

How to get iTunes-specific child nodes of RSS feeds?

I'm trying to process an RSS feed using PHP and there are some tags such as 'itunes:image' which I need to process. The code I'm using is below and for some reason these elements are not returning any value. The output is length is 0.
How can I read these tags and get their attributes?
$f = $_REQUEST['feed'];
$feed = new DOMDocument();
$feed->load($f);
$items = $feed->getElementsByTagName('channel')->item(0)->getElementsByTagName('item');
foreach($items as $key => $item)
{
$title = $item->getElementsByTagName('title')->item(0)->firstChild->nodeValue;
$pubDate = $item->getElementsByTagName('pubDate')->item(0)->firstChild->nodeValue;
$description = $item->getElementsByTagName('description')->item(0)->textContent; // textContent
$arrt = $item->getElementsByTagName('itunes:image');
print_r($arrt);
}
getElementsByTagName is specified by DOM, and PHP is just following that. It doesn't consider namespaces. Instead, use getElementsByTagNameNS, which requires the full namespace URI (not the prefix). This appears to be http://www.itunes.com/dtds/podcast-1.0.dtd*. So:
$img = $item->getElementsByTagNameNS('http://www.itunes.com/dtds/podcast-1.0.dtd', 'image');
// Set preemptive fallback, then set value if check passes
urlImage = '';
if ($img) {
$urlImage = $img->getAttribute('href');
}
Or put the namespace in a constant.
You might be able to get away with simply removing the prefix and getting all image tags of any namespace with getElementsByTagName.
Make sure to check whether a given item has an itunes:image element at all (example now given); in the example podcast, some don't, and I suspect that was also giving you trouble. (If there's no href attribute, getAttribute will return either null or an empty string per the DOM spec without erroring out.)
*In case you're wondering, there is no actual DTD file hosted at that location, and there hasn't been for about ten years.
<?php
$rss_feed = simplexml_load_file("url link");
if(!empty($rss_feed)) {
$i=0;
foreach ($rss_feed->channel->item as $feed_item) {
?>
<?php echo $rss_feed->children('itunes', true)->image->attributes()->href;?>
<?php
}
?>

PHP return value after XML exploration

I got a PHP array with a lot of XML users-file URL :
$tab_users[0]=john.xml
$tab_users[1]=chris.xml
$tab_users[n...]=phil.xml
For each user a <zoom> tag is filled or not, depending if user filled it up or not:
john.xml = <zoom>Some content here</zoom>
chris.xml = <zoom/>
phil.xml = <zoom/>
I'm trying to explore the users datas and display the first filled <zoom> tag, but randomized: each time you reload the page the <div id="zoom"> content is different.
$rand=rand(0,$n); // $n is the number of users
$datas_zoom=zoom($n,$rand);
My PHP function
function zoom($n,$rand) {
global $tab_users;
$datas_user=new SimpleXMLElement($tab_users[$rand],null,true);
$tag=$datas_user->xpath('/user');
//if zoom found
if($tag[0]->zoom !='') {
$txt_zoom=$tag[0]->zoom;
}
... some other taff here
// no "zoom" value found
if ($txt_zoom =='') {
echo 'RAND='.$rand.' XML='.$tab_users[$rand].'<br />';
$datas_zoom=zoom($r,$n,$rand); } // random zoom fct again and again till...
}
else {
echo 'ZOOM='.$txt_zoom.'<br />';
return $txt_zoom; // we got it!
}
}
echo '<br />Return='.$datas_zoom;
The prob is: when by chance the first XML explored contains a "zoom" information the function returns it, but if not nothing returns... An exemple of results when the first one is by chance the good one:
// for RAND=0, XML=john.xml
ZOOM=Anything here
Return=Some content here // we're lucky
Unlucky:
RAND=1 XML=chris.xml
RAND=2 XML=phil.xml
// the for RAND=0 and XML=john.xml
ZOOM=Anything here
// content founded but Return is empty
Return=
What's wrong?
I suggest importing the values into a database table, generating a single local file or something like that. So that you don't have to open and parse all the XML files for each request.
Reading multiple files is a lot slower then reading a single file. And using a database even the random logic can be moved to SQL.
You're are currently using SimpleXML, but fetching a single value from an XML document is actually easier with DOM. SimpleXMLElement::xpath() only supports Xpath expression that return a node list, but DOMXpath::evaluate() can return the scalar value directly:
$document = new DOMDocument();
$document->load($xmlFile);
$xpath = new DOMXpath($document);
$zoomValue = $xpath->evaluate('string(//zoom[1])');
//zoom[1] will fetch the first zoom element node in a node list. Casting the list into a string will return the text content of the first node or an empty string if the list was empty (no node found).
For the sake of this example assume that you generated an XML like this
<zooms>
<zoom user="u1">z1</zoom>
<zoom user="u2">z2</zoom>
</zooms>
In this case you can use Xpath to fetch all zoom nodes and get a random node from the list.
$document = new DOMDocument();
$document->loadXml($xml);
$xpath = new DOMXpath($document);
$zooms = $xpath->evaluate('//zoom');
$zoom = $zooms->item(mt_rand(0, $zooms->length - 1));
var_dump(
[
'user' => $zoom->getAttribute('user'),
'zoom' => $zoom->textContent
]
);
Your main issue is that you are not returning any value when there is no zoom found.
$datas_zoom=zoom($r,$n,$rand); // no return keyword here!
When you're using recursion, you usually want to "chain" return values on and on, till you find the one you need. $datas_zoom is not a global variable and it will not "leak out" outside of your function. Please read the php's variable scope documentation for more info.
Then again, you're calling zoom function with three arguments ($r,$n,$rand) while the function can only handle two ($n and $rand). Also the $r is undiefined, $n is not used at all and you are most likely trying to use the same $rand value again and again, which obviously cannot work.
Also note that there are too many closing braces in your code.
I think the best approach for your problem will be to shuffle the array and then to use it like FIFO without recursion (which should be slightly faster):
function zoom($tab_users) {
// shuffle an array once
shuffle($tab_users);
// init variable
$txt_zoom = null;
// repeat until zoom is found or there
// are no more elements in array
do {
$rand = array_pop($tab_users);
$datas_user = new SimpleXMLElement($rand, null, true);
$tag=$datas_user->xpath('/user');
//if zoom found
if($tag[0]->zoom !='') {
$txt_zoom=$tag[0]->zoom;
}
} while(!$txt_zoom && !empty($tab_users));
return $txt_zoom;
}
$datas_zoom = zoom($tab_users); // your zoom is here!
Please read more about php scopes, php functions and recursion.
There's no reason for recursion. A simple loop would do.
$datas_user=new SimpleXMLElement($tab_users[$rand],null,true);
$tag=$datas_user->xpath('/user');
$max = $tag->length;
while(true) {
$test_index = rand(0, $max);
if ($tag[$test_index]->zoom != "") {
break;
}
}
Of course, you might want to add a bit more logic to handle the case where NO zooms have text set, in which case the above would be an infinite loop.

Fatal error: Function name must be a string Line 11

I know there are plenty of these, and that my PHP may be riddled with errors (I'm new to PHP), but I cant figure this one out.... it's citing the "function must be a string" error on line 11:
<?php
$dom=new DOMDocument();
$dom->formatOutput=true;
$dom->load('test.xml');
$searchItems=$dom->getElementsByTagName('title');
$voteItems=$dom->getElementsByTagName('vote');
for ($i=0; $i < $searchItems->length; $i++){
$value = $voteItems($i)->textContent;
$value++;
$name=$searchItems($i);
$xpath = new DOMXPath($dom);
$resulted = $xpath->query('div[#class="active"]');
$active= $div->$resulted->query('div[#class="content"]');
$names=$active->getAttribute('song');
preg_match($names, "i");
if(preg_match($names, $name )){
$voteItems($i)->length->textContent=$value;
$vote = voteItems($i)->length->textContent;
$results=array($name, $vote);
$txt=($name." scored: ".$vote." votes");
echo $txt;
}
}
?>
What this is doing, just in case there's a WAYYY better way to do this is, it checks and XML sheet I have that looks like this:
<playslist>
<song>
<source>imgs/Beck.jpg</source>
<title>Modern Guilt</title>
<artist>Beck</artist>
<vote>0</vote>
<plays>y</plays>
</song>
</playlist>
It checks for the title, and vote for each song, and stores those.
It then for each gets the value of the vote tag, adds one, then searches the HTML for the <div> with the class="active", and then searches that div with active and finds the inner div that has the class="content", then returns that div's "song" attribute.
I then have a preg match to check whether the name of the current "i" in the loop matches the string from the "song" attribute.
If it's a match, that "i"'s value will +1 to its value. It will then store that name value, and the new vote value as an array for me to check.
After that I'd like to save the XML sheet's new change. (otherwise I would've just kept this in JavaScript)
Any tips, hints, and help would be greatly appreciated! As a newbie to PHP I love to learn more!
$value = $voteItems($i)->textContent;
This is incorrect. You're trying to take $voteItems and use it as the name of a function.
PHP allows it:
function foo() {}
$name = "foo";
$name(); // calls foo()
However, that can only work if $name is a string. Here, $voteItems is a DOMNodeList, hence the error message.
From looking at the documentation, it seems like you meant to write:
$value = $voteItems->item($i)->textContent;
// ^^^^^^^^^^

Linked list not saving datamembers

Using PHP 5.3.10, I created a link-list class and am trying to save a list of football players.
After calling the add function, it seems that the object never retains any information. var_dump($playerList) returns NULL for both my head and tail pointers. Or, if I replace it with var_dump($playerList->count), it prints nothing no matter where I place the var_dump count statement.
I have been through the manual and cannot find the error in my syntax. My gut is telling me mysql_fetch_array is doing something funky. As stated below, my testing shows that values are in fact being passed around when I call playerList->add(). Anyhow, here is my simple code:
/* Populates lists with available players. */
function populateList($sql)
{
$playerList = new PlayerList();
while ($row = mysql_fetch_array($sql, MYSQL_NUM))
{
$playerList->add(new Player($row[0], $row[1], $row[2], $row[3], $row[4]));
}
var_dump($playerList);
}
And my linked list class:
include 'PlayerNode.php';
class PlayerList
{
public $head;
public $tail;
public $count;
function PlayerList()
{
$head = null;
$tail = null;
$count = 0;
}
function add($player)
{
$count ++;
$node = new PlayerNode($player);
//First time in
if ($head == null)
{
$head = $node;
$tail = $node;
$head->nextPtr = null;
}
// All other times
else
{
$tail->nextPtr = $node;
$tail = $node;
$node->nextPtr = null;
}
$count++;
}
}
I can place var_dump($node) and echo statements in the linked list class and observe that PlayerNode is working correctly.
But, another strange observation... if($head==null) ALWAYS evaluates to true too. Could this be related?
Insertion in the head of the Singly Linked Lists :
We can easily insert the elements in the head of the list. So how we do it? Create a new node, set the next of the new node point to the current head node, and set the head variable (in the class) point to the new node. This method works even if the Linked List is empty. Note that we set the next of the new node point to the head node, before we sent the head variable to point to the new node.
Insertion in the tail of the Singly Linked Lists:
We can also easily insert elements in the tail of the Linked List, provided we keep a reference for the tail node of the Linked Lists. Create an new node set the next of the new node to null, set the next of the tail node point to the new node, set the tail variable to point to the new element. Note we set the next of the previous tail node before we change the tail variable to point to the new node.
In all the other times add the new node to the head or tail.
// All other times if head
else{
$temp = $head;
$head = $node;
$node->nextPtr = $temp;
count ++;
}

Categories