protected function _htmlHandling() { $aTagTexts = $this->_splitTagText($this->_oString->get(), true, false); $iTagScriptDepth = 0; $oRegexTag = \Aouka\Text\Regex::tag(); foreach ($aTagTexts as &$sTagText) { if ($oRegexTag->test($sTagText)) { // S'il s'agit d'une balise script if (preg_match("`^<(/)?\\s*script`i", $sTagText, $aCaptures)) { // Si la balise script est ouvrante, // on incrémente la profondeur du script if (!isset($aCaptures[1])) { ++$iTagScriptDepth; } else { $iTagScriptDepth -= 1; $iTagScriptDepth = $iTagScriptDepth < 0 ? 0 : $iTagScriptDepth; } } } else { if (!$iTagScriptDepth) { $sTagText = $this->_process($sTagText); } } } return $this->_oString->setString(implode('', $aTagTexts)); }
/** * Éclate une chaîne en séparant les tags html du texte. * * @param string $sInputString Chaîne a éclater. * @param boolean $bCaptureTags Définit si les tags html doivent être capturés ou non. * @param boolean $bSeparateHtmlPlain Définit si les tags et les textes sont retournés dans deux sous-tableaux différents. * @return array */ protected function _splitTagText($sInputString, $bCaptureTags = true, $bSeparateHtmlPlain = false) { // On remplace par un placeholder les chevrons ouvrants n'étant pas suivis par : // ! => <!DOCTYPE>, <!-- Commentaires --> // une lettre => <div> // / => </div> $sLeftAngleBracketReplace = uniqid('bracket'); $sString = preg_replace("`<(?!!|[[:alpha:]]|/)`", $sLeftAngleBracketReplace, $sInputString); $oTagRegex = Regex::tag()->setModifiers($this->_m()); // On explose la chaîne en fonction des balises html $aHtmlExplodeTexts = array_values($oTagRegex->split($sString, -1, $bCaptureTags ? PREG_SPLIT_NO_EMPTY | PREG_SPLIT_DELIM_CAPTURE : PREG_SPLIT_NO_EMPTY)); foreach ($aHtmlExplodeTexts as &$sHtmlExplodeText) { // Si ce n'est pas une balise html if (mb_substr($sHtmlExplodeText, 0, 1, $this->_oString->getEncoding()) !== '<') { // on décode les potentiels chevrons n'appartenant pas à une balise $sHtmlExplodeText = str_replace($sLeftAngleBracketReplace, '<', $sHtmlExplodeText); } } if ($bCaptureTags && $bSeparateHtmlPlain) { $aTags = $aTexts = array(); foreach ($aHtmlExplodeTexts as $iIndex => $sTagText) { if ($oTagRegex->test($sTagText)) { $aTags[$iIndex] = $sTagText; } else { $aTexts[$iIndex] = $sTagText; } } return array('tags' => $aTags, 'texts' => $aTexts); } return $aHtmlExplodeTexts; }
protected function _htmlHandling() { $aTagTexts = $this->_splitTagText($this->_oString->get()); $oRegexTag = Regex::tag()->setModifiers($this->_m()); foreach ($aTagTexts as &$sTagText) { if (!$oRegexTag->test($sTagText)) { $sTagText = $this->_process($sTagText); } } return $this->_oString->setString(implode('', $aTagTexts)); }
protected function _htmlHandling() { $aHtmlPlainText = $this->_splitTagText($this->_oString->get()); $oRegexTag = Regex::tag()->setModifiers($this->_m()); foreach ($aHtmlPlainText as &$sTagText) { if (!$oRegexTag->test($sTagText)) { $sTagText = mb_strtolower($sTagText, $this->_oString->getEncoding()); } } return $this->_oString->setString(implode('', $aHtmlPlainText)); }
protected function _htmlHandling() { $aHtmlPlainText = $this->_splitTagText($this->_oString->get()); $oRegexTag = Regex::tag()->setModifiers($this->_m()); foreach ($aHtmlPlainText as &$sTagText) { if (!$oRegexTag->test($sTagText)) { $sCasedString = $this->_setCase($sTagText, $this->_cCase); $sTagText = $this->_exceptionSetCase($sCasedString); } } return $this->_oString->setString(implode('', $aHtmlPlainText)); }
protected function _htmlHandling() { $this->_formatPattern(); $aHtmlPlainText = $this->_splitTagText($this->_oString->get()); $oTagRegex = Regex::tag()->setModifiers($this->_m()); foreach ($aHtmlPlainText as &$sTagText) { if (!$oTagRegex->test($sTagText)) { $sTagText = preg_replace_callback($this->_mPattern, array($this, '_executeManipulator'), $sTagText); } } return $this->_oString->setString(implode('', $aHtmlPlainText)); }
protected function _chunkHtmlHandling() { $aTagTexts = $this->_splitTagText($this->_oString->get()); $oRegexTag = Regex::tag(); $iCount = 0; foreach ($aTagTexts as &$sTagText) { if (!$oRegexTag->test($sTagText)) { $iCount += $this->_process($sTagText); } } return $iCount; }
protected function _htmlHandling() { $aHtmlPlainText = $this->_splitTagText($this->_oString->get()); $oTagRegex = Regex::tag()->setModifiers($this->_m()); $sEncoding = $this->_oString->getEncoding(); foreach ($aHtmlPlainText as &$sValue) { if (!$oTagRegex->test($sValue)) { $sValue = self::_ucfirst($sValue, $sEncoding); break; } } return $this->_oString->setString(implode('', $aHtmlPlainText)); }
/** * Définit les tags de début et de fin. * * Les tags de fin sont définis à partir des tags de début. * * @param string Balises HTML de début. * @throws \Exception */ protected function _initTags() { $oRegexTag = Regex::tag()->setModifiers($this->_m()); $aTags = array_filter(preg_split("`({$oRegexTag})`", $this->_sInputTags, -1, PREG_SPLIT_DELIM_CAPTURE)); foreach ($aTags as $sTag) { if (!$oRegexTag->test(trim($sTag))) { throw ExceptionType::invalidArgument("Argument #1 doit être uniquement composé de balises HTML.", Exception::FROM_HANDLER); } $this->_sStartingTags = $this->_sInputTags; if (preg_match('`^<([[:alnum:]]+)`', $sTag, $aMatches)) { $this->_sEndingTags = "</{$aMatches[1]}>" . $this->_sEndingTags; } } }
protected function _commonHandling() { // On n'utilise pas la fonction native strip_tags de php car elle ne gère pas correctement la suppression des tags. // Exemple : pour la chaîne de caractères suivante "<div>a <= b et d > c</div>", la fonction strip_tags // retournera "a c" alors qu'elle qu'on s'attend à ce qu'elle retourne "a <= b et d > c". $this->_setAllowableTagNames(); $oRegexTag = Regex::tag()->setModifiers($this->_m()); $aHtmlTagTexts = array_values($oRegexTag->split($this->_oString->get(), -1, PREG_SPLIT_DELIM_CAPTURE | PREG_SPLIT_NO_EMPTY)); foreach ($aHtmlTagTexts as $iIndex => &$sHtmlTagText) { if ($oRegexTag->test($sHtmlTagText)) { if (!$this->_isAllowableTag($sHtmlTagText)) { $sHtmlTagText = ''; } } } return $this->_oString->setString(implode('', $aHtmlTagTexts)); }
protected function _htmlHandling() { $sString = Regex::tag()->replace($this->_oString->get(), ''); return $this->_process($sString); }
protected function _buildRegexPos() { // Positions des éléments répartis par l'expression rationnelle $this->_aRegexPos = array(); if ($this->_getHTMLParsingMode() !== String::CHUNK_PARSING) { // Texte nettoyé de ses balises if ($this->_getStringType() === InterfaceText::HTML) { $oRegexTag = Regex::tag()->setModifiers($this->_m()); $sPlainText = $oRegexTag->replace($this->_getString()->get(), ''); } else { $sPlainText = $this->_getString()->get(); } // On explose le texte plain selon l'expression rationnelle $aPlainTexts = array_values($this->_getRegex()->split($sPlainText, -1, PREG_SPLIT_NO_EMPTY | PREG_SPLIT_DELIM_CAPTURE | PREG_SPLIT_OFFSET_CAPTURE)); // On alimente le tableau des positions de la regex dans le texte $this->_feedRegexPosArray($aPlainTexts); } else { // Récupération des positions des éléments séparés (balises html et textes plain) $aTagTextPositions = $this->getTagTextPos(); // Longueur des chaînes de texte précédents $iPrevTextsLength = 0; // Pour chaque Tag/Text foreach ($aTagTextPositions as $aTagTextPos) { // S'il l'élément est un texte if ($aTagTextPos['type'] == 'text') { // On l'explose par rapport à la regex, en récupérant les positions $aPlainTexts = $this->_oRegex->split($aTagTextPos['element'], -1, PREG_SPLIT_DELIM_CAPTURE | PREG_SPLIT_NO_EMPTY | PREG_SPLIT_OFFSET_CAPTURE); // On alimente le tableau des positions de la regex dans le texte $iCurrentTextLength = $this->_feedRegexPosArray($aPlainTexts, $iPrevTextsLength); $iPrevTextsLength += $iCurrentTextLength; } } } $iMatchingRegexIndex = $iNoMatchingRegexIndex = 0; foreach ($this->_aRegexPos as $iRegexPosIndex => $aRegexPos) { foreach ($aRegexPos['pos']['string'] as $aPos) { if ($aRegexPos['match_regex']) { $this->_aStats['index']['matching_regex_elem'][$iMatchingRegexIndex] += array('regex_pos' => $iRegexPosIndex); ++$iMatchingRegexIndex; } else { $this->_aStats['index']['no_matching_regex_elem'][$iNoMatchingRegexIndex] += array('regex_pos' => $iRegexPosIndex); ++$iNoMatchingRegexIndex; } } } // Si on n'est pas en chunk // et que le regex_pos précédent est égale au regex_pos actuel // on fusionne les 2, ainsi : /* [0] => Array ( [tag_text_pos] => 0 [chunk_pos] => [regex_pos] => 0 ) [1] => Array ( [tag_text_pos] => 2 [chunk_pos] => [regex_pos] => 0 ) */ // devient /* [0] => Array ( [tag_text_pos] => array(0, 2) [chunk_pos] => [regex_pos] => 0 ) */ if ($this->_getHTMLParsingMode() !== String::CHUNK_PARSING) { $this->_groupStatRegexByRegexPos(); } }
protected function _htmlHandling() { $sEncoding = $this->_oString->getEncoding(); $aHtmlPlainText = $this->_splitTagText($this->_oString->get()); // Par défaut la chaîne n'est ni coupée, ni n'a la taille maximale atteinte $bCutted = $bFitted = false; // Nombre de caractères parsés total de la chaîne $iTotalChars = 0; // Index de la cellule contenant le morceau de chaîne atteignant la limite $iCellIndex = null; $oTagRegex = Regex::tag()->setModifiers($this->_m()); foreach ($aHtmlPlainText as $iIndex => &$sText) { // Pour les éléments en plain text if (!$oTagRegex->test($sText)) { // Si la limite n'a pas encore été atteinte ou dépassée if (!$bFitted && !$bCutted) { $iNbChars = mb_strlen($sText, $sEncoding); $iTotalChars += $iNbChars; if ($this->_iMaxLength <= $iTotalChars) { // Si la limite vient d'être dépassée if ($this->_iMaxLength < $iTotalChars) { $iTotalDelta = $iTotalChars - $this->_iMaxLength; $sText = $this->_cut($sText, $sEncoding, $iNbChars - $iTotalDelta); $bCutted = true; } else { $bFitted = true; } // On note la cellule du tableau à partir de laquelle on exécute la limite $iCellIndex = $iIndex; } } else { $sText = ''; // Si la limite a été atteinte pile-poil et qu'on en est à supprimer du texte if ($bFitted) { $bCutted = true; } } } } // Si le plain text a été coupé et qu'il existe un trimmarker if ($bCutted && $this->_sTrimMarker) { // Si le trimmarker n'est pas à prendre en compte dans la limite if (!$this->_bIncludeTrimMarker) { // On l'ajoute dans la cellule à partir de laquelle la limite a été exécutée, // en supprimant les espaces blancs à la fin du texte de celle-ci if ($iCellIndex !== null) { if ($this->_bExactly) { $aHtmlPlainText[$iCellIndex] = $aHtmlPlainText[$iCellIndex] . $this->_sTrimMarker; } else { $aHtmlPlainText[$iCellIndex] = rtrim($aHtmlPlainText[$iCellIndex]) . $this->_sTrimMarker; } } } else { $iTrimMarkerLength = mb_strlen($this->_sTrimMarker, $sEncoding); $bCutted = $bFitted = false; $iTotalChars = 0; $iCellIndex = null; // Calcul de la taille que doit faire la chaîne, en prenant en compte la taille du trimmarker $iMaxStringLength = $this->_iMaxLength - $iTrimMarkerLength < 0 ? 0 : $this->_iMaxLength - $iTrimMarkerLength; foreach ($aHtmlPlainText as $iIndex => &$sText) { // Pour les éléments en plain text if (!$oTagRegex->test($sText)) { // Si la limite n'a pas encore été atteinte ou dépassée if (!$bFitted && !$bCutted) { $iNbChars = mb_strlen($sText, $sEncoding); $iTotalChars += $iNbChars; if ($iMaxStringLength <= $iTotalChars) { // Si la limite vient d'être dépassée if ($iMaxStringLength < $iTotalChars) { $iTotalDelta = $iTotalChars - $iMaxStringLength; $sText = $this->_cut($sText, $sEncoding, $iNbChars - $iTotalDelta); $bCutted = true; } else { $bFitted = true; } if (!$this->_bExactly) { // On ajoute le trimmarker en supprimant les espaces blancs à la fin du texte $sText = rtrim($sText) . $this->_sTrimMarker; } } } else { $sText = ''; } } } } } return $this->_oString->setString(implode('', $aHtmlPlainText)); }
/** * Retourne un tableau des positions des éléments html et plain dans la chaîne de caractères $this->_oString. * * Par exemple pour $this->_oString->get() = "[div]Toto", le tableau retourné sera comme suit : * [ * [0] => [ * [element] => [div], * [length] => 5, * [pos] => [ * [string] => [0, 5] // Positions de début et de fin dans la chaîne de caractères. * ] * ], * [1] => [ * [element] => Toto, * [length] => 4, * [pos] => [ * [string] => [5, 9], // Positions de début et de fin dans la chaîne de caractères. * [text] => [0, 4] // Positions de début et de fin dans le texte plain. * ] * ] * ] * * @return array Tableau des positions */ protected function _getTagTextPositions() { if ($this->_oString->getType() === InterfaceText::PLAIN) { return $this->_getPlainTagTextPositions(); } // On remplace par un placeholder les chevrons ouvrants n'étant pas suivis par : // ! => <!DOCTYPE>, <!-- Commentaires --> // une lettre => <div> // / => </div> $sLeftAngleBracketReplace = uniqid('bracket'); $sString = preg_replace("`<(?!!|[[:alpha:]]|/)`", $sLeftAngleBracketReplace, $this->_oString->get()); // On explose la chaîne en fonction des balises html $oTagRegex = Regex::tag()->setModifiers($this->_m()); $aHtmlExplodeTexts = array_values($oTagRegex->split($sString, -1, PREG_SPLIT_NO_EMPTY | PREG_SPLIT_DELIM_CAPTURE | PREG_SPLIT_OFFSET_CAPTURE)); // Tableau des infos recueillies $aInfos = array(); // Tableau des stats $aStats = array('tag_indexes' => array(), 'no_tag_indexes' => array()); // Position de fin du texte précédent (càd du dernier élément qui n'est pas une balise) $iLastTextPos = 0; $aTagText = array(); foreach ($aHtmlExplodeTexts as $iIndex => $aHtmlExplodeText) { $sElement = $aHtmlExplodeText[0]; // Est-ce une balise html ? $bTag = mb_substr($sElement, 0, 1, $this->_oString->getEncoding()) == '<'; // Si ce n'est pas une balise html if (!$bTag) { // on décode les potentiels chevrons n'appartenant pas à une balise $sElement = str_replace($sLeftAngleBracketReplace, '<', $sElement); } $aTagText[$iIndex] = $sElement; // Nombre de caractères de l'élément $iLength = mb_strlen($sElement, $this->_oString->getEncoding()); // Stockage des positions de début et de fin de l'élément dans la chaîne de caractères $aPos = array('string' => array($aHtmlExplodeText[1], $aHtmlExplodeText[1] + $iLength)); // Si l'élément n'est pas une balise, on stocke également ses positions de début et de fin // dans le texte affiché sur une page HTML if (!$bTag) { $aPos['text'] = array($iLastTextPos, $iLastTextPos + $iLength); $iLastTextPos += $iLength; } // Ajout des infos dans le tableau statistiques $aInfos[$iIndex] = array('element' => $sElement, 'type' => $bTag ? 'tag' : 'text', 'length' => $iLength, 'pos' => $aPos); $aStats[($bTag ? '' : 'no_') . 'tag_indexes'][] = $iIndex; } $iTotalStringLength = 0; if ($aInfos) { $aLastInfos = end($aInfos); $iTotalStringLength = $aLastInfos['pos']['string'][1]; } return array('tag_text' => $aTagText, 'tag_text_pos' => $aInfos, 'stats' => array('string' => array('length' => $iTotalStringLength), 'text' => array('length' => mb_strlen(Regex::tag()->replace($this->_oString->get(), ''), $this->_oString->getEncoding())), 'tag_text_pos' => $aStats)); }