php foreach issue - php

I'm using simple_html_dom_helper so do some screen scraping and am encountering some errors.
The second foreach runs 4 times (since sizeof($pages) == 4), while it should only run once. I got this code from an example script where table.result-liste occurs several times on the page. In my case it only occurs once, so imho there is no need for a foreach. The print_r($data) prints out the same thing 4 times and there's no need for that.
Further down I'm trying to do the same without the foreach but it just prints out no, so there seems to a different response and am not sure why.
foreach( $pages as $page )
{
$p = $this->create_url($codes[0], $price, $page); //pass page number along
$p_html = file_get_html($p);
$row = $p_html->find("table[class=result-liste] tr");
//RUNS OK BUT NO NEED TO DO IT FOUR TIMES.
//CLASS RESULT-LISTE ONLY OCCURS ONCE ANYWAY
foreach( $p_html->find("table[class=result-liste] tr") as $row)
{
//grab only rows where there is a link
if( $row->find('td a') )
{
$d_price = $this->get_price($row->first_child());
$d_propid = $this->get_prop_id($row->outertext);
$data = array(
"price" => $d_price,
"prop_id" => $d_propid
);
print_r($data);
}
}
//MY ATTEMPT TO AVOID THE SECOND FOREACH DOES NOT WORK ...
$row = $p_html->find("table[class=result-liste] tr");
if( is_object($row) && $row->find('td a')) print "yes ";
else print "no ";
}

Even though the table[class=result-liste] only occurs once on your page, this find statement is looking for the <tr> elements that are the table's rows. So unless your table has only one row, you will need this foreach.
$p_html->find("table[class=result-liste] tr")

Your code
foreach( $p_html->find("table[class=result-liste] tr") as $row)
{
//grab only rows where there is a link
if( $row->find('td a') )
{
$d_price = $this->get_price($row->first_child());
$d_propid = $this->get_prop_id($row->outertext);
$data = array(
"price" => $d_price,
"prop_id" => $d_propid
);
print_r($data);
}
}
Replace above code by MY code
$asRow = $p_html->find("table[class=result-liste] tr");
$row = $asRow[0];
//grab only rows where there is a link
if( $row->find('td a') )
{
$d_price = $this->get_price($row->first_child());
$d_propid = $this->get_prop_id($row->outertext);
$data = array(
"price" => $d_price,
"prop_id" => $d_propid
);
print_r($data);
}
Try with this.

Related

Iteration copying over itself on loop

I'm using ACF's update_sub_field function to add content from a loop to a child repeater field.
I've got it to a point where the data is being added to the child repeater but it's overwriting itself. It only ever updates the first row in the child repeater so I only ever see the last loop through.
I'm iterating the parent repeater using $counter, but when I try to add an iteration to the child repeater it breaks the function. Like so:
update_sub_field( array($field_key, $counter, $sub_field_key, $rowcount), $value, $post_id );
I've tried another function add_sub_row... this adds the correct number of rows to the child repeater's but doesn't add the data.
Here's my full code:
// Product Code Titles
$rows = $html->find('div[class=product-table]', 0)->find('tr');
$field_key = "field_5ae0882f9d6f9";
$sub_field_key = "field_5ae088999d6fb";
if(empty($rows)){
die("Empty array");
}
$titles = array(); // aka your $data
// here we fetch the first row and iterate to get titles
$row = current($rows);
foreach ($row->find('td') as $cell) {
$titles[] = array("column_title" => strip_tags($cell->innertext));
}
update_field( $field_key, $titles, $post_id );
// here we continue iteration starting from second row
$value = array();
$rowcount = 1;
while($row = next($rows)){
$cells = $row->find('td');
$columnsCount = count($cells);
$counter = 1;
foreach ($cells as $cell) {
$value[] = array("text" => strip_tags($cell->innertext));
update_sub_field( array($field_key, $counter, $sub_field_key), $value, $post_id );
echo '<pre>'; print_r($value); echo '</pre>';
$value = array();
$counter++;
}
$rowcount++;
}
Just to give some context, I'm recreating this table with the cell data being put into a child repeater field.
There's not much on this subject so hope this helps someone else.
I stopped it appending to the $value array, changed the function to update_sub_row and added a counter to iterate the child repeater rows.
Here's the full code:
// Product Code Titles
$rows = $html->find('div[class=product-table]', 0)->find('tr');
$field_key = "field_5ae0882f9d6f9";
$sub_field_key = "field_5ae088999d6fb";
if(empty($rows)){
die("Empty array");
}
$titles = array(); // aka your $data
// here we fetch the first row and iterate to get titles
$row = current($rows);
foreach ($row->find('td') as $cell) {
$titles[] = array("column_title" => strip_tags($cell->innertext));
}
update_field( $field_key, $titles, $post_id );
// here we continue iteration starting from second row
$value = array();
$rowcount = 1;
while($row = next($rows)){
$cells = $row->find('td');
$columnsCount = count($cells);
$counter = 1;
foreach ($cells as $cell) {
$value = array("field_5ae088b79d6fc" => strip_tags($cell->innertext));
update_sub_row( array($field_key, $counter, $sub_field_key), $rowcount, $value, $post_id );
echo '<pre>'; print_r($value); echo '</pre>';
$value = array();
$counter++;
}
$rowcount++;
}

Mongo db cursor count not working properly?

I have written following code in php and am using mongo db as database
$projection = array("broadcast_id" => 1,"studentList" => 1);
$query = array('broadcast_id'=> $broadcast_id);
$count = $this->collection->find($query)->count();
$cursor = $this->collection->find($query,$projection);
$result = array();
foreach($cursor as $row)
{
$idstring = trim($row["studentList"]);
$idstring = preg_replace('/\.$/', '', $idstring);
$idarray = explode('|', $idstring);
foreach($idarray as $studentId)
{
$this->StudentCollection = $this->db->studentTbl;
$StudentCursor= $this->StudentCollection->find(array("student_id" => $studentId));
if($StudentCursor->count() > 0)
{
foreach ($StudentCursor as $k => $srow) {
array_push($result, $srow);
}
}
else
{
array_push($result, array("datanotfound"=>1));
}
}
}
return json_encode($result);
After fetching "studentList" from broadcastTbl table and $idstring has "5042|5043|5044" values which are student ids of studentTbl. Now I am trying to fetch corresponding students details by splitting them one by one on the basis of "|". After that I am trying to push them in array $result.
It always displays $StudentCursor->count() as "1" and never enter in else block even if find() query fails to find record and then it displays output as [] i.e it always stay in if statement !!!
Please help me in tracking out what is wrong in the code and writting it efficiently!!!

html php echo on div

here i have a simple function but this show me data fom sql only in 1 div i want to show [ on div 1 show 1 data, in other div show 2 data, etc etc]...
function load_post($added_by)
{
global $Connection;
$SQL_3 = mysqli_query($Connection, "SELECT * FROM posts WHERE added_by='$added_by'");
$NumPosts = mysqli_num_rows($SQL_3);
$out['num_posts'] = $NumPosts;
while($Fetch_3 = mysqli_fetch_array($SQL_3))
{
$out['id'] = $Fetch_3['id'];
$out['text'] = $Fetch_3['text'];
$out['added_by'] = $Fetch_3['added_by'];
$out['mp4'] = $Fetch_3['mp4'];
$out['likes'] = $Fetch_3['likes'];
$out['youtube'] = $Fetch_3['youtube'];
$out['image'] = $Fetch_3['image'];
$out['date_added'] = $Fetch_3['date_added'];
return $out;
}
}
index.php.
$posts = load_post('gentritabazi');
<div class="settings_forms_content">
<?php echo $posts['text']; ?>
</div>
return finish immediately your function so only one iteration is done. You need to save your results in array and then after loop return that array, sth like this:
$out = array();
while($Fetch_3 = mysqli_fetch_array($SQL_3))
{
$out[] = $Fetch_3;
}
return $out;
and display:
$posts = load_post('gentritabazi');
foreach ($posts as $post) {
echo '<div class="settings_forms_content">';
echo $post['text'];
echo '</div>';
}
Lots to amend, so I commented the code rather than write an essay
function load_post($con, $added_by)
{
// dont use globals, use parameters
//global $Connection;
// select only what you want to see not `*`
$SQL_3 = mysqli_query($con, "SELECT id, text, added_by, mp4,
likes, youtube, image, data_added
FROM posts
WHERE added_by='$added_by'");
// not needed
//$NumPosts = mysqli_num_rows($SQL_3);
//$out['num_posts'] = $NumPosts;
while($Fetch_3 = mysqli_fetch_array($SQL_3))
{
/*
* THsi code would overwrite the last iteration of the while loop
$out['id'] = $Fetch_3['id'];
$out['text'] = $Fetch_3['text'];
$out['added_by'] = $Fetch_3['added_by'];
$out['mp4'] = $Fetch_3['mp4'];
$out['likes'] = $Fetch_3['likes'];
$out['youtube'] = $Fetch_3['youtube'];
$out['image'] = $Fetch_3['image'];
$out['date_added'] = $Fetch_3['date_added'];
*/
// now as you SELECT only what you want yo can simply do
$out[] = $Fetch_3;
//return $out; instantly terminates the function
}
return $out; // return the array
}
Now call your function
// pass the connection as a parameter
$posts = load_post($Connection, 'gentritabazi');
// if you want to know how many results were returned
$result_count = count($posts);
// process the returned array
foreach ( $posts as $post ) {
echo '<div class="settings_forms_content">';
echo $post['text'];
echo '</div>';
}
Your script is at risk of SQL Injection Attack
Have a look at what happened to Little Bobby Tables Even
if you are escaping inputs, its not safe!
Use prepared statement and parameterized statements
$posts = load_post('gentritabazi');
foreach ($posts ['text'] as $postText){
echo "<div class='settings_forms_content'>$postText</div>";
}
first line calls your function which returns the array $posts
this array looks like:
$posts = array(
"id" => array of ids
"text" => array of texts
...
);
if you want to access the third text it would be like this:
$posts ['text'][3]
the foreach iterates to your $post array with index "text" -> which is also an array
every value in this array, $post['text'] will be referenced with $postText -> that means:
$post['text'][1] = $postText (first time looping through foreach-loop)
$post['text'][2] = $postText (secondtime looping through foreach-loop)
..
if you are familiar with loops, a foreach is just the short version for
for(var $i=0;$i<length($posts['text'];$i++){
echo "<div class='settings_forms_content'>$posts['text'][i]</div>";
}

Pushing two values from the database to one array

On line 6 I am pushing a value from the database to the array called $products. I would now like to give another value from the database ($row->image) to the same array which matches with $row->name.
Maybe it could make sense to use a two dimensional array but I don't know how to do this in this case.
$products = array();
foreach($_POST['selected_checkboxes'] as $value) {
if($result = $db->query("SELECT * FROM produkte WHERE $value = 1")){
while($row = $result->fetch_object()) {
if (!in_array($row->name, $products)) {
array_push($products, $row->name);
}
}
}
else {
array_push($products, 'error');
}
}
The result should show me the name and the image of both values which belong together.
You could do this, assuming you already have your $row->name and $row->image matching logic sorted:
if (!in_array($row->name, $products)) {
array_push( $products, array('name'=>$row->name, 'image'=>$row->image) );
}
You can try it like this:
$products = array();
foreach ( $_POST['selected_checkboxes'] as $value ) {
if ( $result = $db->query( "SELECT * FROM produkte WHERE $value = 1" ) ) {
while ( $row = $result->fetch_object() ) {
// if your name is unique you can do it like this,
// if not just take $row->id as index
if( isset( $products[$row->name] ) ) continue;
$products[$row->name] = array( "name" => $row->name, "image" => $row->image );
}
} else {
array_push( $products, 'error' );
}
}
// if you want to have plain digits as index you can get a reindexed array
$products = array_values( $products );
then you will get an array like that:
array(//$products
array(
"name" => "productname",
"image" => "productimage"
)
);
I think you can achieve that if you use a stdClass object.
$std = new stdClass();
$std->name = $row->name;
$std->image = $row->image;
array_push($products, $std);
Or you can change your sql query to
SELECT name, image FROM produkte WHERE $value = 1
and
array_push($products, $row);

How can I don't use global variables in this page?

on php document, I made this function.
function getPrices($url) {
global $priceList; // declare global . point of this.
$src = file_get_contents_curl($url);
$dom = new DOMDocument();
$selector = new DOMXPath($dom);
$results = $selector->query('//table/tr/td/span');
foreach($results as $node) {
array_push($priceList, $node->nodeValue);
}
}
and bottom of page, I called it several.
$priceList = array();
getPrices("http://finance.naver.com/item/sise_day.nhn?code=005930");
getPrices("http://finance.naver.com/item/sise_day.nhn?code=005930&page=2");
getPrices("http://finance.naver.com/item/sise_day.nhn?code=005930&page=3");
and display it.
echo $priceList[1];
echo $priceList[2];
echo $priceList[3];
The problem is I'm using CMS kinds of Joomla, Wordpress, and they do not support using global variable So I don't know how to I make this without using global. How can I make it? I need many pages to scrapping, so I'm very afraid. if I scrap just one page,
return in function,
and
$priceList = getPrices("http://finance.naver.com/item/sise_day.nhn?code=$code");
But I don't know many scrapping case. Please help me...
Generally speaking, you shouldn't be using global variables anyways. It's bad practice. Here is one way you can restructure it:
function getPrices($url) {
// this is just a local scoped temp var
$priceList = array();
$src = file_get_contents_curl($url);
$dom = new DOMDocument();
$selector = new DOMXPath($dom);
$results = $selector->query('//table/tr/td/span');
foreach($results as $node) {
array_push($priceList, $node->nodeValue);
}
// return the price list
return $priceList;
}
// here is your real price list
$priceList = array();
// array of urls
$urls = array(
"http://finance.naver.com/item/sise_day.nhn?code=005930",
"http://finance.naver.com/item/sise_day.nhn?code=005930&page=2",
"http://finance.naver.com/item/sise_day.nhn?code=005930&page=3"
// etc..
);
// loop through the urls and assign the results to the price list
foreach ($urls as $url) {
$priceList[] = getPrices($url);
}
Now you have $priceList as an array to do whatever with. Or, if you are looking to immediately output.. you can just skip putting it into $priceList and do your output in the loop above
You could return the partial results from the function and merge them into the complete results array.
<?php
$result = [];
$result = array_merge($result, getSomeValues());
$result = array_merge($result, getSomeValues());
$result = array_merge($result, getSomeValues());
var_export($result);
function getSomeValues() {
static $i = 0;
// returning a partial result of three elements
return [ $i++, $i++, $i++ ];
}
prints
array (
0 => 0,
1 => 1,
2 => 2,
3 => 3,
4 => 4,
5 => 5,
6 => 6,
7 => 7,
8 => 8,
)
You could store the partial results as elements of an array of results.
This way you'd keep some of the information of "what" produced the result.
(You could even use the url as array index)
<?php
$result = [];
$result[] = getSomeValues();
$result[] = getSomeValues();
$result[] = getSomeValues();
// now $result is an array of arrays of (some scalar value)
// so your iteration has to be changed
foreach( $results as $presult ) {
foreach( $presult as $element ) {
..do something with $element
}
}
// or you can "hide" the nesting with
$it = new RecursiveIteratorIterator(new RecursiveArrayIterator($result));
foreach($it as $e ) {
echo $e, ', ';
} // see http://docs.php.net/spl
function getSomeValues() {
static $i = 0;
return [ $i++, $i++, $i++ ];
}
The RecursiveIteratorIterator/foreach part prints 0, 1, 2, 3, 4, 5, 6, 7, 8,

Categories