1<?php 2namespace TYPO3\CMS\Frontend\ContentObject; 3 4/* 5 * This file is part of the TYPO3 CMS project. 6 * 7 * It is free software; you can redistribute it and/or modify it under 8 * the terms of the GNU General Public License, either version 2 9 * of the License, or any later version. 10 * 11 * For the full copyright and license information, please read the 12 * LICENSE.txt file that was distributed with this source code. 13 * 14 * The TYPO3 project - inspiring people to share! 15 */ 16 17use TYPO3\CMS\Core\Utility\GeneralUtility; 18use TYPO3\CMS\Core\Utility\PathUtility; 19 20/** 21 * Contains SVG content object. 22 */ 23class ScalableVectorGraphicsContentObject extends AbstractContentObject 24{ 25 /** 26 * Rendering the cObject, SVG 27 * 28 * @param array $conf Array of TypoScript properties 29 * @return string 30 */ 31 public function render($conf = []): string 32 { 33 $renderMode = isset($conf['renderMode.']) 34 ? $this->cObj->stdWrap($conf['renderMode'], $conf['renderMode.']) 35 : $conf['renderMode']; 36 37 if ($renderMode === 'inline') { 38 return $this->renderInline($conf); 39 } 40 41 return $this->renderObject($conf); 42 } 43 44 /** 45 * @param array $conf 46 * 47 * @return string 48 */ 49 protected function renderInline(array $conf): string 50 { 51 $src = $this->resolveAbsoluteSourcePath($conf); 52 list($width, $height, $isDefaultWidth, $isDefaultHeight) = $this->getDimensions($conf); 53 54 $content = ''; 55 if (file_exists($src)) { 56 $svgContent = file_get_contents($src); 57 $svgContent = preg_replace('/<script[\s\S]*?>[\s\S]*?<\/script>/i', '', $svgContent); 58 // Disables the functionality to allow external entities to be loaded when parsing the XML, must be kept 59 $previousValueOfEntityLoader = libxml_disable_entity_loader(); 60 $svgElement = simplexml_load_string($svgContent); 61 libxml_disable_entity_loader($previousValueOfEntityLoader); 62 63 $domXml = dom_import_simplexml($svgElement); 64 if (!$isDefaultWidth) { 65 $domXml->setAttribute('width', $width); 66 } 67 if (!$isDefaultHeight) { 68 $domXml->setAttribute('height', $height); 69 } 70 // remove xml version tag 71 $content = $domXml->ownerDocument->saveXML($domXml->ownerDocument->documentElement); 72 } else { 73 $value = isset($conf['value.']) ? $this->cObj->stdWrap($conf['value'], $conf['value.']) : $conf['value']; 74 if (!empty($value)) { 75 $content = []; 76 $content[] = '<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="' . (int)$width . '" height="' . (int)$height . '">'; 77 $content[] = $value; 78 $content[] = '</svg>'; 79 $content = implode(LF, $content); 80 } 81 } 82 if (isset($conf['stdWrap.'])) { 83 $content = $this->cObj->stdWrap($content, $conf['stdWrap.']); 84 } 85 return $content; 86 } 87 88 /** 89 * Render the SVG as <object> tag 90 * @param array $conf 91 * 92 * @return string 93 */ 94 protected function renderObject(array $conf): string 95 { 96 $src = $this->resolveAbsoluteSourcePath($conf); 97 list($width, $height) = $this->getDimensions($conf); 98 99 $src = $src === '' ? null : PathUtility::getAbsoluteWebPath($src); 100 101 $value = isset($conf['value.']) ? $this->cObj->stdWrap($conf['value'], $conf['value.']) : $conf['value']; 102 $noscript = isset($conf['noscript.']) ? $this->cObj->stdWrap($conf['noscript'], $conf['noscript.']) : $conf['noscript']; 103 104 // @deprecated since TYPO3 v9, will be removed in TYPO3 v10.0 - see method usages 105 if (!empty($conf['noscript.']) || !empty($conf['noscript'])) { 106 trigger_error('SVG cObject: The option "noscript" will be removed in TYPO3 v10.0.', E_USER_DEPRECATED); 107 } 108 if (!empty($conf['value.']) || !empty($conf['value'])) { 109 trigger_error('SVG cObject: The option "value" without setting renderMode=inline will be removed in TYPO3 v10.0.', E_USER_DEPRECATED); 110 } 111 112 $content = []; 113 if ($src) { 114 $content[] = '<!--[if IE]>'; 115 $content[] = ' <object src="' . htmlspecialchars($src) . '" classid="image/svg+xml" width="' . (int)$width . '" height="' . (int)$height . '">'; 116 $content[] = '<![endif]-->'; 117 $content[] = '<!--[if !IE]>-->'; 118 $content[] = ' <object data="' . htmlspecialchars($src) . '" type="image/svg+xml" width="' . (int)$width . '" height="' . (int)$height . '">'; 119 $content[] = '<!--<![endif]-->'; 120 $content[] = $noscript; 121 $content[] = '</object>'; 122 } else { 123 // @deprecated since TYPO3 v9, will be removed in TYPO3 v10.0 - see method usages 124 $content[] = '<script type="image/svg+xml">'; 125 $content[] = ' <svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="' . (int)$width . '" height="' . (int)$height . '">'; 126 $content[] = $value; 127 $content[] = ' </svg>'; 128 $content[] = '</script>'; 129 $content[] = '<noscript>'; 130 $content[] = $noscript; 131 $content[] = '</noscript>'; 132 } 133 $content = implode(LF, $content); 134 if (isset($conf['stdWrap.'])) { 135 $content = $this->cObj->stdWrap($content, $conf['stdWrap.']); 136 } 137 return $content; 138 } 139 140 /** 141 * @param array $conf 142 * 143 * @return string 144 */ 145 protected function resolveAbsoluteSourcePath(array $conf): string 146 { 147 $src = isset($conf['src.']) ? $this->cObj->stdWrap($conf['src'], $conf['src.']) : $conf['src']; 148 return GeneralUtility::getFileAbsFileName($src); 149 } 150 151 /** 152 * @param array $conf 153 * 154 * @return array 155 */ 156 protected function getDimensions(array $conf): array 157 { 158 $isDefaultWidth = false; 159 $isDefaultHeight = false; 160 $width = isset($conf['width.']) ? $this->cObj->stdWrap($conf['width'], $conf['width.']) : $conf['width']; 161 $height = isset($conf['height.']) ? $this->cObj->stdWrap($conf['height'], $conf['height.']) : $conf['height']; 162 163 if (empty($width)) { 164 $isDefaultWidth = true; 165 $width = 600; 166 } 167 if (empty($height)) { 168 $isDefaultHeight = true; 169 $height = 400; 170 } 171 172 return [$width, $height, $isDefaultWidth, $isDefaultHeight]; 173 } 174} 175