Can I use conditional logic in PHP EOD? - php

Is it possible to put conditional logic inside an EOD string?
$str = <<<EOD
<table>
<tr>
<td>
if ( !empty($var1) ) {
{$var1}
} else {
{$var2}
}
</td>
</tr>
</table>
This doesn't work for me, and it sort of looks like it wouldn't work, but I thought I'd take a stab.
Also, is it EOD or EOT? Both seem to work.

No. You cannot use conditionals in heredoc.
Also, is it EOD or EOT?
As long as your beginning and ending strings match you can use anything:
$x = <<<THOMAS
Pick a string, any string
THOMAS;
The doc contains several examples demonstrating this
As to how best to achieve the example you provided, this would be my first inclination:
$td = !empty($var1) ? $var1 : $var2;
$str = <<<EOD
<table>
<tr>
<td>
{$td}
</td>
</tr>
</table>
EOD;

Related

how to fix preg_match_all in php?

This the code I want to get text from
<tr><td valign="top"><img src="/icons/back.gif" alt="[PARENTDIR]"></td><td>Parent Directory</td><td> </td><td align="right"> - </td><td> </td></tr>
i used it like this:
#preg_match_all("/<td><a href=\"(.*)\">/',$text,$ress);
but the what I get is this
/administrator/components/com_simplephotogallery/x/">Parent Directory</a></td><td> </td><td align="right
Instead of the greedy (.*), use a negated character class [^"]:
preg_match_all('/<td><a href="([^"]+)">/', $text, $ress);
Try this regex instead
#preg_match_all("/<td><a href=\"(([\/\w \.-]*)*\/?)\">/',$text,$ress);
i just used
$a = explod('<a herf="',$text);
$a = explod('">',$a[1])
or anyone can just use DOMDocument class

php search a string for 4 or more numbers with a decimal and format it to currency

I have an include that I'm pulling into a php page that's just a standard table with prices and whatnot.
E.g.
<table>
<tr>
<td>90</td>
<td> </td>
<td> </td>
<td> </td>
<td> </td>
</tr>
<tr>
<td>Hard Top</td>
<td>17170.00</td>
<td>5930.00</td>
<td>20818.00</td>
<td>2282.00</td>
</tr>
<tr>
<td>Hard Top XS</td>
<td>20972.50</td>
<td>7197.50</td>
<td>25381.00</td>
<td>2789.00</td>
</tr>
</table>
What I need to do is search through the include (I presume by putting it into a string first) then formatting all the numbers that are >= 4 characters long with a decimal point into currency.
so i would format '17170.00' as '£17,170.00' but I want to leave '90' alone as that's a title.
I know how to format into currency, that part's easy. But how do I search for clusters of numbers in a string that are >= 4 characters and have a decimal in the middle of them?
Would it use a regex (I've used them before but the intricacies still elude me) or would it be something simpler?
Something like this should work:
$string = file_get_contents('/path/to/file.html');
$string = preg_replace('#<td>(\d{4,}\.\d{2})</td>#', '<td>£$1</td>', $string);
I put the tds in there to restrict to only numbers in table cells as you have shown. You can remove these if not needed.
Debuggex Demo
Added an example with a callback to format the number. Might want to look at money_format instead, but I'm headed to lunch:
$string = preg_replace_callback('#<td>(\d{4,}\.\d{2})</td>#',
function($matches) { return '<td>£'.number_format($matches[1], 2).'</td>'; },
$string);

Get all matches in a preg_match request

I'm having the following problem, i have that structure:
$table = '
<table>
<tbody>
<tr valign="top">
<td>foo</td>
<td>bar</td>
</tr>
</tbody>
</table>
<table>
<tbody>
<tr valign="top">
<td>bee</td>
<td>dog</td>
</tr>
</tbody>
</table>';
I'm trying to retrieve an array with all <tr> but with no success. The closest pattern I've could made it, return all messed up.
$pattern = "/<tr valign[^>]*>(.*)<\/tr>/s";
preg_match_all($pattern, $table, $matches, PREG_PATTERN_ORDER);
If i put var_dump($matches), I want an array that returns:
array(
[0] => "<td>foo</td><td>bar</td>",
[1] => "<td>bee</td><td>dog</td>"
);
...or something close to that.
But I receive:
string(301) "
foo
bar
"
<table>
<tbody>
<tr valign="top">
<td>bee</td>
<td>dog</td>
</tr>
</tbody></table>
Anyone know what I'm doing wrong?
Thanks in advance.
You must make your quantifier lazy: .* => .*?
When you use a greedy quantifier, .* will take all possible characters, When you use a lazy quantifier, .*? will take the minimum number of characters.
When you use a lazy quantifier, the regex engine will take characters one by one and test the pattern completion for each character.
When you use a greedy quantifier (default behavior) the regex engine will take all possible characters (until the end in your case) and will backtrack character by character until the pattern completion succeed.
Notes:
It is useless to add PREG_PATTERN_ORDER since it is the default set of preg_match_all.
DOMDocument is probably a more adapted tool to deal with html. Example:
$dom = new DOMDocument();
#$dom->loadHTML($table);
$trs = $dom->getElementsByTagName('tr');
$results = array();
foreach ($trs as $tr) {
if ($tr->hasAttribute('valign')) {
$children = $tr->childNodes;
$tmp = '';
foreach ($children as $child) {
$tmp .= trim($dom->saveHTML($child));
}
if (!empty($tmp)) $results[] = $tmp;
}
}
echo htmlspecialchars(print_r($results, true));

Extract content from each first TD in a Table

I've got some HTML that looks like this:
<tr class="row-even">
<td align="center">abcde</td>
<td align="center"><img src="../images/delete_x.gif" alt="Delete User" border="none" /></td>
</tr>
<tr class="row-odd">
<td align="center">efgh</td>
<td align="center"><img src="../images/delete_x.gif" alt="Delete User" border="none" /></td>
</tr>
<tr class="row-even">
<td align="center">ijkl</td>
<td align="center"><img src="../images/delete_x.gif" alt="Delete User" border="none" /></td>
</tr>
And I need to retrieve the values, abcde, efgh, and ijkl
This is the regex I'm currently using:
preg_match_all('/(<tr class="row-even">|<tr class="row-odd">)<td align="center">(.*)<\/td><\/tr>/xs', $html, $matches);
Yes, I'm not very good at them. As with most of my regex attempts, this is not working. Can anyone tell me why?
Also, I know about html/xml parsers, but it would require a significant code revisit to make that happen. So that's for later. We need to stick with regex for now.
EDIT: To clarify, I need the values between the first <td align="center"></td> tag after either <tr class="row-even"> or <tr class="row-odd">
~<tr class="row-(even|odd)">\s*<td align="center">(.*?)</td>~m
Notice the m modifier and the use of \s*.
Also, you can make the first group non-capturing via ?:. I.e., (?:even|odd) as you're probably not interested in the class attribute :)
Try this:
preg_match_all('/(?:<tr class="row-even">|<tr class="row-odd">).<td align="center">(.*?)<\/td>/s', $html, $matches);
Changes made:
You've not accounted for the newline
between the tags
You don't need to x modifier as it
will discard the space in the regex.
Make the matching non-greedy by using
.*? in place of .*.
Working link
Actually, you dont need a too big change in your codebase. Fetching Text Nodes is always the same with DOM and XPath. All that does change is the XPath, so you could wrap the DOM code into a function that replaces your preg_match_all. That would be just a tiny change, e.g.
include_once "dom.php";
$matches = dom_match_all('//tr/td[1]', $html);
where dom.php just contains:
// dom.php
function dom_match_all($query, $html, array $matches = array()) {
$dom = new DOMDocument;
libxml_use_internal_errors(TRUE);
$dom->loadHTML($html);
libxml_clear_errors();
$xPath = new DOMXPath($dom);
foreach( $xPath->query($query) as $node ) {
$matches[] = $node->nodeValue;
}
return $matches;
}
and would return
Array
(
[0] => abcde
[1] => efgh
[2] => ijkl
)
But if you want a Regex, use a Regex. I am just giving ideas.
This is what I came up with
<td align="center">([^<]+)</td>
I'll explain. One of the challenges here is what's between the tags could be either the text you're looking for, or an tag. In the regex the [^<]+ says to match one or more characters that is not the < character. That's great, because that means the won't match, and the the group will only match until the tag is found.
Disclaimer: Using regexps to parse HTML is dangerous.
To get the innerhtml of the first TD in each TR, use this regexp:
/<tr[^>]*>\s*<td[^>]>(.+?)<\/td>/si
This is just a quick and dirty regex to meet your needs. It could easily be cleaned up and optimized, but it's a start.
<tr[^>]+>[^\n]*\n #Match the opening <tr> tag
\s*<td[^>]+>([^<]+)[^\n]+\n #Group the wanted data
[^\n]+\n #Match next line
</tr> #Match closing tag
Here is an alternative way, which may be more robust:
deluserconfirm.html\?user=([^"]+)

Trim doesn't remove \n

I am taking a string from textarea and exploding it and trimming each line of the array with array_map():
$answers = explode("\n", $data['answers']);
// remove all whitespace such as \r (carriage return)
$asnwers = array_map('trim', $answers);
Then I store each array value in a separate row in a table answers in the database. The problem is there seems to be \n character at the end of each answer in the database. When I echo answers in HTML like this:
<?php foreach ($this->answers as $a): ?>
<tr>
<td><?php echo $this->escape($a->body); ?></td>
</tr>
<?php endforreach; ?>
When I then look at the HTML source I see this:
<tr>
<td>Some random answer
</td>
</tr>
As you can see, there is a newline (probably \n) at the end of the string because the closing tag gets moved to the next line.
What I am doing wrong?
$asnwers = array_map('trim', $answers);
You're assigning the return value of array_map to $asnwers. It should be $answers.

Categories