File "HtmlTag.php"
Full path: /home/argothem/www/organecyberpresse/ecrire/src/Texte/Collecteur/HtmlTag.php
File size: 5.66 KB
MIME-type: text/x-php
Charset: utf-8
<?php
/***************************************************************************\
* SPIP, Système de publication pour l'internet *
* *
* Copyright © avec tendresse depuis 2001 *
* Arnaud Martin, Antoine Pitrou, Philippe Rivière, Emmanuel Saint-James *
* *
* Ce programme est un logiciel libre distribué sous licence GNU/GPL. *
* \***************************************************************************/
namespace Spip\Texte\Collecteur;
/**
* Extrait une langue des extraits polyglottes (`<multi>`)
*
* Retrouve les balises `<multi>` d'un texte et remplace son contenu
* par l'extrait correspondant à la langue demandée.
*
* Si la langue demandée n'est pas trouvée dans le multi, ni une langue
* approchante (exemple `fr` si on demande `fr_TU`), on retourne l'extrait
* correspondant à la langue par défaut (option 'lang_defaut'), qui est
* par défaut la langue du site. Et si l'extrait n'existe toujours pas
* dans cette langue, ça utilisera la première langue utilisée
* dans la balise `<multi>`.
*
* Ne pas mettre de span@lang=fr si on est déjà en fr.
*/
class HtmlTag extends AbstractCollecteur {
protected static string $markPrefix = 'HTMLTAG';
/**
* La preg pour découper et collecter les modèles
* @var string
*/
protected string $preg_openingtag;
protected string $preg_closingtag;
protected string $tag;
public function __construct(string $tag, ?string $preg_openingtag = null, ?string $preg_closingtag = null) {
$tag = strtolower($tag);
$this->tag = $tag;
$this->preg_openingtag = ($preg_openingtag ?: "@<{$tag}\b([^>]*?)(/?)>@isS");
$this->preg_closingtag = ($preg_closingtag ?: "@</{$tag}\b[^>]*>@isS");
}
/**
* @param string $texte
* @param array $options
* bool $detecter_presence
* bool $nb_max
* @return array
*/
public function collecter(string $texte, array $options = []): array {
if (!$texte) {
return [];
}
$upperTag = strtoupper($this->tag);
$hasUpperCaseTags = (strpos($texte, '<' . $upperTag) !== false or strpos($texte, '</' . $upperTag) !== false);
// collecter les balises ouvrantes
$opening = static::collecteur($texte, '', $hasUpperCaseTags ? '<' : '<' . $this->tag, $this->preg_openingtag, empty($options['detecter_presence']) ? 0 : 1);
if (!$opening) {
return [];
}
// collecter les balises fermantes
$closing = static::collecteur($texte, '', $hasUpperCaseTags ? '</' : '</' . $this->tag, $this->preg_closingtag);
#var_dump($opening);
#var_dump($closing);
// enlever les closing qui sont avant le premier opening, car ils n'ont pas de sens
$first_opening = reset($opening);
while (!empty($closing)
and $first_closing = reset($closing)
and $first_closing['pos'] < $first_opening['pos']) {
array_shift($closing);
}
$profondeur = ($options['profondeur'] ?? 1);
$tags = [];
while (!empty($opening)) {
$first_opening = array_shift($opening);
// self closing ?
if (strpos($first_opening['raw'], '/>', -2) !== false) {
$tag = $first_opening;
$tag['opening'] = $tag['raw'];
$tag['closing'] = '';
$tag['innerHtml'] = '';
$tags[] = $tag;
}
else {
$need_closing = 0;
$next_closing = reset($closing);
$next_opening = reset($opening);
while ($next_opening and $next_closing and $next_opening['pos'] < $next_closing['pos']) {
while ($next_opening and $next_opening['pos'] < $next_closing['pos']) {
// si pas self closing, il faut un closing de plus
if (strpos($next_opening['raw'], '/>', -2) === false) {
$need_closing++;
}
array_shift($opening);
$next_opening = reset($opening);
}
// il faut depiler les balises fermantes autant de fois que nécessaire et tant qu'on a pas une nouvelle balise ouvrante
while ($need_closing and $next_closing and (!$next_opening or $next_closing['pos'] < $next_opening['pos'])) {
array_shift($closing);
$need_closing--;
$next_closing = reset($closing);
}
}
// si pas de fermeture, c'est une autofermante mal fermée...
if (!$next_closing or $need_closing) {
$tag = $first_opening;
$tag['opening'] = $tag['raw'];
$tag['closing'] = '';
$tag['innerHtml'] = '';
$tags[] = $tag;
}
else {
$tag = $first_opening;
$next_closing = array_shift($closing);
$innerHtml = substr($texte, $tag['pos'] + $tag['length'], $next_closing['pos'] - $tag['pos'] - $tag['length']);
$tag['length'] = $next_closing['pos'] - $tag['pos'] + $next_closing['length'];
$tag['opening'] = $tag['raw'];
$tag['raw'] = substr($texte, $tag['pos'], $tag['length']);
$tag['innerHtml'] = $innerHtml;
$tag['closing'] = $next_closing['raw'];
$tags[] = $tag;
}
}
if ((!empty($options['detecter_presence']) and count($tags))) {
return $tags;
}
if (($profondeur == 1 and !empty($options['nb_max']) and count($tags) >= $options['nb_max'])) {
break;
}
}
while (--$profondeur > 0) {
$outerTags = $tags;
$tags = [];
$options['profondeur'] = 1;
foreach ($outerTags as $outerTag) {
if (!empty($outerTag['innerHtml'])) {
$offsetPos = $outerTag['pos'] + strlen($outerTag['opening']);
$innerTags = $this->collecter($outerTag['innerHtml'], $options);
if (!empty($innerTags)) {
foreach ($innerTags as $tag) {
$tag['pos'] += $offsetPos;
$tags[] = $tag;
}
if (($profondeur == 1 and !empty($options['nb_max']) and count($tags) >= $options['nb_max'])) {
return $tags;
}
}
}
}
}
return $tags;
}
}