2 namespace TYPO3\CMS\Core\Html;
32 const VOID_ELEMENTS =
'area|base|br|col|command|embed|hr|img|input|keygen|meta|param|source|track|wbr';
48 return $templateService->getSubpart($content, $marker);
63 public static function substituteSubpart($content, $marker, $subpartContent, $recursive =
true, $keepMarker =
false)
67 return $templateService->substituteSubpart($content, $marker, $subpartContent, $recursive, $keepMarker);
83 return $templateService->substituteSubpartArray($content, $subpartsContent);
101 return $templateService->substituteMarker($content, $marker, $markContent);
123 public static function substituteMarkerArray($content, $markContentArray, $wrap =
'', $uppercase =
false, $deleteUnused =
false)
127 return $templateService->substituteMarkerArray($content, $markContentArray, $wrap, $uppercase, $deleteUnused);
172 return $templateService->substituteMarkerAndSubpartArrayRecursive($content, $markersAndSubparts, $wrap, $uppercase, $deleteUnused);
194 foreach ($tags as &$tag) {
195 $tag = preg_quote($tag,
'/');
197 $regexStr =
'/\\<\\/?(' . implode(
'|', $tags) .
')(\\s*\\>|\\s[^\\>]*\\>)/si';
198 $parts = preg_split($regexStr, $content);
200 $pointer = strlen($parts[0]);
205 $partsSliced = array_slice($parts, 1, null,
true);
206 foreach ($partsSliced as $v) {
207 $isEndTag = substr($content, $pointer, 2) ==
'</' ? 1 : 0;
208 $tagLen = strcspn(substr($content, $pointer),
'>') + 1;
214 $newParts[] = $buffer;
220 $mbuffer = substr($content, $pointer, strlen($v) + $tagLen);
221 $pointer += strlen($mbuffer);
228 if ($eliminateExtraEndTags && $nested < 0) {
233 $buffer .= substr($content, $pointer, $tagLen);
237 if (!$nested && !$eliminated) {
238 $newParts[] = $buffer;
242 $mbuffer = substr($content, $pointer, strlen($v));
243 $pointer += strlen($mbuffer);
247 $newParts[] = $buffer;
266 foreach ($parts as $k => $v) {
269 $tagsArray = array();
271 $tagsArray[
'tag_end'] =
'</' . $firstTagName .
'>';
272 $tagsArray[
'tag_name'] = strtolower($firstTagName);
273 $tagsArray[
'add_level'] = 1;
276 $tagsArray = $procObj->{$callBackTags}($tagsArray, $level);
278 $parts[$k] = $tagsArray[
'tag_start'] . $tagsArray[
'content'] . $tagsArray[
'tag_end'];
280 if ($callBackContent) {
281 $parts[$k] = $procObj->{$callBackContent}($parts[$k], $level);
285 return implode(
'', $parts);
298 public function splitTags($tag, $content)
300 $tags = GeneralUtility::trimExplode(
',', $tag,
true);
301 foreach ($tags as &$tag) {
302 $tag = preg_quote($tag,
'/');
304 $regexStr =
'/\\<(' . implode(
'|', $tags) .
')(\\s[^>]*)?\\/?>/si';
305 $parts = preg_split($regexStr, $content);
306 $pointer = strlen($parts[0]);
308 $newParts[] = $parts[0];
311 $partsSliced = array_slice($parts, 1, null,
true);
312 foreach ($partsSliced as $v) {
313 $tagLen = strcspn(substr($content, $pointer),
'>') + 1;
316 $tag = substr($content, $pointer, $tagLen);
318 $pointer += strlen($tag);
321 $pointer += strlen($v);
335 public function getAllParts($parts, $tag_parts =
true, $include_tag =
true)
338 foreach ($parts as $k => $v) {
339 if (($k + ($tag_parts ? 0 : 1)) % 2) {
341 $v = $this->removeFirstAndLastTag($v);
356 public function removeFirstAndLastTag($str)
359 $start = strpos($str,
'>');
361 $end = strrpos($str,
'<');
363 return substr($str, $start + 1, $end - $start - 1);
373 public function getFirstTag($str)
376 $endLen = strpos($str,
'>');
377 return $endLen !==
false ? substr($str, 0, $endLen + 1) :
'';
388 public function getFirstTagName($str, $preserveCase =
false)
391 if (preg_match(
'/^\\s*\\<([^\\s\\>]+)(\\s|\\>)/', $str, $matches) === 1) {
392 if (!$preserveCase) {
393 return strtoupper($matches[1]);
408 public function get_tag_attributes($tag, $deHSC = 0)
410 list($components, $metaC) = $this->split_tag_attributes($tag);
414 $attributes = array();
415 $attributesMeta = array();
416 if (is_array($components)) {
417 foreach ($components as $key => $val) {
422 $attributes[$name] = $deHSC ? htmlspecialchars_decode($val) : $val;
423 $attributesMeta[$name][
'dashType'] = $metaC[$key];
427 if ($namekey = preg_replace(
'/[^[:alnum:]_\\:\\-]/',
'', $val)) {
428 $name = strtolower($namekey);
429 $attributesMeta[$name] = array();
430 $attributesMeta[$name][
'origTag'] = $namekey;
431 $attributes[$name] =
'';
439 return array($attributes, $attributesMeta);
452 public function split_tag_attributes($tag)
455 if (preg_match(
'/(\\<[^\\s]+\\s+)?(.*?)\\s*(\\>)?$/s', $tag, $matches) !== 1) {
456 return array(array(), array());
458 $tag_tmp = $matches[2];
459 $metaValue = array();
462 if (preg_match_all(
'/("[^"]*"|\'[^\']*\'|[^\\s"\'\\=]+|\\=)/s', $tag_tmp, $matches) > 0) {
463 foreach ($matches[1] as $part) {
464 $firstChar = $part[0];
465 if ($firstChar ==
'"' || $firstChar ==
'\'') {
466 $metaValue[] = $firstChar;
467 $value[] = substr($part, 1, -1);
474 return array($value, $metaValue);
490 public function checkTagTypeCounts($content, $blockTags =
'a,b,blockquote,body,div,em,font,form,h1,h2,h3,h4,h5,h6,i,li,map,ol,option,p,pre,select,span,strong,table,td,textarea,tr,u,ul', $soloTags =
'br,hr,img,input,area')
492 $content = strtolower($content);
493 $analyzedOutput = array();
495 $analyzedOutput[
'counts'] = array();
497 $analyzedOutput[
'errors'] = array();
499 $analyzedOutput[
'warnings'] = array();
501 $analyzedOutput[
'blocks'] = array();
503 $analyzedOutput[
'solo'] = array();
505 $blockTags = explode(
',', $blockTags);
506 foreach ($blockTags as $tagName) {
507 $countBegin = count(preg_split((
'/\\<' . preg_quote($tagName,
'/') .
'(\\s|\\>)/s'), $content)) - 1;
508 $countEnd = count(preg_split((
'/\\<\\/' . preg_quote($tagName,
'/') .
'(\\s|\\>)/s'), $content)) - 1;
509 $analyzedOutput[
'blocks'][$tagName] = array($countBegin, $countEnd, $countBegin - $countEnd);
511 $analyzedOutput[
'counts'][$tagName] = $countBegin;
513 if ($countBegin - $countEnd) {
514 if ($countBegin - $countEnd > 0) {
515 $analyzedOutput[
'errors'][$tagName] =
'There were more start-tags (' . $countBegin .
') than end-tags (' . $countEnd .
') for the element "' . $tagName .
'". There should be an equal amount!';
517 $analyzedOutput[
'warnings'][$tagName] =
'There were more end-tags (' . $countEnd .
') than start-tags (' . $countBegin .
') for the element "' . $tagName .
'". There should be an equal amount! However the problem is not fatal.';
522 $soloTags = explode(
',', $soloTags);
523 foreach ($soloTags as $tagName) {
524 $countBegin = count(preg_split((
'/\\<' . preg_quote($tagName,
'/') .
'(\\s|\\>)/s'), $content)) - 1;
525 $countEnd = count(preg_split((
'/\\<\\/' . preg_quote($tagName,
'/') .
'(\\s|\\>)/s'), $content)) - 1;
526 $analyzedOutput[
'solo'][$tagName] = array($countBegin, $countEnd);
528 $analyzedOutput[
'counts'][$tagName] = $countBegin;
531 $analyzedOutput[
'warnings'][$tagName] =
'There were end-tags found (' . $countEnd .
') for the element "' . $tagName .
'". This was not expected (although XHTML technically allows it).';
534 return $analyzedOutput;
578 public function HTMLcleaner($content, $tags = array(), $keepAll = 0, $hSC = 0, $addConfig = array())
580 $newContent = array();
581 $tokArr = explode(
'<', $content);
582 $newContent[] = $this->processContent(current($tokArr), $hSC, $addConfig);
584 $tokArrSliced = array_slice($tokArr, 1, null,
true);
586 $tagRegister = array();
591 foreach ($tokArrSliced as $tok) {
593 if (($eocPos = strpos($tok,
'-->')) ===
false) {
595 $newContent[$c++] =
'<' . $tok;
599 $newContent[$c++] =
'<' . substr($tok, 0, ($eocPos + 3));
600 $tok = substr($tok, $eocPos + 3);
604 if (($eocPos = strpos($tok,
'/*]]>*/')) ===
false) {
606 $newContent[$c++] =
'<' . $tok;
610 $newContent[$c++] =
'<' . substr($tok, 0, $eocPos + 10);
611 $tok = substr($tok, $eocPos + 10);
614 }
elseif (substr($tok, 0, 3) ==
'!--') {
615 if (($eocPos = strpos($tok,
'-->')) ===
false) {
617 $newContent[$c++] =
'<' . $tok;
622 $newContent[$c++] =
'<' . substr($tok, 0, ($eocPos + 3));
623 $tok = substr($tok, $eocPos + 3);
625 }
elseif (substr($tok, 0, 10) ===
'![CDATA[*/') {
626 if (($eocPos = strpos($tok,
'/*]]>*/')) ===
false) {
628 $newContent[$c++] =
'<' . $tok;
633 $newContent[$c++] =
'<' . substr($tok, 0, $eocPos + 10);
634 $tok = substr($tok, $eocPos + 10);
637 $firstChar = $tok[0];
639 if (!$skipTag && preg_match(
'/[[:alnum:]\\/]/', $firstChar) == 1) {
640 $tagEnd = strpos($tok,
'>');
643 $endTag = $firstChar ==
'/' ? 1 : 0;
644 $tagContent = substr($tok, $endTag, $tagEnd - $endTag);
645 $tagParts = preg_split(
'/\\s+/s', $tagContent, 2);
646 $tagName = strtolower($tagParts[0]);
648 if (isset($tags[$tagName])) {
650 if (is_array($tags[$tagName])) {
651 if (preg_match(
'/^(' . self::VOID_ELEMENTS .
' )$/i', $tagName)) {
657 if ((
string)$tags[$tagName][
'overrideAttribs'] !==
'') {
658 $tagParts[1] = $tags[$tagName][
'overrideAttribs'];
661 if ((
string)$tags[$tagName][
'allowedAttribs'] !==
'') {
663 if ((
string)$tags[$tagName][
'allowedAttribs'] ===
'0') {
665 }
elseif (trim($tagParts[1])) {
666 $tagAttrib = $this->get_tag_attributes($tagParts[1]);
668 $newTagAttrib = array();
669 if (!($tList = $tags[$tagName][
'_allowedAttribs'])) {
671 $tList = ($tags[$tagName][
'_allowedAttribs'] = GeneralUtility::trimExplode(
',', strtolower($tags[$tagName][
'allowedAttribs']),
true));
673 foreach ($tList as $allowTag) {
674 if (isset($tagAttrib[0][$allowTag])) {
675 $newTagAttrib[$allowTag] = $tagAttrib[0][$allowTag];
678 $tagParts[1] = $this->compileTagAttribs($newTagAttrib, $tagAttrib[1]);
682 if (is_array($tags[$tagName][
'fixAttrib'])) {
683 $tagAttrib = $this->get_tag_attributes($tagParts[1]);
685 foreach ($tags[$tagName][
'fixAttrib'] as $attr => $params) {
686 if (isset($params[
'set']) && $params[
'set'] !==
'') {
687 $tagAttrib[0][$attr] = $params[
'set'];
689 if (!empty($params[
'unset'])) {
690 unset($tagAttrib[0][$attr]);
692 if (!isset($tagAttrib[0][$attr]) && (
string)$params[
'default'] !==
'') {
693 $tagAttrib[0][$attr] = $params[
'default'];
695 if ($params[
'always'] || isset($tagAttrib[0][$attr])) {
696 if ($params[
'trim']) {
697 $tagAttrib[0][$attr] = trim($tagAttrib[0][$attr]);
699 if ($params[
'intval']) {
700 $tagAttrib[0][$attr] = (int)$tagAttrib[0][$attr];
702 if ($params[
'lower']) {
703 $tagAttrib[0][$attr] = strtolower($tagAttrib[0][$attr]);
705 if ($params[
'upper']) {
706 $tagAttrib[0][$attr] = strtoupper($tagAttrib[0][$attr]);
708 if ($params[
'range']) {
709 if (isset($params[
'range'][1])) {
710 $tagAttrib[0][$attr] = \TYPO3\CMS\Core\Utility\MathUtility::forceIntegerInRange($tagAttrib[0][$attr], (
int)$params[
'range'][0], (
int)$params[
'range'][1]);
712 $tagAttrib[0][$attr] = \TYPO3\CMS\Core\Utility\MathUtility::forceIntegerInRange($tagAttrib[0][$attr], (
int)$params[
'range'][0]);
715 if (is_array($params[
'list'])) {
718 if ($attr ==
'class') {
719 $newClasses = array();
720 $classes = GeneralUtility::trimExplode(
' ', $tagAttrib[0][$attr],
true);
721 foreach ($classes as $class) {
722 if (in_array($class, $params[
'list'])) {
723 $newClasses[] = $class;
726 if (!empty($newClasses)) {
727 $tagAttrib[0][$attr] = implode(
' ', $newClasses);
729 $tagAttrib[0][$attr] = $params[
'list'][0];
732 if (!in_array($this->caseShift($tagAttrib[0][$attr], $params[
'casesensitiveComp']), $this->caseShift($params[
'list'], $params[
'casesensitiveComp'], $tagName))) {
733 $tagAttrib[0][$attr] = $params[
'list'][0];
737 if ($params[
'removeIfFalse'] && $params[
'removeIfFalse'] !=
'blank' && !$tagAttrib[0][$attr] || $params[
'removeIfFalse'] ==
'blank' && (
string)$tagAttrib[0][$attr] ===
'') {
738 unset($tagAttrib[0][$attr]);
740 if ((
string)$params[
'removeIfEquals'] !==
'' && $this->caseShift($tagAttrib[0][$attr], $params[
'casesensitiveComp']) === $this->caseShift($params[
'removeIfEquals'], $params[
'casesensitiveComp'])) {
741 unset($tagAttrib[0][$attr]);
743 if ($params[
'prefixLocalAnchors']) {
744 if ($tagAttrib[0][$attr][0] ===
'#') {
745 if ($params[
'prefixLocalAnchors'] == 2) {
747 $contentObjectRenderer = GeneralUtility::makeInstance(\TYPO3\CMS\Frontend\ContentObject\ContentObjectRenderer::class);
748 $prefix = $contentObjectRenderer->getUrlToCurrentLocation();
750 $prefix = GeneralUtility::getIndpEnv(
'TYPO3_REQUEST_URL');
752 $tagAttrib[0][$attr] = $prefix . $tagAttrib[0][$attr];
755 if ($params[
'prefixRelPathWith']) {
756 $urlParts = parse_url($tagAttrib[0][$attr]);
757 if (!$urlParts[
'scheme'] && $urlParts[
'path'][0] !==
'/') {
759 $tagAttrib[0][$attr] = $params[
'prefixRelPathWith'] . $tagAttrib[0][$attr];
762 if ($params[
'userFunc']) {
763 if (is_array($params[
'userFunc.'])) {
764 $params[
'userFunc.'][
'attributeValue'] = $tagAttrib[0][$attr];
766 $params[
'userFunc.'] = $tagAttrib[0][$attr];
768 $tagAttrib[0][$attr] = GeneralUtility::callUserFunction($params[
'userFunc'], $params[
'userFunc.'], $this);
772 $tagParts[1] = $this->compileTagAttribs($tagAttrib[0], $tagAttrib[1]);
779 if ($tags[$tagName][
'protect']) {
787 if ($tags[$tagName][
'remap']) {
788 $tagParts[0] = $tags[$tagName][
'remap'];
791 if ($endTag || trim($tagParts[1]) || !$tags[$tagName][
'rmTagIfNoAttrib']) {
794 if ($endTag && $tags[$tagName][
'allowedAttribs'] === 0 && $tags[$tagName][
'rmTagIfNoAttrib'] === 1) {
797 if ($tags[$tagName][
'nesting']) {
798 if (!is_array($tagRegister[$tagName])) {
799 $tagRegister[$tagName] = array();
803 if ($tags[$tagName][
'nesting'] ==
'global') {
804 $lastEl = end($tagStack);
805 if ($tagName !== $lastEl) {
806 if (in_array($tagName, $tagStack)) {
807 while (!empty($tagStack) && $tagName !== $lastEl) {
808 $elPos = end($tagRegister[$lastEl]);
809 unset($newContent[$elPos]);
810 array_pop($tagRegister[$lastEl]);
811 array_pop($tagStack);
812 $lastEl = end($tagStack);
820 if (empty($tagRegister[$tagName]) || !$correctTag) {
823 array_pop($tagRegister[$tagName]);
824 if ($tags[$tagName][
'nesting'] ==
'global') {
825 array_pop($tagStack);
829 array_push($tagRegister[$tagName], $c);
830 if ($tags[$tagName][
'nesting'] ==
'global') {
831 array_push($tagStack, $tagName);
837 $newContent[$c++] = $this->processTag($lt . ($endTag ?
'/' :
'') . trim($tagParts[0] .
' ' . $tagParts[1]) . ($emptyTag ?
' /' :
'') . $gt, $addConfig, $endTag, $lt ==
'<');
841 $newContent[$c++] = $this->processTag(
'<' . ($endTag ?
'/' :
'') . $tagContent .
'>', $addConfig, $endTag);
845 if ($keepAll ===
'protect') {
852 $newContent[$c++] = $this->processTag($lt . ($endTag ?
'/' :
'') . $tagContent . $gt, $addConfig, $endTag, $lt ==
'<');
854 $newContent[$c++] = $this->processContent(substr($tok, $tagEnd + 1), $hSC, $addConfig);
856 $newContent[$c++] = $this->processContent(
'<' . $tok, $hSC, $addConfig);
859 $newContent[$c++] = $this->processContent(($skipTag ?
'' :
'<') . $tok, $hSC, $addConfig);
865 foreach ($tagRegister as $tag => $positions) {
866 foreach ($positions as $pKey) {
867 unset($newContent[$pKey]);
870 $newContent = implode(
'', $newContent);
871 $newContent = $this->stripEmptyTagsIfConfigured($newContent, $addConfig);
882 public function bidir_htmlspecialchars($value, $dir)
886 $value = htmlspecialchars($value);
888 $value = htmlspecialchars($value, ENT_COMPAT,
'UTF-8',
false);
890 $value = htmlspecialchars_decode($value);
904 public function prefixResourcePath($main_prefix, $content, $alternatives = array(), $suffix =
'')
906 $parts = $this->splitTags(
'embed,td,table,body,img,input,form,link,script,a,param', $content);
907 foreach ($parts as $k => $v) {
909 $params = $this->get_tag_attributes($v);
911 $tagEnd = substr($v, -2) ==
'/>' ?
' />' :
'>';
913 $firstTagName = $this->getFirstTagName($v);
915 $prefix = isset($alternatives[strtoupper($firstTagName)]) ? $alternatives[strtoupper($firstTagName)] : $main_prefix;
916 switch (strtolower($firstTagName)) {
922 $src = $params[0][
'background'];
924 $params[0][
'background'] = $this->prefixRelPath($prefix, $params[0][
'background'], $suffix);
935 $src = $params[0][
'src'];
937 $params[0][
'src'] = $this->prefixRelPath($prefix, $params[0][
'src'], $suffix);
944 $src = $params[0][
'href'];
946 $params[0][
'href'] = $this->prefixRelPath($prefix, $params[0][
'href'], $suffix);
951 $src = $params[0][
'action'];
953 $params[0][
'action'] = $this->prefixRelPath($prefix, $params[0][
'action'], $suffix);
958 $test = $params[0][
'name'];
959 if ($test && $test ===
'movie') {
960 if ($params[0][
'value']) {
961 $params[0][
'value'] = $this->prefixRelPath($prefix, $params[0][
'value'], $suffix);
967 if ($somethingDone) {
968 $tagParts = preg_split(
'/\\s+/s', $v, 2);
969 $tagParts[1] = $this->compileTagAttribs($params[0], $params[1]);
970 $parts[$k] =
'<' . trim(strtolower($firstTagName) .
' ' . $tagParts[1]) . $tagEnd;
974 $content = implode(
'', $parts);
976 $prefix = isset($alternatives[
'style']) ? $alternatives[
'style'] : $main_prefix;
977 if ((
string)$prefix !==
'') {
978 $parts = $this->splitIntoBlock(
'style', $content);
979 foreach ($parts as $k => &$part) {
981 $part = preg_replace(
'/(url[[:space:]]*\\([[:space:]]*["\']?)([^"\')]*)(["\']?[[:space:]]*\\))/i',
'\\1' . $prefix .
'\\2' . $suffix .
'\\3', $part);
985 $content = implode(
'', $parts);
999 public function prefixRelPath($prefix, $srcVal, $suffix =
'')
1003 if ($srcVal[0] !==
'/' && $srcVal[0] !==
'#') {
1004 $urlParts = parse_url($srcVal);
1006 if (!$urlParts[
'scheme']) {
1007 $srcVal = $prefix . $srcVal . $suffix;
1023 public function cleanFontTags($value, $keepFace = 0, $keepSize = 0, $keepColor = 0)
1026 $fontSplit = $this->splitIntoBlock(
'font', $value);
1027 foreach ($fontSplit as $k => $v) {
1030 $attribArray = $this->get_tag_attributes_classic($this->getFirstTag($v));
1031 $newAttribs = array();
1032 if ($keepFace && $attribArray[
'face']) {
1033 $newAttribs[] =
'face="' . $attribArray[
'face'] .
'"';
1035 if ($keepSize && $attribArray[
'size']) {
1036 $newAttribs[] =
'size="' . $attribArray[
'size'] .
'"';
1038 if ($keepColor && $attribArray[
'color']) {
1039 $newAttribs[] =
'color="' . $attribArray[
'color'] .
'"';
1041 $innerContent = $this->cleanFontTags($this->removeFirstAndLastTag($v), $keepFace, $keepSize, $keepColor);
1042 if (!empty($newAttribs)) {
1043 $fontSplit[$k] =
'<font ' . implode(
' ', $newAttribs) .
'>' . $innerContent .
'</font>';
1045 $fontSplit[$k] = $innerContent;
1049 return implode(
'', $fontSplit);
1061 public function mapTags($value, $tags = array(), $ltChar =
'<', $ltChar2 =
'<')
1063 foreach ($tags as $from => $to) {
1064 $value = preg_replace(
'/' . preg_quote($ltChar,
'/') .
'(\\/)?' . $from .
'\\s([^\\>])*(\\/)?\\>/', $ltChar2 .
'$1' . $to .
' $2$3>', $value);
1076 public function unprotectTags($content, $tagList =
'')
1078 $tagsArray = GeneralUtility::trimExplode(
',', $tagList,
true);
1079 $contentParts = explode(
'<', $content);
1081 $contentPartsSliced = array_slice($contentParts, 1, null,
true);
1082 foreach ($contentPartsSliced as $k => $tok) {
1083 $firstChar = $tok[0];
1084 if (trim($firstChar) !==
'') {
1085 $subparts = explode(
'>', $tok, 2);
1086 $tagEnd = strlen($subparts[0]);
1087 if (strlen($tok) != $tagEnd) {
1088 $endTag = $firstChar ==
'/' ? 1 : 0;
1089 $tagContent = substr($tok, $endTag, $tagEnd - $endTag);
1090 $tagParts = preg_split(
'/\\s+/s', $tagContent, 2);
1091 $tagName = strtolower($tagParts[0]);
1092 if ((
string)$tagList ===
'' || in_array($tagName, $tagsArray)) {
1093 $contentParts[$k] =
'<' . $subparts[0] .
'>' . $subparts[1];
1095 $contentParts[$k] =
'<' . $tok;
1098 $contentParts[$k] =
'<' . $tok;
1101 $contentParts[$k] =
'<' . $tok;
1104 return implode(
'', $contentParts);
1116 public function caseShift($str, $flag, $cacheKey =
'')
1118 $cacheKey .= $flag ? 1 : 0;
1119 if (is_array($str)) {
1120 if (!$cacheKey || !isset($this->caseShift_cache[$cacheKey])) {
1121 foreach ($str as &$v) {
1123 $v = strtoupper($v);
1128 $this->caseShift_cache[$cacheKey] = $str;
1131 $str = $this->caseShift_cache[$cacheKey];
1134 $str = strtoupper($str);
1148 public function compileTagAttribs($tagAttrib, $meta = array(), $xhtmlClean = 0)
1151 foreach ($tagAttrib as $k => $v) {
1153 $attr = strtolower($k);
1154 if ((
string)$v !==
'' || isset($meta[$k][
'dashType'])) {
1155 $attr .=
'="' . htmlspecialchars($v) .
'"';
1158 $attr = $meta[$k][
'origTag'] ?: $k;
1159 if (strcmp($v,
'') || isset($meta[$k][
'dashType'])) {
1160 $dash = $meta[$k][
'dashType'] ?: (\TYPO3\CMS\Core\Utility\MathUtility::canBeInterpretedAsInteger($v) ?
'' :
'"');
1161 $attr .=
'=' . $dash . $v . $dash;
1166 return implode(
' ', $accu);
1177 public function get_tag_attributes_classic($tag, $deHSC = 0)
1179 $attr = $this->get_tag_attributes($tag, $deHSC);
1180 return is_array($attr[0]) ? $attr[0] : array();
1191 public function indentLines($content, $number = 1, $indentChar = TAB)
1193 $preTab = str_pad(
'', $number * strlen($indentChar), $indentChar);
1194 $lines = explode(LF, str_replace(CR,
'', $content));
1195 foreach ($lines as &$line) {
1196 $line = $preTab . $line;
1199 return implode(LF, $lines);
1210 public function HTMLparserConfig($TSconfig, $keepTags = array())
1213 $alTags = array_flip(GeneralUtility::trimExplode(
',', strtolower($TSconfig[
'allowTags']),
true));
1214 $keepTags = array_merge($alTags, $keepTags);
1216 if (is_array($TSconfig[
'tags.'])) {
1217 foreach ($TSconfig[
'tags.'] as $key => $tagC) {
1218 if (!is_array($tagC) && $key == strtolower($key)) {
1219 if ((
string)$tagC ===
'0') {
1220 unset($keepTags[$key]);
1222 if ((
string)$tagC ===
'1' && !isset($keepTags[$key])) {
1223 $keepTags[$key] = 1;
1227 foreach ($TSconfig[
'tags.'] as $key => $tagC) {
1228 if (is_array($tagC) && $key == strtolower($key)) {
1229 $key = substr($key, 0, -1);
1230 if (!is_array($keepTags[$key])) {
1231 $keepTags[$key] = array();
1233 if (is_array($tagC[
'fixAttrib.'])) {
1234 foreach ($tagC[
'fixAttrib.'] as $atName => $atConfig) {
1235 if (is_array($atConfig)) {
1236 $atName = substr($atName, 0, -1);
1237 if (!is_array($keepTags[$key][
'fixAttrib'][$atName])) {
1238 $keepTags[$key][
'fixAttrib'][$atName] = array();
1240 $keepTags[$key][
'fixAttrib'][$atName] = array_merge($keepTags[$key][
'fixAttrib'][$atName], $atConfig);
1241 if ((
string)$keepTags[$key][
'fixAttrib'][$atName][
'range'] !==
'') {
1242 $keepTags[$key][
'fixAttrib'][$atName][
'range'] = GeneralUtility::trimExplode(
',', $keepTags[$key][
'fixAttrib'][$atName][
'range']);
1244 if ((
string)$keepTags[$key][
'fixAttrib'][$atName][
'list'] !==
'') {
1245 $keepTags[$key][
'fixAttrib'][$atName][
'list'] = GeneralUtility::trimExplode(
',', $keepTags[$key][
'fixAttrib'][$atName][
'list']);
1250 unset($tagC[
'fixAttrib.']);
1251 unset($tagC[
'fixAttrib']);
1252 if (isset($tagC[
'rmTagIfNoAttrib']) && $tagC[
'rmTagIfNoAttrib'] && empty($tagC[
'nesting'])) {
1253 $tagC[
'nesting'] = 1;
1255 $keepTags[$key] = array_merge($keepTags[$key], $tagC);
1260 if ($TSconfig[
'localNesting']) {
1261 $lN = GeneralUtility::trimExplode(
',', strtolower($TSconfig[
'localNesting']),
true);
1262 foreach ($lN as $tn) {
1263 if (isset($keepTags[$tn])) {
1264 if (!is_array($keepTags[$tn])) {
1265 $keepTags[$tn] = array();
1267 $keepTags[$tn][
'nesting'] = 1;
1271 if ($TSconfig[
'globalNesting']) {
1272 $lN = GeneralUtility::trimExplode(
',', strtolower($TSconfig[
'globalNesting']),
true);
1273 foreach ($lN as $tn) {
1274 if (isset($keepTags[$tn])) {
1275 if (!is_array($keepTags[$tn])) {
1276 $keepTags[$tn] = array();
1278 $keepTags[$tn][
'nesting'] =
'global';
1282 if ($TSconfig[
'rmTagIfNoAttrib']) {
1283 $lN = GeneralUtility::trimExplode(
',', strtolower($TSconfig[
'rmTagIfNoAttrib']),
true);
1284 foreach ($lN as $tn) {
1285 if (isset($keepTags[$tn])) {
1286 if (!is_array($keepTags[$tn])) {
1287 $keepTags[$tn] = array();
1289 $keepTags[$tn][
'rmTagIfNoAttrib'] = 1;
1290 if (empty($keepTags[$tn][
'nesting'])) {
1291 $keepTags[$tn][
'nesting'] = 1;
1296 if ($TSconfig[
'noAttrib']) {
1297 $lN = GeneralUtility::trimExplode(
',', strtolower($TSconfig[
'noAttrib']),
true);
1298 foreach ($lN as $tn) {
1299 if (isset($keepTags[$tn])) {
1300 if (!is_array($keepTags[$tn])) {
1301 $keepTags[$tn] = array();
1303 $keepTags[$tn][
'allowedAttribs'] = 0;
1307 if ($TSconfig[
'removeTags']) {
1308 $lN = GeneralUtility::trimExplode(
',', strtolower($TSconfig[
'removeTags']),
true);
1309 foreach ($lN as $tn) {
1310 $keepTags[$tn] = array();
1311 $keepTags[$tn][
'allowedAttribs'] = 0;
1312 $keepTags[$tn][
'rmTagIfNoAttrib'] = 1;
1316 $addConfig = array();
1317 if ($TSconfig[
'xhtml_cleaning']) {
1318 $addConfig[
'xhtml'] = 1;
1320 if (isset($TSconfig[
'stripEmptyTags'])) {
1321 $addConfig[
'stripEmptyTags'] = $TSconfig[
'stripEmptyTags'];
1322 if (isset($TSconfig[
'stripEmptyTags.'])) {
1323 $addConfig[
'stripEmptyTags.'] = $TSconfig[
'stripEmptyTags.'];
1328 '' . $TSconfig[
'keepNonMatchedTags'],
1329 (
int)$TSconfig[
'htmlSpecialChars'],
1360 public function XHTML_clean($content)
1362 GeneralUtility::logDeprecatedFunction(
'TYPO3\CMS\Core\Html\HtmlParser::XHTML_clean has been deprecated with TYPO3 CMS 7 and will be removed with TYPO3 CMS 8.');
1363 return $this->HTMLcleaner($content, array(), 1, 0, array(
'xhtml' => 1));
1377 public function processTag($value, $conf, $endTag, $protected = 0)
1380 if ($protected || empty($conf)) {
1385 if ($conf[
'xhtml']) {
1386 GeneralUtility::deprecationLog(
'This section has been deprecated with TYPO3 CMS 7 and will be removed with CMS 8.');
1389 $value = strtolower($value);
1390 }
elseif (substr($value, 0, 4) !=
'<!--') {
1393 $inValue = substr($value, 1, substr($value, -2) ==
'/>' ? -2 : -1);
1395 list($tagName, $tagP) = preg_split(
'/\\s+/s', $inValue, 2);
1396 $tagName = strtolower($tagName);
1398 $tagAttrib = $this->get_tag_attributes($tagP);
1399 if ($tagName ===
'img' && !isset($tagAttrib[0][
'alt'])) {
1400 $tagAttrib[0][
'alt'] =
'';
1403 if ($tagName ===
'script' && !isset($tagAttrib[0][
'type'])) {
1404 $tagAttrib[0][
'type'] =
'text/javascript';
1408 foreach ($tagAttrib[0] as $attrib_name => $attrib_value) {
1410 $outA[] = $attrib_name .
'="' . $this->bidir_htmlspecialchars($attrib_value, 2) .
'"';
1412 $newTag =
'<' . trim($tagName .
' ' . implode(
' ', $outA));
1414 if (GeneralUtility::inList(
'img,br,hr,meta,link,base,area,input,param,col', $tagName) || substr($value, -2) ==
'/>') {
1434 public function processContent($value, $dir, $conf)
1437 $value = $this->bidir_htmlspecialchars($value, $dir);
1451 public function stripEmptyTags($content, $tagList = null, $treatNonBreakingSpaceAsEmpty =
false)
1453 $tagRegEx =
'[^ >]+';
1455 $tags = preg_split(
'/,/', $tagList);
1456 $tagRegEx = preg_replace(
'/ */',
'', join(
'|', $tags));
1459 $nbspRegex = $treatNonBreakingSpaceAsEmpty ?
'|( )' :
'';
1460 while ($count != 0) {
1461 $content = preg_replace(sprintf(
'/<(%s)[^>]*>( %s)*<\/\\1[^>]*>/i', $tagRegEx, $nbspRegex),
'', $content, -1, $count);
1473 protected function stripEmptyTagsIfConfigured($value, $configuration)
1475 if (isset($configuration[
'stripEmptyTags']) && $configuration[
'stripEmptyTags']) {
1478 isset($configuration[
'stripEmptyTags.'][
'tags'])
1479 && $configuration[
'stripEmptyTags.'][
'tags'] !==
''
1481 $tags = $configuration[
'stripEmptyTags.'][
'tags'];
1484 $treatNonBreakingSpaceAsEmpty =
false;
1486 isset($configuration[
'stripEmptyTags.'][
'treatNonBreakingSpaceAsEmpty'])
1487 && $configuration[
'stripEmptyTags.'][
'treatNonBreakingSpaceAsEmpty']
1489 $treatNonBreakingSpaceAsEmpty = (bool)$configuration[
'stripEmptyTags.'][
'treatNonBreakingSpaceAsEmpty'];
1493 $value = $this->stripEmptyTags($value, $tags, $treatNonBreakingSpaceAsEmpty);