How to cut a PHP string in <H2> tags

Asked

Viewed 61 times

-1

I have a recipes website where the ingredients are separated into blocks, for example:

$ingredientes='<ul>
<li>100g de farinha de trigo</li>
<li>1 ovo</li>
<li>2 pitadas de sal</li>
<li>1 fio de azeite</li>
</ul>
<h2>Molho</h2>
<ul>
<li>Tomate</li>
<li>Cebola</li>
</ul>';

Then I needed to separate each block in order to create input fields for editing (each title H2 starts a new block), in this example would be:

<textarea name="bloco1"><ul>
    <li>100g de farinha de trigo</li>
    <li>1 ovo</li>
    <li>2 pitadas de sal</li>
    <li>1 fio de azeite</li>
    </ul></textarea>

<input name="titulo2" value="Molho">

<textarea name="bloco2"><ul>
<li>Tomate</li>
<li>Cebola</li>
</ul></textarea>

Only it won’t always be 2 blocks, sometimes it can be 2, other 3, and so on.

2 answers

1

I believe you can use Xpath, something like:

// Inicia o DOMDocument
$html = new DOMDocument();
// Importa o HTML (do $ingrediente)
$html->loadHTML($ingredientes);

// Inicia o XPath e busca por <ul>
$els = (new DOMXpath($html))->query("//ul");

// Obtém o HTML de cada <ul> e exibe entre <textarea>
foreach ($els as $el) {
    echo "<textarea>" . $el->ownerDocument->saveHTML($el) . "</textarea>";
}

This will return:

<textarea><ul>
<li>100g de farinha de trigo</li>
<li>1 ovo</li>
<li>2 pitadas de sal</li>
<li>1 fio de azeite</li>
</ul>
</textarea>
<textarea><ul>
<li>Tomate</li>
<li>Cebola</li>
</ul></textarea>

In this case I’ve considered that you want to take everything in <ul>. If you want to ignore the h2 I think you can use another Xpath, or the bad one you can use a * and check on foreach if he’s a h2 and ignore it.


With the comment, you can just pick up all the ul and h2 and change the display based on what it is.

$html = new DOMDocument();
$html->loadHTML($ingredientes);

foreach ((new DOMXpath($html))->query('//ul|//h2') as $el) {
    if(strtolower($el->nodeName) === 'ul') {
          printf('<textarea>%s</textarea>', trim($el->ownerDocument->saveHTML($el)));
    }else{
          printf('<input value="%s">', htmlentities($el->textContent, ENT_HTML5 | ENT_QUOTES, 'utf-8'));
    }
}

If he goes ul it will display the HTML inside the <textarea>, if he is a input it will show the contents of h2 as a value. The $el->ownerDocument->saveHTML($el) will return the HTML, already the $el->textContent returns only the text.

Remember that this may still be vulnerable to an XSS!

Upshot:

<textarea><ul>
<li>100g de farinha de trigo</li>
<li>1 ovo</li>
<li>2 pitadas de sal</li>
<li>1 fio de azeite</li>
</ul>
</textarea>
<input value="Molho">
<textarea><ul>
<li>Tomate</li>
<li>Cebola</li>
</ul></textarea>

Test here.

  • opa, just need to return the title in the input tbm

  • @Leandromarzullo I edited

0

You can use a combination of explode with foreach to achieve the desired result. See:

<?php

$ingredientes='<ul>
<li>100g de farinha de trigo</li>
<li>1 ovo</li>
<li>2 pitadas de sal</li>
<li>1 fio de azeite</li>
</ul>
<h2>Molho</h2>
<ul>
<li>Tomate</li>
<li>Cebola</li>
</ul>';

$exploded = explode('<h2>', $ingredientes);

foreach ($exploded as $i => $item) 
{
    $partes = explode('</h2>', $item);
    $index = $i + 1;

    /**
     * Se existe o indice 1 é pq tem 2 items
     * Logo existe o titulo e os ingredientes
     */
    if (isset($partes[1])) 
    {
        printf('<input type="text" name="titulo%d" value="%s"/>', $index, trim($partes[0]));
        printf('<textarea name="bloco%d">%s</textarea>', $index, trim($partes[1]));
        continue;
    }
    /**
     * Caso contrario existe somente
     * os ingredientes
     */
    printf('<textarea name="bloco%d">%s</textarea>', $index, trim($partes[0]));
}

Browser other questions tagged

You are not signed in. Login or sign up in order to post.