html being processed in string_replace as variable - php

I have a html <h1 class="title">[VALUE]</h1> where [VALUE] gets replaced with some data when the template is processed.
I would like to used the data that replaces [VALUE] in a php variable.
Something like this,
$my_var = '[VALUE]';
but the above don't work.
function getHTML($articleid, $fieldid, $category = false, $write=false)
{
global $globalreturn;
//$str = fieldattach::getInput($articleid, $fieldid, $category);
$html ='';
$valor = fieldattach::getValue( $articleid, $fieldid , $category );
$title = fieldattach::getName( $articleid, $fieldid , $category );
$published = plgfieldsattachment_input::getPublished( $fieldid );
if(!empty($valor) && $published)
{
$html = plgfieldsattachment_input::getTemplate($fieldid);
if(fieldattach::getShowTitle( $fieldid )) $html = str_replace("[TITLE]", $title, $html);
else
$html = str_replace("[TITLE]", "", $html);
$html = str_replace("[VALUE]", $valor, $html);
$html = str_replace("[FIELD_ID]", $fieldid, $html);
}
//WRITE THE RESULT
if($write)
{
echo $html;
}else{
$globalreturn = $html;
return $html;
}
}
function getTemplate($fieldsids, $file="input", $valor)
{
global $globalreturn;
echo $valor;
$templateDir = dirname(__FILE__).'/tmpl/'.$file.'.tpl.php';
$html = file_get_contents ($templateDir);
$app = JFactory::getApplication();
$templateDir = JPATH_BASE . '/templates/' . $app->getTemplate().'/html/com_fieldsattach/fields/'.$file.'.tpl.php';
if(file_exists($templateDir))
{
$html = file_get_contents ($templateDir);
}
$app = JFactory::getApplication();
$templateDir = JPATH_BASE . '/templates/' . $app->getTemplate().'/html/com_fieldsattach/fields/'.$fieldsids.'_'.$file.'.tpl.php';
if(file_exists($templateDir))
{
include ($templateDir);
}
//return $html;
}
I am trying to use the $valor form function getHTML(); inside the getTemplate();
As you will see in he code above I already tried to call global $globalreturn and then echo $valor; but it doesn't work.

You can try as follows
I think you want pass variable to another page. So add following code in myfile.php
<h1 class="title"><?php define ( 'myVariable', '[VALUE]' ); ?></h1>
And call using require function in your next page.
<?php
require("myfile.php");
?>

Related

How to replace strings except inside tag attributes in PHP?

Problem
I have a working script to mass replace all occurrences of listed strings:
function replace_content( $text_content ) {
$input = file_get_contents(__DIR__ . "/strings.json");
$data = json_decode($input, true);
$textlist = array();
foreach($data as $item) {
$text_content = str_ireplace( $item['n.name'], "<span class='hello'>" . $item['n.name'] .'</span>', $text_content );
}
return $text_content;
}
add_filter( 'the_content', 'replace_content' );
However, for occurrences inside tag attributes, I don't want them to be replaced. For example, if I have:
<div id="AListedString" foobar="bla n.name='AnotherListedString' bla">
AListedString YetAnotherListedString
</div>
then the desired output is:
<div id="AListedString" foobar="bla n.name='AnotherListedString' bla">
<span class='hello'>AListedString</span>
<span class='hello'>YetAnotherListedString</span>
</div>
So far the script replaces all occurrences of AListedString, AnotherListedString, YetAnotherListedString. How should I do this?
Attempt
I found this question How to replace text except when it's between two tags in PHP?, but when I use this code:
function replace_content( $text_content ) {
$input = file_get_contents(__DIR__ . "/node.json");
$inputclean = removeBOM($input);
$data = json_decode($inputclean, true);
$textlist = array();
foreach($data as $item) {
// $replaceStr = "<span class='beliefnode'>" . $item['n.name'] .'</span>'
$text_content = str_ireplace( $item['n.name'], "<span class='beliefnode'>" . $item['n.name'] .'</span>', $text_content );
$domElem = new DOMDocument();
$domElem->loadXML("<temp_tag>".$text_content."</temp_tag>");
$nodes = $domElem->getElementsByTagName('div');
$index = 0;
while($nodes->item($index)->nodeValue)
{
$nodes->item($index)->nodeValue = str_replace("<span class='beliefnode'>" . $item['n.name'] .'</span>',
$item['n.name'],
$nodes->item($index)->nodeValue);
$index++;
}
echo $domElem->saveHTML();
}
return $text_content;
}
add_filter( 'the_content', 'replace_content' );
It throws a lot of errors that I think it's really not the way to solve this.

How to fix "XML declaration allowed only at the start of the document"

I am trying to generate a sitemap but somehow an extra DIV tag at the initial line of xml. I need to remove this wrong tag DIV from the xml output.
I've tried to gather the logic at first and segregate the generation of the xml side at the bottom.
set header 'text/xml'.
I tried to strip_tags the whole xml string before output, but then, it shows document empty
private function removeImageAndEmbeds ( $content )
{
// remove img tags
$re1='(<img).*?\\/.*?\\/.*?\\/.*?\\/.*?\\/.*?\\/.*?(\\/>)';
if ( $c=preg_replace("/".$re1."/is", "", $content) ) $content = $c;
// remove embedded tags
$re2='(<div).*?(data-oembed-url=)(".*?").*?<\\/div>.*?(<\\/div>)';
if ( $c=preg_replace("/".$re2."/is", "", $content) ) $content = $c;
return $content;
}
public function sitemaps ($tenantName="") {
if ( !empty($tenantName) ) {
$this->db->like( 't.name', str_replace('-', ' ', rawurldecode($tenantName)), 'none' );
$results = $this->db->get($this->TBL . ' t')->result_array();
foreach ( $results as $result ) {
$tenantId = $result['id'];
$tenantNameinURL = formatTenantNameinURL( $result['name'] );
$AllItems = $this->db->get_where($this->DIVIEW . ' di', 'di.account_id = '. $tenantId)->result_array();
$topics = [];
$itemIds = [];
$ddIds = [];
$urls = [];
foreach ( $AllItems as $k => $item ) {
$pieces = explode('_', $item['id']);
if ( $pieces[1] === $this->ITEMTBL ) {
if( !in_array($item['record_id'], $itemIds) ){
$itemIds[] = $item['record_id'];
$content = $this->removeImageAndEmbeds( $item['content'] );
$AllItems[$k]['content'] = $content;
$topics[$k][] = $AllItems[$k];
$urls[$k]['url'] = formatFrontEndURL( $this->current_class_name, $tenantName, 'show', $pieces[0] );
}
} else if ( $pieces[1] === 'dataDefinitions' ) {
if( !in_array($item['record_id'], $ddIds) ){
$ddIds[] = $item['record_id'];
$content = $this->removeImageAndEmbeds( $item['content'] );
$AllItems[$k]['content'] = $content;
$topics[$k][] = $AllItems[$k];
$urls[$k]['url'] = formatFrontEndURL( $this->current_class_name, $tenantName, 'data_definition', $pieces[0] );
}
}
}
$urlset = new SimpleXMLElement('<?xml version="1.0" encoding="UTF-8"?><urlset />');
$urlset->addAttribute('xmlns', 'http://www.sitemaps.org/schemas/sitemap/0.9');
foreach ($topics as $i => $itemsInTopic) {
$url = $urlset->addChild('url');
$url->loc = $urls[$i]['url'];
$pageMap = $url->addChild('PageMap');
$pageMap->addAttribute('xmlns', 'http://www.google.com/schemas/sitemap-pagemap/1.0');
foreach ( $itemsInTopic as $item ) {
$content = $item['content'];
$content = trim( str_replace([" ","\r","\n","\t", "
", "
"], ' ', strip_tags( utf8_decode( $content ) )) );
$dataObject = $pageMap->addChild('DataObject');
$dataObject->addAttribute('type', 'document');
$dataObject->addAttribute('id', $item['record_id']);
$dataObject->Attribute[0]['name'] = 'title';
$dataObject->Attribute[0] = $item['title'];
$dataObject->Attribute[1]['name'] = 'content';
$dataObject->Attribute[1] = $content;
}
}
$xmlContent = $urlset->asXML();
$this->output->set_content_type('text/xml')->set_output( $xmlContent );
}
}
}
here are two errors generated from seochat validator
https://drive.google.com/file/d/1vacmuJL6hnMErzqZ5zZWkkObT74rKOmT/view?usp=sharing
https://drive.google.com/file/d/1y3z85D1WtJIT9GvOC-DeYwS-DtQCAxK5/view?usp=sharing
here is google console error
https://drive.google.com/file/d/1qMvifyjGILqAjJzdWdc90jyymvdUFV5A/view?usp=sharing

How to properly call a function from a different file?

So I have this code here in my main file.
require_once(plugin_dir_path(__FILE__) . 'load_functions.php');
add_shortcode( 'ccss-show-recipes', 'ccss_show_tag_recipes' );
function ccss_show_tag_recipes() {
global $post;
global $wp;
$html = '';
$url = home_url( $wp->request );
$path = parse_url($url, PHP_URL_PATH);
$pathFragments = explode('/', $path);
$currentPage = end($pathFragments);
// $html.= '<p>'.$currentPage.'</p>';
if ($currentPage == 'recipes') {
ccss_load_all_recipes();
} elseif ( in_array( $currentPage ,["cleanse","combine","commence","commit","complete","consolidate"] ) ) {
//load_phases();
} elseif ( in_array( $currentPage ,["basic-marinades","basic-stock-recipes"] ) ) {
// load_recipe_type();
}
return $html;
// Restore original post data.
wp_reset_postdata();
}
and I have function here in load_functions.php
function ccss_load_all_recipes() {
//code here that wont return
$html .= '<p>test</p>'; //--> It wont display this
echo 'test'; //---> This will be displayed
}
The problem when I call ccss_load_all_recipes() it won't return anything, any ideas on what error I made? But when I try an echo statement it returns it
Thanks,
Carl
your function css_load_all_recipes() does not know the variable $html. In order to achieve that you should pass the $html variable into the function and return it again at the end.
// in your main file
$html = ccss_load_all_recipes($html);
// in load_functions.php
function ccss_load_all_recipes($html = '') {
$html .= '<p>test</p>';
return $html;
}
Edit: other possibilities are: declaring $html as a global variable, or passing $html as reference so you don't have to return the altered html back to the main file. But I would advise against both of these options, unless you run into the exact same problem many times within your application.

Remove array from JSON decode

Here's the function I'm using to grab and process a JSON input:
<?php
$json = "http://pastebin.com/raw.php?i=ihAapq30";
$cache_lastfm = 'BLAHBLAHDIR/'.sha1($json).'.json';
if(file_exists($cache_lastfm) && filemtime($cache_lastfm) > time() - 1000){
// if a cache file newer than 1000 seconds exists, use it
$data = json_decode(file_get_contents($cache_lastfm), true);
} else {
$data = json_decode(file_get_contents($json), true);
file_put_contents($cache_lastfm,json_encode($data));
}
$data = $data['recenttracks'];
foreach ($data['track'] as $track) {
$artist = $track['artist']['#text'];
$title = $track['name'];
$url = $track['url'];
echo '<li>', $artist, ' - ', $title, '</li>'; }
?>
It works perfectly.. my question is, how can I remove only the "entry" that has the:
"#attr":{
"nowplaying":"true"
}
... "attribute"? Check the pastebin page to understand what I mean :)
Please try this:
<?php
$data = $data['recenttracks'];
$tracks=$data['track'];
foreach ($tracks as $index=>$track) {
if (isset($track['#attr'])) {
unset($tracks[$index]);
}
}
foreach ($tracks as $track) {
$artist = $track['artist']['#text'];
$title = $track['name'];
$url = $track['url'];
echo '<li>', $artist, ' - ', $title, '</li>';
}
?>

How to add rel="nofollow" to links with preg_replace()

The function below is designed to apply rel="nofollow" attributes to all external links and no internal links unless the path matches a predefined root URL defined as $my_folder below.
So given the variables...
$my_folder = 'http://localhost/mytest/go/';
$blog_url = 'http://localhost/mytest';
And the content...
internal
internal cloaked link
external
The end result, after replacement should be...
internal
internal cloaked link
external
Notice that the first link is not altered, since its an internal link.
The link on the second line is also an internal link, but since it matches our $my_folder string, it gets the nofollow too.
The third link is the easiest, since it does not match the blog_url, its obviously an external link.
However, in the script below, ALL of my links are getting nofollow. How can I fix the script to do what I want?
function save_rseo_nofollow($content) {
$my_folder = $rseo['nofollow_folder'];
$blog_url = get_bloginfo('url');
preg_match_all('~<a.*>~isU',$content["post_content"],$matches);
for ( $i = 0; $i <= sizeof($matches[0]); $i++){
if ( !preg_match( '~nofollow~is',$matches[0][$i])
&& (preg_match('~' . $my_folder . '~', $matches[0][$i])
|| !preg_match( '~'.$blog_url.'~',$matches[0][$i]))){
$result = trim($matches[0][$i],">");
$result .= ' rel="nofollow">';
$content["post_content"] = str_replace($matches[0][$i], $result, $content["post_content"]);
}
}
return $content;
}
Here is the DOMDocument solution...
$str = 'internal
internal cloaked link
external
external
external
external
';
$dom = new DOMDocument();
$dom->preserveWhitespace = FALSE;
$dom->loadHTML($str);
$a = $dom->getElementsByTagName('a');
$host = strtok($_SERVER['HTTP_HOST'], ':');
foreach($a as $anchor) {
$href = $anchor->attributes->getNamedItem('href')->nodeValue;
if (preg_match('/^https?:\/\/' . preg_quote($host, '/') . '/', $href)) {
continue;
}
$noFollowRel = 'nofollow';
$oldRelAtt = $anchor->attributes->getNamedItem('rel');
if ($oldRelAtt == NULL) {
$newRel = $noFollowRel;
} else {
$oldRel = $oldRelAtt->nodeValue;
$oldRel = explode(' ', $oldRel);
if (in_array($noFollowRel, $oldRel)) {
continue;
}
$oldRel[] = $noFollowRel;
$newRel = implode($oldRel, ' ');
}
$newRelAtt = $dom->createAttribute('rel');
$noFollowNode = $dom->createTextNode($newRel);
$newRelAtt->appendChild($noFollowNode);
$anchor->appendChild($newRelAtt);
}
var_dump($dom->saveHTML());
Output
string(509) "<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN" "http://www.w3.org/TR/REC-html40/loose.dtd">
<html><body>
internal
internal cloaked link
external
external
external
external
</body></html>
"
Try to make it more readable first, and only afterwards make your if rules more complex:
function save_rseo_nofollow($content) {
$content["post_content"] =
preg_replace_callback('~<(a\s[^>]+)>~isU', "cb2", $content["post_content"]);
return $content;
}
function cb2($match) {
list($original, $tag) = $match; // regex match groups
$my_folder = "/hostgator"; // re-add quirky config here
$blog_url = "http://localhost/";
if (strpos($tag, "nofollow")) {
return $original;
}
elseif (strpos($tag, $blog_url) && (!$my_folder || !strpos($tag, $my_folder))) {
return $original;
}
else {
return "<$tag rel='nofollow'>";
}
}
Gives following output:
[post_content] =>
internal
<a href="http://localhost/mytest/go/hostgator" rel=nofollow>internal cloaked link</a>
<a href="http://cnn.com" rel=nofollow>external</a>
The problem in your original code might have been $rseo which wasn't declared anywhere.
Try this one (PHP 5.3+):
skip selected address
allow manually set rel parameter
and code:
function nofollow($html, $skip = null) {
return preg_replace_callback(
"#(<a[^>]+?)>#is", function ($mach) use ($skip) {
return (
!($skip && strpos($mach[1], $skip) !== false) &&
strpos($mach[1], 'rel=') === false
) ? $mach[1] . ' rel="nofollow">' : $mach[0];
},
$html
);
}
Examples:
echo nofollow('something');
// will be same because it's already contains rel parameter
echo nofollow('something'); // ad
// add rel="nofollow" parameter to anchor
echo nofollow('something', 'localhost');
// skip this link as internall link
Using regular expressions to do this job properly would be quite complicated. It would be easier to use an actual parser, such as the one from the DOM extension. DOM isn't very beginner-friendly, so what you can do is load the HTML with DOM then run the modifications with SimpleXML. They're backed by the same library, so it's easy to use one with the other.
Here's how it can look like:
$my_folder = 'http://localhost/mytest/go/';
$blog_url = 'http://localhost/mytest';
$html = '<html><body>
internal
internal cloaked link
external
</body></html>';
$dom = new DOMDocument;
$dom->loadHTML($html);
$sxe = simplexml_import_dom($dom);
// grab all <a> nodes with an href attribute
foreach ($sxe->xpath('//a[#href]') as $a)
{
if (substr($a['href'], 0, strlen($blog_url)) === $blog_url
&& substr($a['href'], 0, strlen($my_folder)) !== $my_folder)
{
// skip all links that start with the URL in $blog_url, as long as they
// don't start with the URL from $my_folder;
continue;
}
if (empty($a['rel']))
{
$a['rel'] = 'nofollow';
}
else
{
$a['rel'] .= ' nofollow';
}
}
$new_html = $dom->saveHTML();
echo $new_html;
As you can see, it's really short and simple. Depending on your needs, you may want to use preg_match() in place of the strpos() stuff, for example:
// change the regexp to your own rules, here we match everything under
// "http://localhost/mytest/" as long as it's not followed by "go"
if (preg_match('#^http://localhost/mytest/(?!go)#', $a['href']))
{
continue;
}
Note
I missed the last code block in the OP when I first read the question. The code I posted (and basically any solution based on DOM) is better suited at processing a whole page rather than a HTML block. Otherwise, DOM will attempt to "fix" your HTML and may add a <body> tag, a DOCTYPE, etc...
Thanks #alex for your nice solution. But, I was having a problem with Japanese text. I have fixed it as following way. Also, this code can skip multiple domains with the $whiteList array.
public function addRelNoFollow($html, $whiteList = [])
{
$dom = new \DOMDocument();
$dom->preserveWhiteSpace = false;
$dom->loadHTML(mb_convert_encoding($html, 'HTML-ENTITIES', 'UTF-8'));
$a = $dom->getElementsByTagName('a');
/** #var \DOMElement $anchor */
foreach ($a as $anchor) {
$href = $anchor->attributes->getNamedItem('href')->nodeValue;
$domain = parse_url($href, PHP_URL_HOST);
// Skip whiteList domains
if (in_array($domain, $whiteList, true)) {
continue;
}
// Check & get existing rel attribute values
$noFollow = 'nofollow';
$rel = $anchor->attributes->getNamedItem('rel');
if ($rel) {
$values = explode(' ', $rel->nodeValue);
if (in_array($noFollow, $values, true)) {
continue;
}
$values[] = $noFollow;
$newValue = implode($values, ' ');
} else {
$newValue = $noFollow;
}
// Create new rel attribute
$rel = $dom->createAttribute('rel');
$node = $dom->createTextNode($newValue);
$rel->appendChild($node);
$anchor->appendChild($rel);
}
// There is a problem with saveHTML() and saveXML(), both of them do not work correctly in Unix.
// They do not save UTF-8 characters correctly when used in Unix, but they work in Windows.
// So we need to do as follows. #see https://stackoverflow.com/a/20675396/1710782
return $dom->saveHTML($dom->documentElement);
}
<?
$str='internal
internal cloaked link
external';
function test($x){
if (preg_match('#localhost/mytest/(?!go/)#i',$x[0])>0) return $x[0];
return 'rel="nofollow" '.$x[0];
}
echo preg_replace_callback('/href=[\'"][^\'"]+/i', 'test', $str);
?>
Here is the another solution which has whitelist option and add tagret Blank attribute.
And also it check if there already a rel attribute before add a new one.
function Add_Nofollow_Attr($Content, $Whitelist = [], $Add_Target_Blank = true)
{
$Whitelist[] = $_SERVER['HTTP_HOST'];
foreach ($Whitelist as $Key => $Link)
{
$Host = preg_replace('#^https?://#', '', $Link);
$Host = "https?://". preg_quote($Host, '/');
$Whitelist[$Key] = $Host;
}
if(preg_match_all("/<a .*?>/", $Content, $matches, PREG_SET_ORDER))
{
foreach ($matches as $Anchor_Tag)
{
$IS_Rel_Exist = $IS_Follow_Exist = $IS_Target_Blank_Exist = $Is_Valid_Tag = false;
if(preg_match_all("/(\w+)\s*=\s*['|\"](.*?)['|\"]/",$Anchor_Tag[0],$All_matches2))
{
foreach ($All_matches2[1] as $Key => $Attr_Name)
{
if($Attr_Name == 'href')
{
$Is_Valid_Tag = true;
$Url = $All_matches2[2][$Key];
// bypass #.. or internal links like "/"
if(preg_match('/^\s*[#|\/].*/', $Url))
{
continue 2;
}
foreach ($Whitelist as $Link)
{
if (preg_match("#$Link#", $Url)) {
continue 3;
}
}
}
else if($Attr_Name == 'rel')
{
$IS_Rel_Exist = true;
$Rel = $All_matches2[2][$Key];
preg_match("/[n|d]ofollow/", $Rel, $match, PREG_OFFSET_CAPTURE);
if( count($match) > 0 )
{
$IS_Follow_Exist = true;
}
else
{
$New_Rel = 'rel="'. $Rel . ' nofollow"';
}
}
else if($Attr_Name == 'target')
{
$IS_Target_Blank_Exist = true;
}
}
}
$New_Anchor_Tag = $Anchor_Tag;
if(!$IS_Rel_Exist)
{
$New_Anchor_Tag = str_replace(">",' rel="nofollow">',$Anchor_Tag);
}
else if(!$IS_Follow_Exist)
{
$New_Anchor_Tag = preg_replace("/rel=[\"|'].*?[\"|']/",$New_Rel,$Anchor_Tag);
}
if($Add_Target_Blank && !$IS_Target_Blank_Exist)
{
$New_Anchor_Tag = str_replace(">",' target="_blank">',$New_Anchor_Tag);
}
$Content = str_replace($Anchor_Tag,$New_Anchor_Tag,$Content);
}
}
return $Content;
}
To use it:
$Page_Content = 'internal
internal
google
example
stackoverflow';
$Whitelist = ["http://yoursite.com","http://localhost"];
echo Add_Nofollow_Attr($Page_Content,$Whitelist,true);
WordPress decision:
function replace__method($match) {
list($original, $tag) = $match; // regex match groups
$my_folder = "/articles"; // re-add quirky config here
$blog_url = 'https://'.$_SERVER['SERVER_NAME'];
if (strpos($tag, "nofollow")) {
return $original;
}
elseif (strpos($tag, $blog_url) && (!$my_folder || !strpos($tag, $my_folder))) {
return $original;
}
else {
return "<$tag rel='nofollow'>";
}
}
add_filter( 'the_content', 'add_nofollow_to_external_links', 1 );
function add_nofollow_to_external_links( $content ) {
$content = preg_replace_callback('~<(a\s[^>]+)>~isU', "replace__method", $content);
return $content;
}
a good script which allows to add nofollow automatically and to keep the other attributes
function nofollow(string $html, string $baseUrl = null) {
return preg_replace_callback(
'#<a([^>]*)>(.+)</a>#isU', function ($mach) use ($baseUrl) {
list ($a, $attr, $text) = $mach;
if (preg_match('#href=["\']([^"\']*)["\']#', $attr, $url)) {
$url = $url[1];
if (is_null($baseUrl) || !str_starts_with($url, $baseUrl)) {
if (preg_match('#rel=["\']([^"\']*)["\']#', $attr, $rel)) {
$relAttr = $rel[0];
$rel = $rel[1];
}
$rel = 'rel="' . ($rel ? (strpos($rel, 'nofollow') ? $rel : $rel . ' nofollow') : 'nofollow') . '"';
$attr = isset($relAttr) ? str_replace($relAttr, $rel, $attr) : $attr . ' ' . $rel;
$a = '<a ' . $attr . '>' . $text . '</a>';
}
}
return $a;
},
$html
);
}

Categories