I'm trying to parse the most recent 3 news articles in an RSS feed. After that, it should create a "preview" of the description, and then display the title and the preview. I got it to display the first article 3 times...
<?php
$doc = new DOMDocument();
$doc->load('http://info.arkmediainc.com/CMS/UI/Modules/BizBlogger/rss.aspx?tabid=575593&moduleid=1167800&maxcount=25&t=16c4c7582db87da06664437e98a74210');
$arrFeeds = array();
foreach ($doc->getElementsByTagName('item') as $node) {
$itemRSS = array (
'title' => $node->getElementsByTagName('title')->item(0)->nodeValue,
'link' => $node->getElementsByTagName('link')->item(0)->nodeValue,
'description' => $node->getElementsByTagName('description')->item(0)->nodeValue,
'pubDate' => $node->getElementsByTagName('pubDate')->item(0)->nodeValue
);
array_push($arrFeeds, $itemRSS);
}
$itemRSS = array_slice($itemRSS, 0, 3); // This cuts it down to 3 articles.
for ($i = 0; $i < 3; $i++)
{
$title = $itemRSS['title'];
$description = substr($itemRSS['description'],0,100);
echo("<h2>".$title."</h2>");
echo("<br />".$description."<br />");
}
?>
I also got it to "work" (show the first 3) by using a foreach loop...
/*
foreach($itemRSS as $ira)
{
$title = $itemRSS['title'];
$description = substr($itemRSS['description'],0,100);
echo("<h2>".$title."</h2>");
echo("<br />".$description."<br />");
}
*/
It's commented out because it makes less sense to me.
Please help! Thanks!
You have pushed the rss items into the $arrFeeds and now you can access these by the index, e.g. $arrFeeds[0] would be the first rss item.
for ($i = 0; $i < 3; $i++)
{
$title = $arrFeeds[$i]['title'];
$description = substr($arrFeeds[$i]['description'],0,100);
echo("<h2>".$title."</h2>");
echo("<br />".$description."<br />");
}
But the following is better: with foreach:
$theFirstThreeArticles = array_slice($arrFeeds, 0, 3); // This cuts it down to 3 articles.
foreach($theFirstThreeArticles as $ira)
{
$title = $ira['title'];
$description = substr($ira['description'],0,100);
echo("<h2>".$title."</h2>");
echo("<br />".$description."<br />");
}
When you use foreach, there are there are two (in your case, but there can be 3) possible "parameters" that it accepts. An array to traverse and a variable to store each element. This example:
$numbers = array('one', 'two');
foreach($numbers as $number) {
echo "\nNew Iteration\n";
var_dump($numbers);
var_dump($number);
}
Will output:
New Iteration
array(2) {
[0] => string(3) "one"
[1] => string(3) "two"
}
string(3) "one"
New Iteration
array(2) {
[0] => string(3) "one"
[1] => string(3) "two"
}
string(3) "two"
The iterator never modifies the array. It just sets $number to be the value of each element in the array until there are no more elements. The same principle applies to a for loop. The code below will produce the same as above.
$numbers = array('one', 'two');
for($i = 0; $i < count($numbers); $i++) {
echo "\nNew Iteration\n";
var_dump($numbers);
var_dump($numbers[$i]);
}
The same applies when you use multidimensional arrays. Whether you choose for or foreach, you have to access each element in the array. So your code will look something like this:
foreach($rssItems as $rssItem)
{
$title = $rssItem['title'];
$description = substr($rssItem['description'],0,100);
echo("<h2>".$title."</h2>");
echo("<br />".$description."<br />");
}
I chose to use foreach because I find it's much easier to let PHP handle the iteration. Plus, the foreach line reads properly in English. For each item in $rssItems alias it as $rssItem. Notice the difference between the plural and the singular. The foreach runs its block for each item in $rssItems and for each iteration the variable $rssItem will contain the current value in $rssItems that the loop is on.
Want more of a reason to use foreach? If you need to work with the key too, foreach will give you both the key and value of every element of the hash (array).
$words = array('hola' => 'hello', 'adios' => 'goodbye', 'gracias' => 'thank you');
foreach($words as $spanishWord => $englishTranslation) {
echo $spanishWord . " in English is " . $englishTranslation . "\n";
}
Foreach also allows you with SPL to write classes that extend or implement an iterator. Classes that contain collections, can function as a class but can be iterated over. For example:
class PhotoAlbum implements IteratorAggregate {
private $pictures = array();
public function __construct($pictures) {
$this->pictures = $pictures;
}
public function addPicture($picture) {
$this->pictures[] = $picture;
}
public function share($friend) {
// etc..
}
public function getIterator() {
return new ArrayIterator($this->pictures);
}
}
$album = new PhotoAlbum($picturesArrayFromDB);
foreach($album as $picture) {
echo $picture;
}
Related
I'm trying to add the dynamically generated variables $title and $price to the array $list.
This works to a certain degree. The code creates an array with the keys where they have a title and price value.
The price value is correct and different for each key. However, it seems that only the first title result is added, creating the following array (same title untill key 30)
[0]=> array(2) { ["title"]=> string(57) "Gibson Les Paul ** Nr.1 Gibson dealer ** 18 gitaarwinkels" ["price"]=> string(25) " € 300,00 " } [1]=> array(2) { ["title"]=> string(57) "Gibson Les Paul ** Nr.1 Gibson dealer ** 18 gitaarwinkels" ["price"]=> string(25) " € 100,00 " }
Looking at the code I think it is because the first foreach loop is only executing the second one.
I know the correct values for $title are there, because when I isolate the title foreach loop like this:
foreach ($titlehit as $titles) {
$title = $titles->nodeValue;
echo "$title";
}
30 different $title result are displayed
$url = "https://url.com";
$html = new DOMDocument();
#$html->loadHtmlFile($url);
$xpath = new DOMXPath($html);
$titlehit = $xpath->query("//span[#class='mp-listing-title']");
$pricehit = $xpath->query("//span[#class='price-new']");
$list = array();
$i = 0;
foreach ($titlehit as $titles) {
foreach ($pricehit as $prices) {
if ($i >=5 && $i <=35) {
$title = $titles->nodeValue;
$price = $prices->nodeValue;
$list[] = array(
'title' => $title,
'price' => $price
);
}
$i++;
}
}
How can I get the array $list to hold both the correct title and price values? Thanks for your help.
Assuming that for each title, there is one price i.e there is a 1:1 title-to-price ratio in the corresponding arrays, you will only need 1 loop.
$list = array();
$i = 0; // initialize
// Assuming $titlehit AND $pricehit have the same number of elements
foreach ($titlehit as $titles) {
// Assuming $pricehit is a simple array. If it is an associative array, we need to use the corresponding key as the index instead of $i. We'll get to this once you can confirm the input.
$prices = $pricehit[$i];
// Not entirely sure why you need this condition.
if ($i >=5 && $i <=35) {
$title = $titles->nodeValue;
$price = $prices->nodeValue;
$list[] = array(
'title' => $title,
'price' => $price
);
}
$i++;
}
Not exactly enough code here to know for sure but it looks like you need to reset your iterator $i with each iteration of your foreach loop:
$list = array();
foreach ($titlehit as $titles) {
$i = 0;
foreach ($pricehit as $prices) {
if ($i >=5 && $i <=35) {
$title = $titles->nodeValue;
$price = $prices->nodeValue;
$list[] = array(
'title' => $title,
'price' => $price
);
}
$i++;
}
}
I have an array like this
Array
(
[0] => 123_dr_for_ma_on_2352015_2nd Shift_(08-29-2015_11-31).pdf
[1] => 123_dr_for_ma_on_2352015_2nd Shift_(08-29-2015_11-30).pdf
[2] => 123_bms_for__on__(10-06-2015_18-36).pdf
)
I want to convert this into multidimensional array based on its value such
as
Array
(
[dr] => Array
(
[0] => 123_dr_for_ma_on_2352015_2nd Shift_(08-29-2015_11-31).pdf
[1] => 123_dr_for_ma_on_2352015_2nd Shift_(08-29-2015_11-30).pdf
)
[bms] => Array
(
[0] => 123_bms_for__on__(10-06-2015_18-36).pdf
)
)
based on name after first underscore (bms,dr) like....... Please help me to achieve this
I would do the following:
$newArray = array();
foreach ($array as $key => $value) {
$parts = explode('_', $value);
$newArray[$parts[1]][] = $value;
}
print_r($newArray);
To solve this without a loop, it would be smart to use a function along with built in Array Filter function.
Here's another possible solution - which seems a little cooler I suppose;
<?php
// ####################
// GLOBAL VARIABLES DEFINITION
// ####################
// Store Pattern Here = Used to Define Array at the end
global $Array_IDs;
$Array_IDs = array();
// Store Variables With Header Pattern (ID) in this area
global $Array_Values;
$Array_Values = array();
// ####################
// FUNCTION DEFINITION
// ####################
// FUNCTION TO SPLIT ARRAY
function Get_ID($variable){
// ACCESS GLOBALS
global $Array_IDs;
global $Array_Values;
// GET CURRENT VARIBALE - EXPLODE TO EXTRACT PATTERN AS ID
$Temp_Parts = explode("_", $variable);
// CHECK IF IDENTIFIER IS ALREADY FOUND (STORED IN ARRAY_ID)
if (in_array($Temp_Parts[1], $Array_IDs)){
// ID ALREADY HAS SUB-ARRAY CREATED
// JUST APPEND VARIABLE
$Array_Values[$Temp_Parts[1]][] = $variable;
}else{
// ADD ID TO Array_IDs
$Array_IDs[] = $Temp_Parts[1];
// Create New ARRAY with HEADER AS PATTERN - ID
$Array_Values[$Temp_Parts[1]][] = $variable;
}
}
// ####################
// CODE STARTS HERE == ONLY THREE LINES ;)
// ####################
$Start_Array = array('123_dr_for_ma_on_2352015_2nd Shift_(08-29-2015_11-31).pdf','123_dr_for_ma_on_2352015_2nd Shift_(08-29-2015_11-30).pdf','123_bms_for__on__(10-06-2015_18-36).pdf');
array_filter($Start_Array,"Get_ID");
print_r($Array_Values);
?>
Give it a try and let me know how it goes, the output is as requested ;)
You can use array_reduce function and regex matching for elegant & lesser code.
$array = array(
'0'=>'123_dr_for_ma_on_2352015_2nd Shift_(08-29-2015_11-31).pdf',
'1'=>'123_dr_for_ma_on_2352015_2nd Shift_(08-29-2015_11-30).pdf',
'2'=>'123_bms_for__on__(10-06-2015_18-36).pdf'
);
$result = array_reduce($array, function($prod, $current){
preg_match('/(?<=^123_)\w+(?=_for\w+)/',$current,$match);
$prod[$match[0]][] = $current;
return $prod;
}, []);
Will produce the following result.
array(2) {
[0]=>
string(57) "123_dr_for_ma_on_2352015_2nd Shift_(08-29-2015_11-31).pdf"
[1]=>
string(57) "123_dr_for_ma_on_2352015_2nd Shift_(08-29-2015_11-30).pdf"
}
array(1) {
[0]=>
string(39) "123_bms_for__on__(10-06-2015_18-36).pdf"
}
Using square bracket require PHP 5.4 above, you can replace with array() instead for lower version of PHP.
please find below code as per your requirement.
<?php
$array = array(
'0'=>'123_dr_for_ma_on_2352015_2nd Shift_(08-29-2015_11-31).pdf',
'1'=>'123_dr_for_ma_on_2352015_2nd Shift_(08-29-2015_11-30).pdf',
'2'=>'123_bms_for__on__(10-06-2015_18-36).pdf'
);
$dr_array = array();
$bms_array = array();
foreach($array as $val){
$str_explode = explode("_",$val);
if($str_explode[1]=="dr"){
$dr_array[] = $val;
}
else if($str_explode[1]=="bms"){
$bms_array[] = $val;
}
}
var_dump($dr_array);
var_dump($bms_array);
?>
Output :
array(2) {
[0]=>
string(57) "123_dr_for_ma_on_2352015_2nd Shift_(08-29-2015_11-31).pdf"
[1]=>
string(57) "123_dr_for_ma_on_2352015_2nd Shift_(08-29-2015_11-30).pdf"
}
array(1) {
[0]=>
string(39) "123_bms_for__on__(10-06-2015_18-36).pdf"
}
Thanks.
$basicArray = array(); //It Stores All The Elements
$firstArray = array(); //It will store array elements of first type
$secondArray = array(); //It will store array elements of second type
for($i = 0; $i < count($basicArray); $i++)
{
$elementArray = explode("_", $basicArray[i]);
if($elementArray[1] == "dr")
array_push($firstArray, $basicArray[i]);
else if($elementArray[1] == "bms")
array_push($secondArray, $basicArray[i]);
}
$finalArray = array();
array_push($finalArray, $firstArray, $secondArray);
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,
Say, we have an array: array(1,2,3,4,...)
And I want to convert it to:
array(
1=>array(
2=>array(
3=>array(
4=>array()
)
)
)
)
Can anybody help?
Thanks
EDIT It would be good to have the solution with iterations.
$x = count($array) - 1;
$temp = array();
for($i = $x; $i >= 0; $i--)
{
$temp = array($array[$i] => $temp);
}
You can simply make a recursive function :
<?php
function nestArray($myArray)
{
if (empty($myArray))
{
return array();
}
$firstValue = array_shift($myArray);
return array($firstValue => nestArray($myArray));
}
?>
Well, try something like this:
$in = array(1,2,3,4); // Array with incoming params
$res = array(); // Array where we will write result
$t = &$res; // Link to first level
foreach ($in as $k) { // Walk through source array
if (empty($t[$k])) { // Check if current level has required key
$t[$k] = array(); // If does not, create empty array there
$t = &$t[$k]; // And link to it now. So each time it is link to deepest level.
}
}
unset($t); // Drop link to last (most deep) level
var_dump($res);
die();
Output:
array(1) {
[1]=> array(1) {
[2]=> array(1) {
[3]=> array(1) {
[4]=> array(0) {
}
}
}
}
}
I think the syntax for the multidimensional array you want to create would look like the following.
$array = array(
'array1' => array('value' => 'another_value'),
'array2' => array('something', 'something else'),
'array3' => array('value', 'value')
);
Is this what you're looking for?
You can also use this array library to do that in just one line:
$array = Arr::setNestedElement([], '1.2.3.4', 'value');
For a project I'm working on, I have a base URI with placeholders and I want to generate all the possible combinations from an array of possible values for each placeholder using PHP.
More concretely:
<?php
$uri = "foo/bar?foo=%foo%&bar=%bar%";
$placeholders = array(
'%foo%' => array('a', 'b'),
'%bar%' => array('c', 'd'),
// ...
);
I'd like ending up having the following array:
array(4) {
[0]=>
string(23) "foo/bar?foo=a&bar=c"
[1]=>
string(23) "foo/bar?foo=a&bar=d"
[2]=>
string(19) "foo/bar?foo=b&bar=c"
[3]=>
string(19) "foo/bar?foo=b&bar=d"
}
Not to mention I should be able to add more placeholders to generate more computed uris, of course, so the solution should work recursively.
I might be overtired these days, but I'm getting stuck at achieving this simply, and I'm sure there's a simple way, perhaps even with builtin PHP functions…
Hints? Any help much appreciated.
<?php
function rec($values,$keys,$index,$str,&$result)
{
if($index<count($values))
foreach($values[$index] as $val)
rec($values,$keys,$index+1,$str.substr($keys[$index],1,strlen($keys[$index])-2)."=".$val."&",$result);
else
$result[count($result)] = $str;
}
// Now for test
$placeholders = array(
'%foo%' => array('a', 'b'),
'%bar%' => array('c', 'd' , 'h'),
);
$xvalues = array_values($placeholders) ;
$xkeys = array_keys($placeholders) ;
$result = array();
rec($xvalues,$xkeys,0,"",$result); // calling the recursive function
print_r($result);
// the result will be:
Array (
[0] => foo=a&bar=c&
[1] => foo=a&bar=d&
[2] => foo=a&bar=h&
[3] => foo=b&bar=c&
[4] => foo=b&bar=d&
[5] => foo=b&bar=h&
)
?>
It handles unlimited count of placeholders & unlimited count of values
$uri= "foo/bar?foo=%foo%&bar=%bar%&baz=%baz%";
$placeholders = array(
'%foo%' => array('a', 'b'),
'%bar%' => array('c', 'd', 'e'),
'%baz%' => array('f', 'g')
);
//adds a level of depth in the combinations for each new array of values
function expandCombinations($combinations, $values)
{
$results = array();
$i=0;
//combine each existing combination with all the new values
foreach($combinations as $combination) {
foreach($values as $value) {
$results[$i] = is_array($combination) ? $combination : array($combination);
$results[$i][] = $value;
$i++;
}
}
return $results;
}
//generate the combinations
$patterns = array();
foreach($placeholders as $pattern => $values)
{
$patterns[] = $pattern;
$combinations = isset($combinations) ? expandCombinations($combinations, $values) : $values;
}
//generate the uris for each combination
foreach($combinations as $combination)
{
echo str_replace($patterns, $combination, $uri),"\n";
}
The idea here is to list in an array all the possible combinations for the replacements. The function expandCombinations just adds one level of depth in the combinations for each new pattern to replace with no recursion (we know how PHP loves recursion). This should allow for a decent number of patterns to replace without recursing at an insane depth.
A recursive solution:
function enumerate($uri, $placeholders){
$insts = array();
if (!empty($placeholders)){
$key = array_keys($placeholders)[0];
$values = array_pop($placeholders);
foreach($values => $value){
$inst = str_replace($uri, $key, $value);
$insts = array_merge($insts, (array)enumerate($inst, $placeholders));
}
return $insts;
} else {
return $uri;
}
}
Each call to the function pops one placeholder off the array and loops through its potential values enumerating through all the remaining placeholder values for each one. The complexity is O(k^n) where k is the average number of replacements for each placeholder and n is the number of placeholders.
My PHP is a little rusty; let me know if I got any of the syntax wrong.
foreach($placeholders['%foo%'] as $foo){
foreach($placeholders['%bar%'] as $bar){
$container[] = str_replace(array('%foo%','%bar%'),array($foo,$bar),$uri);
}
}
This work, but it's not so elegant because of the need to get rid of the placeholder array keys :
<?php
/*
* borrowed from http://www.theserverpages.com/php/manual/en/ref.array.php
* author: skopek at mediatac dot com
*/
function array_cartesian_product($arrays) {
//returned array...
$cartesic = array();
//calculate expected size of cartesian array...
$size = sizeof($arrays) > 0 ? 1 : 0;
foreach ($arrays as $array) {
$size *= sizeof($array);
}
for ($i = 0; $i < $size; $i++) {
$cartesic[$i] = array();
for ($j = 0; $j < sizeof($arrays); $j++) {
$current = current($arrays[$j]);
array_push($cartesic[$i], $current);
}
//set cursor on next element in the arrays, beginning with the last array
for ($j = sizeof($arrays) - 1; $j >= 0; $j--) {
//if next returns true, then break
if (next($arrays[$j])) {
break;
} else { //if next returns false, then reset and go on with previuos array...
reset($arrays[$j]);
}
}
}
return $cartesic;
}
$uri = "foo/bar?foo=%foo%&bar=%bar%";
$placeholders = array(
0 => array('a', 'b'), // '%foo%'
1 => array('c', 'd'), // '%bar%'
);
//example
header("Content-type: text/plain");
$prod = array_cartesian_product($placeholders);
$result = array();
foreach ($prod as $vals) {
$temp = str_replace('%foo%', $vals[0], $uri);
$temp = str_replace('%bar%', $vals[1], $temp);
array_push($result, $temp);
}
print_r($result);
?>