Ok, I'm using SimpleXML to parse RSS feeds, and as many feeds contain embedded html, I'd like to be able to isolate any image addresses contained in embedded html. Sounds like an easy enough task, but I'm running into an issue with parsing the data from the SimpleXMLElement objects. Here's the relevant code.
for($i = 0; $i < count($articles); $i++) {
foreach($articles[$i] as $feedDeet) {
$str = (string)$feedDeet;
$result = strpos($str, '"');
if($result === false) {
echo 'There are apparently no quotes in this string: '.$str;
}
$explodedString = explode('"', $str);
echo "<br>";
if($explodedString[0] == $str) {
echo 'ExplodedString is equal to str. Apparently, once again, the string contains no quotes.';
}
echo "<hr>";
}
}
In this situation, $articles is an array of SimpleXMLElement objects each representing an RSS article, and containing many child SimpleXMLElement objects representing properties and details of that article. Basically, I'd like to iterate through those properties one by one, cast them as strings, and then explode the strings using any quotes as delimiters (because any image addresses would be contained inside of quotes). I would then parse through the exploded array and search for any strings that appear to be an image address. However, neither explode() nor strpos() is behaving as I would expect it to. To give an example of what I mean, one of the outputs of the above code is as follows:
There are apparently no quotes in this string: <p style="text-align: center;"><img class="alignnone size-full wp-image-243922" alt="gold iPhone Shop Le Monde" src="http://media.idownloadblog.com/wp-content/uploads/2013/08/gold-iPhone-Shop-Le-Monde.jpg" width="593" height="515" /></p> <p>Folks still holding out hope that the gold iPhone rumors aren’t true may want to brace themselves, the speculation has just been confirmed by the Wall Street Journal-owned blog AllThingsD. And given the site’s near perfect (perfect?) track record with predicting future Apple plans, and corroborating evidence, we’d say Apple is indeed going for the gold…(...)<br/>Read the rest of AllThingsD confirms gold iPhone coming</p> <hr /> <p><small> "AllThingsD confirms gold iPhone coming" is an article by iDownloadBlog.com. <br/>Make sure to follow us on Twitter, Facebook, and Google+. </small></p>
ExplodedString is equal to str. Apparently, once again, the string contains no quotes.
Sorry if that was a little hard to read, it's copied verbatim from the output.
As you can see, there are clearly quotes in the string in question, yet, strpos is returning false, meaning that the specified string could not be found, and explode is returning an array with the original string inside, signifying that the specified delimiter could not be found. What is going on here? I've been stumped by this for hours, and I feel like I'm losing my mind.
Thanks!
The mistake you've made here is that your debug output is an HTML page, so the messages you print are being interpreted as HTML by your browser. To see their actual contents, you either need to view the page source, or use <pre> tags to preserve whitespace, and htmlspecialchars() to add a layer of HTML escaping: echo '<pre>' . htmlspecialchars($str) . '</pre>';
If the output in the browser looks like <p style="text-align: center;">, then clearly the input is already escaped with HTML-entities, and probably actually looks like <p style="text-align: center;">. Although that " looks like ", it is not the same string, so strpos() won't find it.
In order to undo this extra layer of escaping, you could run html_entity_decode() on the string before processing it.
Related
I'm trying to redirect to another php page from sql server fetch array with WHILE loop.
All records are fetched well, but i want to add to the table "delete" link to every fetched record.
I tried the code below separatedly and it works just fine.
The problem is because the code is inside PHP tag and i'm confused with all of the ' ' signs.
while compailing the code below i just can't see nothing (without the "delete" line everything is OK):
while ( $record = sqlsrv_fetch_array($rs, SQLSRV_FETCH_NUMERIC) )
{
$o .= '<tr><td><center>'.$record [0].'</center></td><td><center>'.$record [1].'</center></td>
<td><center>'.$record [2].'</center></td><td><center>'.$record [3].'</center></td>
<td><center>'.$record [4].'</center></td><td><center>'.$record [5].'</center></td>
<td><center>'.$record [6].'</center></td><td><center>'.$record [7].'</center></td>
<td>**<a href="JavaScript:if(confirm('delete record?')==true)
{window.location='phpSQLServerDeleteRecord.php?EventID=<?php echo $record[0];';}">delete</a>**
</tr>';
}
$o .= '</tbody></table>';
echo $o;
Thanks a lot for your help!
The use of single-quotes is creating a syntax error:
'</center></td><td>**<a href="JavaScript:if(confirm('delete record?')==true)
{window.location='phpSQLServerDeleteRecord.php?EventID=<?php echo $record[0];';}">delete</a>**
</tr>'
Since the server-side string literal began with a single quote, as soon as the string contains a single-quote then the PHP engine will interpret that as the end of the string, which then results in a couple of syntax errors here as things intended to be part of the string are interpreted as code.
There are a couple of ways to go about this. One quick fix would be to "escape" the single-quotes which are meant to be part of the string rather than a boundary of the string:
'</center></td><td>**<a href="JavaScript:if(confirm(\'delete record?\')==true)
{window.location=\'phpSQLServerDeleteRecord.php?EventID=<?php echo $record[0];\';}">delete</a>**
</tr>'
Of course, there's still the error that now PHP code (the echo statement) is being emitted as part of a string. You can terminate the string boundaries around that and concatenate the value to the string like any other string concatenation:
'</center></td><td>**<a href="JavaScript:if(confirm(\'delete record?\')==true)
{window.location=\'phpSQLServerDeleteRecord.php?EventID=' . $record[0] . '\';}">delete</a>**
</tr>'
(Note that immediately after the reference to $record[0] there are two single-quotes. One to begin the new string literal and then an escaped one to be the first character in that string literal, since the client-side code will need that single-quote character to terminate its string literal. That's probably the root of your confusion in the matter... These server-side strings aren't just HTML, they're also JavaScript which has its own client-side strings.)
You'll also want to URL-encode that value being emitted as part of a query string (even though it should just be a numeric identifier I suspect, it's still good form):
'</center></td><td>**<a href="JavaScript:if(confirm(\'delete record?\')==true)
{window.location=\'phpSQLServerDeleteRecord.php?EventID=' . urlencode($record[0]) . '\';}">delete</a>**
</tr>'
There are a number of other ways to potentially clean this up. Take a look at the PHP documentation on strings, particularly around the "heredoc" syntax. My PHP is to rusty to whip up an example of that, but I suspect it will end up looking a little cleaner in the resulting code. Either way, it's good to get some practice in the differences between the various ways PHP handle string literals.
I will echo the comment from #mario above but give you an example of how to use Heredoc syntax to make large blocs of text much more readable and easy to work with, as you will not need to mess with escaping quotes at all.
while (...)
{
$o .= <<<EOT
<tr>
<td><center>{$record[0]}</center></td>
<td><center>{$record[1]}</center></td>
<td><center>{$record[2]}</center></td>
<td><center>{$record[3]}</center></td>
<td><center>{$record[4]}</center></td>
<td><center>{$record[5]}</center></td>
<td><center>{$record[6]}</center></td>
<td><center>{$record[7]}</center></td>
<td>**<a href="JavaScript:if(confirm('delete record?')==true)
{window.location='phpSQLServerDeleteRecord.php?EventID={$record[0]}}">delete</a>**</td>
</tr>
EOT
}
Now doesn't that look a whole lot nicer?
Note: brackets around PHP variables are optional. I just like them when using Heredoc as I find it makes it easier to see where your variables are.
Read here for more information on Herdoc syntax:
http://php.net/manual/en/language.types.string.php#language.types.string.syntax.heredoc
For future readers, please look to answer by #David as well. He does good job of explaining why the OP was having his problem. I really look at this answer as complementary to that one, giving the reader an example of what might be a good way to go about solving the problem.
I'm building an ExpressionEngine module in PHP.
In ExpressionEngine, one can access parameters passed to the module in a template using:
$my_param = $this->EE->TMPL->fetch_param('my_param');
However, when I fetch a string that way, explode does not work on it:
public function get_tyres()
{
$tyres = $this->EE->TMPL->fetch_param('tyres');
echo($tyres);
// this shows: '205/55R16M+S|205/55R16|205/55R16'
// now I want to split it into single tyres, using the pipe as a delimiter
$tyre_array = explode("|", $tyres);
foreach($tyre_array as $tyre)
{
echo($tyre . '<br>');
}
// the above produces: '205/55R16M+S|205/55R16|205/55R16',
// where I'd expect it to produce:
// 205/55R16M+S
// 205/55R16
// 205/55R16
}
I've tried to specifically cast to a string using $tyres = (string) $this->EE->TMPL->fetch_param('tyres');, with no luck.
I've also tried manually creating and exploding a string:
$tyres = '205/55R16M+S|205/55R16|205/55R16'; which worked, but obviously I need to get the param from the template, not hard code it.
Lastly, I tried using preg_split and a regex, with no luck either:
$tyre_array = preg_split('/\|/', $tyres); which also returned an array with the entire string in it.
What could be at work here? Is this a scope related thing? Is it an encoding-related thing? What to look for next?
Update
Okay, we're getting somewhere. I've added the following to the function:
for($i = 0; $i < strlen($tyres); $i++) {
echo substr($tyres, $i, 1) . ", ";
}
Which returns... {, v, e, r, s, i, o, n, :, t, y, r, e, s, }, and that is in fact the variable passed to PHP in the HTML template:
{exp:my_module:tyres tyres="{version:tyres}"}
<h1>{tyre:name}</h1>
... more irrelevant HTML
{/exp:my_module:tyres}
This means it has something to do with the parsing order of ExpressionEngine. Apparently, the variable {version:tyres} isn't parsed yet. So I pass that variable to the module, it tries to explode it by the pipe character, but the string {version:tyres} does not contain a pipe, meaning it can't be exploded. ExpressionEngine then returns {version:tyres} as a whole, passes it back in to the template and then the variable is parsed as 205/55R16M+S|205/55R16|205/55R16.
I've tested this, and can confirm that exploding by ':' returns the array:
array (size=2)
0 => string '{version' (length=8)
1 => string 'tyres}' (length=6)
I will now look in to ExpressionEngine parse order. If anyone has an idea on how to work around this, I'd be happy to know ;-).
I tested your code, copy and pasting your test string, and it works fine for me. Make sure your pipe ("|") is really the character you think it is, and not, say, some crazy unicode stuff that just looks like a pipe, but is actually Klingon for for 'staff', or something.
Try something like this as a reality check:
echo " the pipe is at " .strpos($tyres,"|"). " and I really hope this it says '12'";
The answer lies in the ExpressionEngine parse order, as outlined here: https://ellislab.com/expressionengine/user-guide/templates/template_engine.html#rendering-stages
Because the template tag {exp:my_module:tyres} used a variable passed to it by a template tag that it was nested in, the variable wasn't parsed yet as the innermost tags are parsed first.
Adding the parameter parse="inward" to the outer template tag makes ExpressionEngine parse that tag first, passing the correct variable to the inner template tag.
See https://ellislab.com/expressionengine/user-guide/templates/plugins.html#changing-parsing-order for more on changing the parsing order.
I'm currently trying out this PHP preg_replace function and I've run into a small problem. I want to replace all the tags with a div with an ID, unique for every div, so I thought I would add it into a for loop. But in some strange way, it only do the first line and gives it an ID of 49, which is the last ID they can get. Here's my code:
$res = mysqli_query($mysqli, "SELECT * FROM song WHERE id = 1");
$row = mysqli_fetch_assoc($res);
mysqli_set_charset("utf8");
$lyric = $row['lyric'];
$lyricHTML = nl2br($lyric);
$lines_arr = preg_split('[<br />]',$lyricHTML);
$lines = count($lines_arr);
for($i = 0; $i < $lines; $i++) {
$string = preg_replace(']<br />]', '</h4><h4 id="no'.$i.'">', $lyricHTML, 1);
echo $i;
}
echo '<h4>';
echo $string;
echo '</h4>';
How it works is that I have a large amount of text in my database, and when I add it into the lyric variable, it's just plain text. But when I nl2br it, it gets after every line, which I use here. I get the number of by using the little "lines_arr" method as you can see, and then basically iterate in a for loop.
The only problem is that it only outputs on the first line and gives that an ID of 49. When I move it outside the for loop and removes the limit, it works and all lines gets an <h4> around them, but then I don't get the unique ID I need.
This is some text I pulled out from the database
Mama called about the paper turns out they wrote about me
Now my broken heart´s the only thing that's broke about me
So many people should have seen what we got going on
I only wanna put my heart and my life in songs
Writing about the pain I felt with my daddy gone
About the emptiness I felt when I sat alone
About the happiness I feel when I sing it loud
He should have heard the noise we made with the happy crowd
Did my Gran Daddy know he taught me what a poem was
How you can use a sentence or just a simple pause
What will I say when my kids ask me who my daddy was
I thought about it for a while and I'm at a loss
Knowing that I´m gonna live my whole life without him
I found out a lot of things I never knew about him
All I know is that I´ll never really be alone
Cause we gotta lot of love and a happy home
And my goal is to give every line an <h4 id="no1">TEXT</h4> for example, and the number after no, like no1 or no4 should be incremented every iteration, that's why I chose a for-loop.
Looks like you need to escape your regexp
preg_replace('/\[<br \/\]/', ...);
Really though, this is a classic XY Problem. Instead of asking us how to fix your solution, you should ask us how to solve your problem.
Show us some example text in the database and then show us how you would like it to be formatted. It's very likely there's a better way.
I would use array_walk for this. ideone demo here
$lines = preg_split("/[\r\n]+/", $row['lyric']);
array_walk($lines, function(&$line, $idx) {
$line = sprintf("<h4 id='no%d'>%s</h4>", $idx+1, $line);
});
echo implode("\n", $lines);
Output
<h4 id="no1">Mama called about the paper turns out they wrote about me</h4>
<h4 id="no2">Now my broken heart's the only thing that's broke about me</h4>
<h4 id="no3">So many people should have seen what we got going on</h4>
...
<h4 id="no16">Cause we gotta lot of love and a happy home</h4>
Explanation of solution
nl2br doesn't really help us here. It converts \n to <br /> but then we'd just end up splitting the string on the br. We might as well split using \n to start with. I'm going to use /[\r\n]+/ because it splits one or more \r, \n, and \r\n.
$lines = preg_split("/[\r\n]+/", $row['lyric']);
Now we have an array of strings, each containing one line of lyrics. But we want to wrap each string in an <h4 id="noX">...</h4> where X is the number of the line.
Ordinarily we would use array_map for this, but the array_map callback does not receive an index argument. Instead we will use array_walk which does receive the index.
One more note about this line, is the use of &$line as the callback parameter. This allows us to alter the contents of the $line and have it "saved" in our original $lyrics array. (See the Example #1 in the PHP docs to compare the difference).
array_walk($lines, function(&$line, $idx) {
Here's where the h4 comes in. I use sprintf for formatting HTML strings because I think they are more readable. And it allows you to control how the arguments are output without adding a bunch of view logic in the "template".
Here's the world's tiniest template: '<h4 id="no%d">%s</h4>'. It has two inputs, %d and %s. The first will be output as a number (our line number), and the second will be output as a string (our lyrics).
$line = sprintf('<h4 id="no%d">%s</h4>', $idx+1, $line);
Close the array_walk callback function
});
Now $lines is an array of our newly-formatted lyrics. Let's output the lyrics by separating each line with a \n.
echo implode("\n", $lines);
Done!
If your text in db is in every line why just not explode it with \n character?
Always try to find a solution without using preg set of functions, because they are heavy memory consumers:
I would go lke this:
$lyric = $row['lyric'];
$lyrics =explode("\n",$lyrics);
$lyricsHtml=null;
$i=0;
foreach($lyrics as $val){
$i++;
$lyricsHtml[] = '<h4 id="no'.$i.'">'.$val.'</h4>';
}
$lyricsHtml = implode("\n",$lyricsHtml);
An other way with preg_replace_callback:
$id = 0;
$lyric = preg_replace_callback('~(^)|$~m',
function ($m) use (&$id) {
return (isset($m[1])) ? '<h4 id="no' . ++$id . '">' : '</h4>'; },
$lyric);
i have already succesfully translated some quotes via my translation function __(); and now I want to echo only one of those quotes at random. All quotes are separated in this string with a special character like a |
Sofar I only have this. What code could should go below this tackle my random echo?
$quotes =
__("IF YOU MAKE EVERYTHING BOLD, NOTHING IS BOLD") . "|" .
__("Quality of design is an indicator of credibility") . "|" .
__("People ignore design, that ignores people");
(An important restriction: it is essential that the quotes be exactly closed with __(" and "); sothat they can be checked and translated.) __($variable) doest not work with current clean up scripts that I have bought so these won't work.
You're already calling __() on each of your quotes individually, why not save all the extra translating and do something like:
$quotes = array('quote1', 'quote2', 'quote3');
$index = array_rand($quotes);
echo __($quotes[$index]);
Edit: To satisfy your other requirement, that the call to __() must immediately surround each string, you could do this:
$quotes = array(__('quote1'), __('quote2'), __('quote3'));
$index = array_rand($quotes);
echo $quotes[$index];
The big downside here is that you're now looking up a translation for every string in that array, even though only one is printed, but that's the same situation you had in the "one big string" solution.
Why don't you keep them in an array and translate only what is actually outputted?
$quotes = array(
"IF YOU MAKE EVERYTHING BOLD, NOTHING IS BOLD",
"Quality of design is an indicator of credibility",
"People ignore design, that ignores people",
);
$randomQuote = $quotes[ rand(0, count($quotes)-1)];
echo __($randomQuote);
Why the biscuits are they all in one string, and not an array? Your problem would be immediately solved if this was the case. As stands, split in | and index randomly into the array created to pick a random quote.
This will not validate because of the output from print_r, is it not supposed to be used "on a site" or do one have to format it in a certain way?
<?php
$stuff1 = $_POST["stuff1"];//catch variables
$stuff2 = $_POST["stuff2"];
$stuff3 = $_POST["stuff3"];
$myStuff[0] = $stuff1;//put into array
$myStuff[1] = $stuff2;
$myStuff[2] = $stuff3;
print_r($myStuff);
?>
print_r() is mainly designed as a helpful tool for developers, not for actual production use in a manner that end-users would see. Thus, you shouldn't really be trying to validate it - if you're at the stage where you're trying to get stuff to validate, you shouldn't be using print_r anyway.
The validator can't distinguish the output of print_\r() from the surrounding html structure; it simply parses the whole character stream. If the output of your print_r() contains characters that have a special meaning in html (apparently < and > in your case) the validator must assume that it belongs to the html structure, not the text data. You have to mark them as "no, this is just text data, not a control character" for html parsers. One way to do this is to send entities instead of the "real" character itself, e.g. < instead of <
The function htmlspecialchars() takes care of those characters that always have a special meaning in (x)html.
You might also want to enclose the output in a <pre>....</pre> element to keep the formatting of print_r().
echo '<pre>', htmlspecialchars(print_r($myStuff, true)), "</pre>\n";
A plain print_r outputs text, so there's no reason for it not to affect validation. To print it out nicely formatted on an HTML page, use a <pre>:
$printout = print_r($my_var);
echo "<pre>$printout</pre>";
If you don't want to display it, but only to see it as a developer, place it in an HTML (<!-- any text -->).