I have a php file that generates an xml feed containing a list of all the products of my e-commerce.
For each of the products, the php file is designed to assign a series of tags (price, title, description etc...). One of these tags is the link of the product on my e-commerce.
Example:
<title> smartphone </title>
<category> electronics </category>
<price> 100 </price>
<link> www.mysite.com/smartphone </link>
This is the part of the code (working) used to extract the link of the product (my e-commerce is made with prestashop):
$link = $item->addChild('LINK', $productobj->getLink();
The thing that I need to do, is to dynamically add some string at the end of the link generated for each product.
For example, if the link is:
www.mysite.com/product-name
I need the link to be like this:
www.mysite.com/product-name?parameter1=abc¶meter2=def¶meter3=ghi
And the parameters need to be adapted based on the value of the tag <category>.
Example:
if the product A has the tag <category>electronics</category>
the string to add at the end of its url would be:
?parameter1=electronics¶meter2=def¶meter3=ghi
if the product B has the tag <category>clothes</category>
the string to add at the end of its url would be:
?parameter1=clothes¶meter2=def¶meter3=ghi
Thanks in advance for your precious help.
Good evening.
EDIT:
I report below more detail of the code used to generate the xml file.
<?php
public function addChildWithCDATA($name, $value = NULL) {
$new_child = $this->addChild($name);
if ($new_child !== NULL) {
$node = dom_import_simplexml($new_child);
$no = $node->ownerDocument;
$node->appendChild($no->createCDATASection($value));
}
return $new_child;
}
}
require_once(dirname(__FILE__) . '/config/config.inc.php');
require_once(dirname(__FILE__) . '/init.php');
$config = Configuration::getMultiple(array('PS_LANG_DEFAULT', 'PS_COUNTRY_DEFAULT'));
$defaultLangId = $config['PS_LANG_DEFAULT'];
$defaultCountryId = $config['PS_COUNTRY_DEFAULT'];
Context::getContext()->language = new Language($defaultLangId);
Context::getContext()->link = new Link();
$products = Db::getInstance(_PS_USE_SQL_SLAVE_)->executeS($query);
$counter = 0;
if ($products) {
$itemlist = new SimpleXMLElementExtended('<?xml version="1.0" encoding="UTF-8"?><ITEMLIST></ITEMLIST>');
foreach ($products as $product) {
$item = $itemlist->addChild('ITEM');
$productobj = new Product($product['id_product'], false, $defaultLangId);
$counter++;
$item->addAttribute('ID', $productobj->id);
$item->addAttribute('CITYID', $defcityID);
$item->addAttribute('CATEGORYID', $product['CATEGORYID']);
$title = $item->addChildWithCDATA('TITLE',trim($productobj->name));
$title = $item->addChildWithCDATA('TEXT',strip_tags($productobj->description));
$email = $item->addChild('EMAIL', $defemail);
$link = $item->addChild('LINK', $productobj->getLink());
}
unset($products);
$success &= file_put_contents(_PS_ROOT_DIR_.'/feed.xml', $itemlist->asXML());
echo "DONE";
} else {
echo "NOTHING FOUND";
}
?>
If you are trying to add the category as a URL parameter, you could use:
$link = $item->addChild('LINK', $productobj->getLink() . "?parameter1=" . $product['CATEGORYID']);
I'm trying to scrape pricing data from a few home depot URLs. I'm using simple_html_dom.php which can be found here: https://simplehtmldom.sourceforge.io/
I'm having issues figuring out how to get the individual span class that I need in order to get the data I want.
Here's an image of the inspect element with the various fields I'm trying to access:
https://prnt.sc/qx5ujt
Here's the code I have so far which returns an empty array:
?<php
require 'simple_html_dom.php';
$dom = file_get_html('https://www.homedepot.com/p/Zinsco-20-Amp-1-1-2-in-2-Pole-Replacement-Thick-Circuit-Breaker-UBIZ220/100183119', false);
$answer = array();
if(empty($dom))
{
echo "EMPTY";
exit;
}
$divClass = "";
$dollars = "";
$cents = "";
$i = 0;
foreach($dom->find('price__wrapper') as $divClass)
{
foreach($divClass->find('span[class=price__dollars]') as $dollars) //dollars
{
$answer[$i]['dollars'] = $dollars->plaintext;
}
foreach($divClass->find('span[class=price__cents]') as $cents) //cents
{
$answer[$i]['cents'] = $cents->plaintext;
}
$i++;
}
print_r($answer);
exit;
?>
If the HTML really looks always like in the screenshot, than you can go on the content attribute of the parent span element.
This you can archive like below (untested example).
// Get the parent span element with ID ajaxPrice
$element = $dom->find('span#ajaxPrice',0);
// Check if attribute "content" exists
if(isset($element->content)) {
$price = $element->content; // This is the price as string value
$priceFloat = floatval($price); // This is the price as float value
// Splitting price in dollar and cent
$price = explode('.', $price);
$dollar = $price[0];
$cent = $price[1];
}
So I have this function to convert text URLs to links. What do I need to add to preg_replace, to limit a long URL, currently it displays domain only, I would like to add a 4th attribute to this, that shows limit from full URL, limits the URL, I have no idea how to do this. This function is tested and works very well this is why I want to keep using it, how to I add this extra snippet for 4th attribute.
function autolink($str, $attributes=array()) {
$attrs = '';
foreach ($attributes as $attribute => $value) {
$attrs .= " {$attribute}=\"{$value}\"";
}
$str = ' ' . $str;
$str = preg_replace(
'|([\w\d]*)\s(https?://([\d\w\.-]+\.[\w\.]{2,6})[^\s\]\[\<\>]*/?)|i',
'$1 $3',
$str
);
return $str;
}
Can someone please help me out.
INPUT:
$cont=autolink("https://www.example.com/test.php?ss=a https://www.example.com/2 https://www.exxxxxxxxxxxxxxxxxxaaample.com/3");
Output current:
www.example.com www.example.com www.exxxxxxxxxxxxxxxxxxaaample.com
WANTED output:
www.example.com/test... www.example.com/2 www.exxxxxxxxxxxxx.....
I should be able to limit the URL name to like 40 chars. Anyways the third attribute is not needed and would be modified, not returning the domain, but the real name of URL limited to 40 chars.
I hope it's final: answer is *preg_replace_callback*and this is the best regex, used here, best way to make text URL to HTML link, easy to modify.
function autolink($textOriginal)
{
$textOriginal=" $textOriginal";
$urlPattern = '|([\w]*)\s(https?://([\w.-]+\.[\w.]{2,6})[^\s\]\[\<\>]*/?)|i';
$textNew = preg_replace_callback($urlPattern, "replaceLinkParts", $textOriginal);
return $textNew;
}
function replaceLinkParts($matches)
{
$thefullurl=''.$matches[2].'';
$whatisthis=''.$matches[1].'';
//////////
$myDomainx = parse_url("$thefullurl");
$simpleurl="" . $myDomainx["host"] . "";
$simpleurlp = "" . $myDomainx["path"] . "";
if ($simpleurlp == "/") {
$simpleurlp = "";
}
$newurl="$simpleurl$simpleurlp";
////////////////
$lastpart= "";
$limichars="30";
$limitlast="10";
$calcit=$limichars-$limitlast;
$nmre=strlen($newurl);
if ($nmre > $limichars) {
$lastpart=$nmre - $limitlast;
$lastpart= substr($newurl, $lastpart, $limitlast);
$newurl= substr($newurl, 0, $calcit);
$newurl= ''.$newurl.'...';
}
////////////
$retthis=''.$whatisthis.' <a target="_blank" title="'.$thefullurl.'" rel="nofollow" href="'.$thefullurl.'">'.$newurl.''.$lastpart.'</a>';
return $retthis;
}
Outputs HTML link: www.example.com...ifverylongurl
I have a function which returns all img links of any web page but i want to take the image that represent the news article best . I know that it is a little hard question but every news articles have some main image on top of the article . I need to pick it among all of other images . Facebook and reddit like sites can do that . Do you have any kind of idea ? When members of my website shared a link , there should be a picture for it . I can take all url of images in a web page now i need to find main image . :)
function get_links($url) {
$xml = new DOMDocument();
libxml_use_internal_errors(true);
$html = file_get_contents($url);
if(!$xml->loadHTML($html)) {
$errors="";
foreach (libxml_get_errors() as $error) {
$errors.=$error->message."<br/>";
}
libxml_clear_errors();
print "libxml errors:<br>$errors";
return;
}
// Empty array to hold all links to return
$links = array();
//Loop through each <img> tag in the dom and add it to the link array
foreach ($xml->getElementsByTagName('img') as $link) {
$url = $link->getAttribute('src');
if (!empty($url)) {
$links[] = $link->getAttribute('src');
}
}
//Return the links
return $links;
}
You can improve your existing function, but if you want to preference the existence of the Open Graph data, add this before your getElementsByTagName('img') logic...
$xpath = new DOMXPath( $xml );
if( $xpathNodeList = $xpath->query('//meta[#property="og:image" and #content]') )
{
return array( $xpathNodeList->item(0)->getAttribute('content') );
}
or add it to your array...
// Empty array to hold all links to return
$links = array();
$xpath = new DOMXPath( $xml );
if( $xpathNodeList = $xpath->query('//meta[#property="og:image" and #content]') )
{
$links[] = $xpathNodeList->item(0)->getAttribute('content');
}
This question already has answers here:
Closed 11 years ago.
Possible Duplicate:
Walk array recursively and print the path of the walk
Anyone can help me on this code?
<?php
function buildMenuWalk(&$array, &$depth, $currentDepth = 1)
{
# start new level html
$html = '';
# walk till the depth defined on the config
if($currentDepth > $depth)
{
return null;
}
# loop through all items in this level
foreach($array as $key => &$value)
{
# if not in area map continue
if(!is_numeric($key))
{
continue;
}
# if no <li> has been created yet, open the <ul>
$html .= empty( $html ) ? '<ul class="dropdown">' : '';
#extract the label from this level's array, designated by $labelKey
$label = isset( $value['areaname'] ) ? $value['areaname'] : '';
# open an <li>
$html .= '<li>';
# generate url
$url = '';
if($currentDepth == $depth)
{
$url = ' href="'.
$url .= '"';
}
# construct content inside the <li>
$html .= '<a' . $url .'>' . $label . '</a>';
# run the function again to grab children levels
if(is_array($value))
{
$html .= buildMenuWalk($value, $depth, $currentDepth + 1);
}
# close <li>
$html .= '</li>';
}
# close <ul> if was generated content on this level
$html .= !empty( $html ) ? '</ul>' : '';
return $html;
}
$depth = 2;
$config['content']['map'][1]['areaname'] = 'area_1';
$config['content']['map'][1][1]['areaname'] = 'block_1';
$config['content']['map'][2]['areaname'] = 'area_2';
$config['content']['map'][2][1]['areaname'] = 'block_1';
$config['content']['map'][2][2]['areaname'] = 'bloack_2';
echo buildMenuWalk($config['content']['map'], $depth);
?>
If you check the code above, Im using to display a menu recursively ...
If the script identify the menu reached the depth, will display href="" inside the tag. Inside this href I want add all parent areas on the recursion.
For example:
$config['content']['map'][2]['areaname'] = 'area_2';
$config['content']['map'][2][1]['areaname'] = 'block_1';
$config['content']['map'][2][2]['areaname'] = 'bloack_2';
When script reaches the bloack_2, I need display:
<a href="area_2=2&block_2=2">
Since its a multidimensional array and can grow to like 4-5 dimension, the output href should count all these levels. For example area_2=1&block_10=5&sub_area_1=5§ion_7=8 ...
I probably need some array to store all href path during the recursion, but I cant figure how to do it.
Thanks,
PS: The script will be used to build a dropdown menu. The parent levels don't need to be linked, so print the tag will display the child menu. The last child, will be linked, but need contain all parent params so the results can be filtered.
Link to the code running and returning values:
http://codepad.org/iyrcdfQP
Here is a modification of that same slice of code that makes the href= a little more like what you are describing, although it doesn't really make sense to me.
# generate url
$url = '';
if($currentDepth == $depth) {
$url = " href=".$GLOBALS['area_name']."=".$GLOBALS['area']."&$label=$key";
}
else {
$GLOBALS['area'] = $key;
$GLOBALS['area_name'] = $label;
}
I don't see why one would bother with recursoin and multiple dimensions in a world of 2 dimensions as the menu in a web page is!
I would go for 2 dimensions only, the first dimension is to keep all elements (without any criteria) and the second to keep infos about the element:
Check an example for yourself, you set which element to get the function displays it along with all ancestors and root elements of previous levels (as California is).
<?php
function buildMenuWalk($element,$menuElements)
{
for($i=0;$i<=$element;$i++)
{
//for a new level go to the next line
if(!isset($menuElements[$i]['ancestors']))
{
echo '<br>______________________________________</br>';
echo '<strong>',$menuElements[$i]['label'],'</strong> | ';
}
//if the element is reached display it along with ancestors
if($i==$element)
{
//echo all the ancestores
foreach($menuElements[$element]['ancestors'] as $value)
{
echo $menuElements[$value]['label'],' | ';
}
//display the element itself
echo '<font color=red>',$menuElements[$element]['label'],' | </font>';
}
}
}
//California
$menuElements[0]=Array('url'=>'http://www.California.com','label'=>'California');
$menuElements[1]=Array('url'=>'http://www.San Diego.com','label'=>'San Diego','ancestors'=>Array(0));
$menuElements[2]=Array('url'=>'http://www.San Jose.com','label'=>'San Jose','ancestors'=>Array(0,1));
$menuElements[3]=Array('url'=>'http://www.San Francisco.com','label'=>'San Francisco','ancestors'=>Array(0,1,2));
$menuElements[4]=Array('url'=>'http://www.Fresno.com','label'=>'San Francisco','ancestors'=>Array(0,1,2,3));
$menuElements[5]=Array('url'=>'http://www.Sacramento.com','label'=>'Sacramento','ancestors'=>Array(0,1,2,3,4));
//Wyoming
$menuElements[6]=Array('url'=>'http://www.Wyoming.com','label'=>'Wyoming');
$menuElements[7]=Array('url'=>'http://www.Cheyenne.com','label'=>'Cheyenne','ancestors'=>Array(6));
$menuElements[8]=Array('url'=>'http://www.Casper.com','label'=>'Casper','ancestors'=>Array(6,7));
$menuElements[9]=Array('url'=>'http://www.Laramie.com','label'=>'Laramie','ancestors'=>Array(6,7,8));
$menuElements[10]=Array('url'=>'http://www.Gillette.com','label'=>'Gillette','ancestors'=>Array(6,7,8,9));
$menuElements[11]=Array('url'=>'http://www.Rock Springs.com','label'=>'Rock Springs','ancestors'=>Array(6,7,8,9,10));
echo '<pre>';
buildMenuWalk(9,$menuElements);
?>
Since this function is recursively calling itself, you'll have to refer to a global variable to keep track of the previous tree. So here is the code that'll do what I think you want it to do. All of you have to change is the #generate url section.
# generate url
$url = '';
if($currentDepth == $depth) {
$url = " href=area=" . $GLOBALS['area'] . "&block=$key";
} else {
$GLOBALS['area'] = $key;
}