Diskuze: Stránkování článků po znacích - problém s obrázky

PHP PHP Stránkování článků po znacích - problém s obrázky American English version English version

Avatar
roverjedla
Člen
Avatar
roverjedla:

Ahoj,

měl bych dotaz ohledně rozdělení článku na několik stránek. Napsal jsem si kód, který mi článek vytažený z databáze rozdělí po tolika písmenech co si určím - takto jsem to chtěl a funguje to perfektně.

Problém nastává ve fázi kdy do článku vložím i obrázek. Používám TinyMCE a ten mi obrázek, který je třeba zkopírovaný z googlu vloží tímto stylem:

<p>nějaký text....</p><p><img src="https://www.royalcanin.com/~/media/Royal-Canin/Product-Categories/cat-adult-landing-hero.ashx" alt="" /></p><p>nějaký text....</p>

Jistě Vám již došlo, že problém je v tom, když si vytáhnu obsah článku a poté pomocí substringu vypisuju jen jeho část, jelikož se tam započítá i <img src=....>. Potřeboval bych vymyslet něco, co by bylo schopné tyto tagy ignorovat. Nenapadá Vás, jak by to přibližně šlo?

V konečné fázi bych tedy nastavil, ať se zobrazí třeba 1000 znaků na stránku a pokud mezi těmito tisíci znaky bude i nějaký obrázek, tak se zobrazí také, ale nezmenší výsledný počet znaků - těch musí být prostě 1000 - resp. tolik, kolik se na začátku nastaví.

Díky moc, roverjedla.

 
Odpovědět 29. července 22:31
Avatar
David Hynek
Redaktor
Avatar
Odpovídá na roverjedla
David Hynek:

co nahradit tag obrázku nějakým znakem třeba #, pak upravit text na 1000 znaků a pak tento znak zpět nahradit obrázkem?

Nahoru Odpovědět 29. července 23:31
Čím víc vím, tím víc věcí nevím.
Avatar
petr.jouza
Člen
Avatar
Odpovídá na roverjedla
petr.jouza:

Ahoj,
nevím, zda to bude fungovat správně, ale zkusil bych funkci strip_tags(), která odstraní z řetězce tagy HTML a PHP. Pak bys měl jen čistý text, který budeš ořezávat. Musíš ho samozřejmě pak zvlášť naformátovat, protože ti veškeré <p></p>, <div></div>, <a>, atd... odstraní.

 
Nahoru Odpovědět 30. července 8:23
Avatar
Oxtimus
Člen
Avatar
Oxtimus:

O něco jsem se pokusil. Je to celkem dlouhé a možná i dost těžkopádné, ale na druhou stranu vždy dostaneš původní text (rozdělený do položek pole) bez jakékoliv deformace:

/**
 * Rozdělí text do pole po částech o $countChars znacích
 * @param string $text zdrojový text
 * @param int $countChars max. počet znaků v jedné části
 * @param array $allowed seznam tagů, které se nebudou započítávat do délky textu
 * @return array rozdělený text
 */
function partition($text, $countChars, $allowed = ['p', 'img'])
{
    $tag = false; // Příznak tagu (rozlišuje, zda se aktuální znak bude počítat docelkové délky textu)
    $temp = ''; // Dočasný text, který má max. délku $countChars a po naplnění se uloží do výsledného pole a opět vyprázdní
    $char = 0; // Počet znaků mimo tagy v $temp
    $result = []; // Konečný výsledek

    // Pomocí cyklu se projedou všechny znaky
    for ($i = 0, $l = mb_strlen($text); $i < $l; $i++) {
        // Pokud zde začíná počáteční nebo ukončovací tag, nastaví se příznak $tag = true
        for ($j = 0, $k = count($allowed); $j < $k; $j++) {
            if (mb_substr($text, $i, mb_strlen($allowed[$j]) + 1) === '<' . $allowed[$j] || mb_substr($text, $i, mb_strlen($allowed[$j]) + 2) === '</' . $allowed[$j]) {
                $tag = true;
                break;
            }
        }
        $temp .= mb_substr($text, $i, 1);
        // Pouze pokud aktuální znak není součástí tagu, započítá se do počtu znaků
        if (!$tag) {
            $char++;
        }
        // Při dosažení počtu max. znaků se aktuální část uloží jako nová položka do výsledku a začne se počítat další část o $countChars znacích
        if ($char === $countChars) {
            $char = 0;
            $result[] = $temp;
            $temp = '';
        }
        // Pokud zde končí tag, nastaví se příznak $tag = false
        if (mb_substr($text, $i, 1) === '>') {
            $tag = false;
        }
    }
    // Zbytek se uloží jako další položka do výsledku
    if(preg_match('/^<[^>]*>$/', $temp)) {
        $result[count($result) - 1] .= $temp;
    } else {
        $result[] = $temp;
    }
    return $result;
}

U každého použití pak bude stačit napsat:

$array = partition($text, 10);

což rozdělí text na části o maximální délce 10 znaků (tagy se nepočítají).

$text = '<p>nějaký text....</p><p><img src="https://www.royalcanin.com/~/media/Royal-Canin/Product-Categories/cat-adult-landing-hero.ashx" alt="" /></p><p>nějaký text....</p>';
var_dump(partition($text, 10));

// Výsledek
array (size=3)
  0 => string '<p>nějaký tex' (length=15)
  1 => string 't....</p><p><img src="https://www.royalcanin.com/~/media/Royal-Canin/Product-Categories/cat-adult-landing-hero.ashx" alt="" /></p><p>nějak' (length=139)
  2 => string 'ý text....</p>' (length=15)

K jednotlivým částem textu o 10 znacích máš pak přístup jednoduše přes index toho pole, kam si výsledek uložil ($array[0], $array[1], ...).

 
Nahoru Odpovědět 30. července 12:06
Avatar
petr.jouza
Člen
Avatar
Odpovídá na roverjedla
petr.jouza:

Tak jsem si vzpomněl, že jsem něco podobného v minulosti dělal a skutečně to takto funguje:

<?php
        $textSTagy = '<p>TADY JE TEXT S TAGY</p>' ;
        $textBezTagu = strip_tags($textSTagy) ;
        $text = substr($textBezTagu,0,1000) ;
        $delkaTextu = strlen($textBezTagu) ;
        echo $text ; if($delkaTextu >= 1000) {echo '...' ;}
?>

strip_tags() mi odstraní všechny HTML a PHP znaky, substr() zkrátí text na požadovanou délku a ještě přes strlen() si spočítám délku textu a pokud je delší, tak přes if podmínku případně doplním tři tečky na konec.

Samozřejmě si z toho můžeš udělat i funkci.

P.S. také ořezávám text z TinyMCE.

 
Nahoru Odpovědět 30. července 18:25
Avatar
roverjedla
Člen
Avatar
Odpovídá na David Hynek
roverjedla:

Když jsem nad tím tak přemýšlel, tak se mi nápad, abych nahradil celý tag <img> za nějaký znak, docela zamlouvá. Jak by ale mohl vypadat příkaz pro nahrazení za nějaký jednoduchý znak? Protože samozřejmě je

<img src='xxx' alt='xxx'>

a poté třeba tag

<img src='yyy' alt='yyy'>

vždycky je vnitřek tagu jiný a já bych potřeboval udělat nějakou funkci, která by našla začátek tagu - tudíž <img src= - to je na začátku vždy stejně a poté i konec - tudíž pouze >.

Tudíž teď pracuji na funkci, která nestraně dokáže nahradit např. toto

<img src="https://www.royalcanin.com/~/media/Royal-Canin/Product-Categories/cat-adult-landing-hero.ashx" alt="" />

nebo toto

<img src="jakákoliAdresa...." alt="" />

například na znak #..
Je to dobrý cesta, popřípadě napadá Vás lepší? Budu vděčný za rady, jak lze toto zkonstruovat.

Díky moc...

 
Nahoru Odpovědět 31. července 12:06
Avatar
David Hynek
Redaktor
Avatar
Odpovídá na roverjedla
David Hynek:

To né já, to Kosmas :)

<?php

$r = "Lorem ipsum dolor sit amet <img src='http://www.ditom.cz/img/zateplene-montovana-hala-predni-cast.jpg' alt='img' title='hala' /> consectetuer turpis velit nibh interdum dapibus. Feugiat ut convallis Morbi.";

// vytažení obrázku z textu
preg_match('/(<img.*\/>)/', $r, $r_img);
echo $r_img[1];

// výpis s náhradou za obrázek, moznost delat s textem psi kusy
$r_nahrada = preg_replace('/(<img.*\/>)/',"#",$r );
echo $r_nahrada;
echo "<br />";

// a zpet obrazek na misto kam to patři
$r_obnova = preg_replace('/(#)/',$r_img[1],$r_nahrada );
echo $r_obnova;

?>
Akceptované řešení
+20 Zkušeností
+1 bodů
Řešení problému
Nahoru Odpovědět 31. července 12:56
Čím víc vím, tím víc věcí nevím.
Avatar
roverjedla
Člen
Avatar
 
Nahoru Odpovědět  +1 31. července 13:10
Avatar
David Hynek
Redaktor
Avatar
Odpovídá na roverjedla
David Hynek:

úplně jsem zapomenul ošetřit "hladovost" regulárního příkazu, změň si je takto:

preg_match('/(<img.*?\/>)/', $r, $r_img);
$r_nahrada = preg_replace('/(<img.*?\/>)/',"#",$r );

Je to přidání toho otazníku, nebude pak tolik hladový, jinak by ti "sežral" všechno mezi začátkem prvního a koncem posledního obrázku. Kdyby tam bylo v textu více obrázků, pak budou uloženy v poli. Ty pak musíš projet cyklem text a podle pořadí náhradního znaku nahradit obrázkem ve stejném pořadí. Tedy první znak # prvním obrázkem a td.
Ať to slouží :)

Nahoru Odpovědět 31. července 13:34
Čím víc vím, tím víc věcí nevím.
Děláme co je v našich silách, aby byly zdejší diskuze co nejkvalitnější. Proto do nich také mohou přispívat pouze registrovaní členové. Pro zapojení do diskuze se přihlas. Pokud ještě nemáš účet, zaregistruj se, je to zdarma.

Zobrazeno 9 zpráv z 9.