/** * Add the given icon to the TCA table type * * @param string $table * @param string $type * @param string $icon */ public static function addTcaTypeIcon($table, $type, $icon) { if (GeneralUtility::compat_version('7.0')) { $fullIconPath = substr(PathUtility::getAbsoluteWebPath($icon), 1); if (StringUtility::endsWith(strtolower($fullIconPath), 'svg')) { $iconProviderClass = 'TYPO3\\CMS\\Core\\Imaging\\IconProvider\\SvgIconProvider'; } else { $iconProviderClass = 'TYPO3\\CMS\\Core\\Imaging\\IconProvider\\BitmapIconProvider'; } /** @var IconRegistry $iconRegistry */ $iconRegistry = GeneralUtility::makeInstance('TYPO3\\CMS\\Core\\Imaging\\IconRegistry'); $iconIdentifier = 'tcarecords-' . $table . '-' . $type; $iconRegistry->registerIcon($iconIdentifier, $iconProviderClass, ['source' => $fullIconPath]); $GLOBALS['TCA']['tt_content']['ctrl']['typeicon_classes'][$type] = $iconIdentifier; } else { $fullIconPath = str_replace('../typo3/', '', $icon); SpriteManager::addTcaTypeIcon('tt_content', $type, $fullIconPath); } }
/** * Helper function for parseFunc() * * @param string $theValue The value to process. * @param array $conf TypoScript configuration for parseFunc * @return string The processed value * @access private * @see parseFunc() */ public function _parseFunc($theValue, $conf) { if (!empty($conf['if.']) && !$this->checkIf($conf['if.'])) { return $theValue; } // Indicates that the data is from within a tag. $inside = 0; // Pointer to the total string position $pointer = 0; // Loaded with the current typo-tag if any. $currentTag = ''; $stripNL = 0; $contentAccum = array(); $contentAccumP = 0; $allowTags = strtolower(str_replace(' ', '', $conf['allowTags'])); $denyTags = strtolower(str_replace(' ', '', $conf['denyTags'])); $totalLen = strlen($theValue); do { if (!$inside) { if (!is_array($currentTag)) { // These operations should only be performed on code outside the typotags... // data: this checks that we enter tags ONLY if the first char in the tag is alphanumeric OR '/' $len_p = 0; $c = 100; do { $len = strcspn(substr($theValue, $pointer + $len_p), '<'); $len_p += $len + 1; $endChar = ord(strtolower(substr($theValue, $pointer + $len_p, 1))); $c--; } while ($c > 0 && $endChar && ($endChar < 97 || $endChar > 122) && $endChar != 47); $len = $len_p - 1; } else { // If we're inside a currentTag, just take it to the end of that tag! $tempContent = strtolower(substr($theValue, $pointer)); $len = strpos($tempContent, '</' . $currentTag[0]); if (is_string($len) && !$len) { $len = strlen($tempContent); } } // $data is the content until the next <tag-start or end is detected. // In case of a currentTag set, this would mean all data between the start- and end-tags $data = substr($theValue, $pointer, $len); if ($data != '') { if ($stripNL) { // If the previous tag was set to strip NewLines in the beginning of the next data-chunk. $data = preg_replace('/^[ ]*' . CR . '?' . LF . '/', '', $data); } // These operations should only be performed on code outside the tags... if (!is_array($currentTag)) { // Constants $tsfe = $this->getTypoScriptFrontendController(); $tmpConstants = $tsfe->tmpl->setup['constants.']; if ($conf['constants'] && is_array($tmpConstants)) { foreach ($tmpConstants as $key => $val) { if (is_string($val)) { $data = str_replace('###' . $key . '###', $val, $data); } } } // Short if (is_array($conf['short.'])) { $shortWords = $conf['short.']; krsort($shortWords); foreach ($shortWords as $key => $val) { if (is_string($val)) { $data = str_replace($key, $val, $data); } } } // stdWrap if (is_array($conf['plainTextStdWrap.'])) { $data = $this->stdWrap($data, $conf['plainTextStdWrap.']); } // userFunc if ($conf['userFunc']) { $data = $this->callUserFunction($conf['userFunc'], $conf['userFunc.'], $data); } // Makelinks: (Before search-words as we need the links to be generated when searchwords go on...!) if ($conf['makelinks']) { $data = $this->http_makelinks($data, $conf['makelinks.']['http.']); $data = $this->mailto_makelinks($data, $conf['makelinks.']['mailto.']); } // Search Words: if ($tsfe->no_cache && $conf['sword'] && is_array($tsfe->sWordList) && $tsfe->sWordRegEx) { $newstring = ''; do { $pregSplitMode = 'i'; if (isset($tsfe->config['config']['sword_noMixedCase']) && !empty($tsfe->config['config']['sword_noMixedCase'])) { $pregSplitMode = ''; } $pieces = preg_split('/' . $tsfe->sWordRegEx . '/' . $pregSplitMode, $data, 2); $newstring .= $pieces[0]; $match_len = strlen($data) - (strlen($pieces[0]) + strlen($pieces[1])); $inTag = false; if (strstr($pieces[0], '<') || strstr($pieces[0], '>')) { // Returns TRUE, if a '<' is closer to the string-end than '>'. // This is the case if we're INSIDE a tag (that could have been // made by makelinks...) and we must secure, that the inside of a tag is // not marked up. $inTag = strrpos($pieces[0], '<') > strrpos($pieces[0], '>'); } // The searchword: $match = substr($data, strlen($pieces[0]), $match_len); if (trim($match) && strlen($match) > 1 && !$inTag) { $match = $this->wrap($match, $conf['sword']); } // Concatenate the Search Word again. $newstring .= $match; $data = $pieces[1]; } while ($pieces[1]); $data = $newstring; } } $contentAccum[$contentAccumP] .= $data; } $inside = 1; } else { // tags $len = strcspn(substr($theValue, $pointer), '>') + 1; $data = substr($theValue, $pointer, $len); if (StringUtility::endsWith($data, '/>') && !StringUtility::beginsWith($data, '<link ')) { $tagContent = substr($data, 1, -2); } else { $tagContent = substr($data, 1, -1); } $tag = explode(' ', trim($tagContent), 2); $tag[0] = strtolower($tag[0]); if ($tag[0][0] === '/') { $tag[0] = substr($tag[0], 1); $tag['out'] = 1; } if ($conf['tags.'][$tag[0]]) { $treated = false; $stripNL = false; // in-tag if (!$currentTag && !$tag['out']) { // $currentTag (array!) is the tag we are currently processing $currentTag = $tag; $contentAccumP++; $treated = true; // in-out-tag: img and other empty tags if (preg_match('/^(area|base|br|col|hr|img|input|meta|param)$/i', $tag[0])) { $tag['out'] = 1; } } // out-tag if ($currentTag[0] === $tag[0] && $tag['out']) { $theName = $conf['tags.'][$tag[0]]; $theConf = $conf['tags.'][$tag[0] . '.']; // This flag indicates, that NL- (13-10-chars) should be stripped first and last. $stripNL = (bool) $theConf['stripNL']; // This flag indicates, that this TypoTag section should NOT be included in the nonTypoTag content. $breakOut = $theConf['breakoutTypoTagContent'] ? 1 : 0; $this->parameters = array(); if ($currentTag[1]) { $params = GeneralUtility::get_tag_attributes($currentTag[1]); if (is_array($params)) { foreach ($params as $option => $val) { $this->parameters[strtolower($option)] = $val; } } } $this->parameters['allParams'] = trim($currentTag[1]); // Removes NL in the beginning and end of the tag-content AND at the end of the currentTagBuffer. // $stripNL depends on the configuration of the current tag if ($stripNL) { $contentAccum[$contentAccumP - 1] = preg_replace('/' . CR . '?' . LF . '[ ]*$/', '', $contentAccum[$contentAccumP - 1]); $contentAccum[$contentAccumP] = preg_replace('/^[ ]*' . CR . '?' . LF . '/', '', $contentAccum[$contentAccumP]); $contentAccum[$contentAccumP] = preg_replace('/' . CR . '?' . LF . '[ ]*$/', '', $contentAccum[$contentAccumP]); } $this->data[$this->currentValKey] = $contentAccum[$contentAccumP]; $newInput = $this->cObjGetSingle($theName, $theConf, '/parseFunc/.tags.' . $tag[0]); // fetch the content object $contentAccum[$contentAccumP] = $newInput; $contentAccumP++; // If the TypoTag section if (!$breakOut) { $contentAccum[$contentAccumP - 2] .= $contentAccum[$contentAccumP - 1] . $contentAccum[$contentAccumP]; unset($contentAccum[$contentAccumP]); unset($contentAccum[$contentAccumP - 1]); $contentAccumP -= 2; } unset($currentTag); $treated = true; } // other tags if (!$treated) { $contentAccum[$contentAccumP] .= $data; } } else { // If a tag was not a typo tag, then it is just added to the content $stripNL = false; if (GeneralUtility::inList($allowTags, $tag[0]) || $denyTags != '*' && !GeneralUtility::inList($denyTags, $tag[0])) { $contentAccum[$contentAccumP] .= $data; } else { $contentAccum[$contentAccumP] .= HTMLSpecialChars($data); } } $inside = 0; } $pointer += $len; } while ($pointer < $totalLen); // Parsing nonTypoTag content (all even keys): reset($contentAccum); $contentAccumCount = count($contentAccum); for ($a = 0; $a < $contentAccumCount; $a++) { if ($a % 2 != 1) { // stdWrap if (is_array($conf['nonTypoTagStdWrap.'])) { $contentAccum[$a] = $this->stdWrap($contentAccum[$a], $conf['nonTypoTagStdWrap.']); } // userFunc if ($conf['nonTypoTagUserFunc']) { $contentAccum[$a] = $this->callUserFunction($conf['nonTypoTagUserFunc'], $conf['nonTypoTagUserFunc.'], $contentAccum[$a]); } } } return implode('', $contentAccum); }
/** * @test * @dataProvider endsWithReturnsThrowsExceptionWithInvalidArgumentsDataProvider * @expectedException \InvalidArgumentException */ public function endsWithReturnsThrowsExceptionWithInvalidArguments($string, $part) { StringUtility::endsWith($string, $part); }
/** * Gets the current GIT revision and branch * * @return void */ protected function getGitRevision() { if (!StringUtility::endsWith(TYPO3_version, '-dev') || \TYPO3\CMS\Core\Core\SystemEnvironmentBuilder::isFunctionDisabled('exec')) { return; } // check if git exists CommandUtility::exec('git --version', $_, $returnCode); if ((int) $returnCode !== 0) { // git is not available return; } $revision = trim(CommandUtility::exec('git rev-parse --short HEAD')); $branch = trim(CommandUtility::exec('git rev-parse --abbrev-ref HEAD')); if (!empty($revision) && !empty($branch)) { $this->systemInformation[] = array('title' => htmlspecialchars($this->getLanguageService()->sL('LLL:EXT:lang/locallang_core.xlf:toolbarItems.sysinfo.gitrevision')), 'value' => sprintf('%s [%s]', $revision, $branch), 'icon' => $this->iconFactory->getIcon('sysinfo-git', Icon::SIZE_SMALL)->render()); } }
/** * Renders the $icon, supports a filename for skinImg or sprite-icon-name * * @param string $icon The icon passed, could be a file-reference or a sprite Icon name * @param string $alt Alt attribute of the icon returned * @param string $title Title attribute of the icon return * @return string A tag representing to show the asked icon * @internal */ public static function getIconHtml($icon, $alt = '', $title = '') { $icon = (string) $icon; $iconFile = ''; $iconInfo = false; if (StringUtility::beginsWith($icon, 'EXT:')) { $absoluteFilePath = GeneralUtility::getFileAbsFileName($icon); if (!empty($absoluteFilePath)) { $iconFile = '../' . PathUtility::stripPathSitePrefix($absoluteFilePath); $iconInfo = StringUtility::endsWith($absoluteFilePath, '.svg') ? true : getimagesize($absoluteFilePath); } } elseif (StringUtility::beginsWith($icon, '../')) { // @TODO: this is special modList, files from folders and selicon $iconFile = GeneralUtility::resolveBackPath($icon); if (is_file(PATH_site . GeneralUtility::resolveBackPath(substr($icon, 3)))) { $iconInfo = StringUtility::endsWith($icon, '.svg') ? true : getimagesize(PATH_site . GeneralUtility::resolveBackPath(substr($icon, 3))); } } if ($iconInfo !== false && is_file(GeneralUtility::resolveBackPath(PATH_typo3 . $iconFile))) { return '<img' . ' src="' . htmlspecialchars($iconFile) . '"' . ' alt="' . htmlspecialchars($alt) . '" ' . ($title ? 'title="' . htmlspecialchars($title) . '"' : '') . ' />'; } $iconFactory = GeneralUtility::makeInstance(IconFactory::class); return '<span alt="' . htmlspecialchars($alt) . '" title="' . htmlspecialchars($title) . '">' . $iconFactory->getIcon($icon, Icon::SIZE_SMALL)->render() . '</span>'; }
/** * Detect the IconProvider of an icon * * @param string $iconReference * @return string */ protected function detectIconProvider($iconReference) { if (StringUtility::endsWith(strtolower($iconReference), 'svg')) { return SvgIconProvider::class; } else { return BitmapIconProvider::class; } }
/** * Load icons from TCA for each table and add them as "tcarecords-XX" to $this->icons */ protected function registerTCAIcons() { // if TCA is not available, e.g. for some unit test, return directly if (!is_array($GLOBALS['TCA'])) { return; } $resultArray = array(); $tcaTables = array_keys($GLOBALS['TCA']); // check every table in the TCA, if an icon is needed foreach ($tcaTables as $tableName) { // This method is only needed for TCA tables where typeicon_classes are not configured if (is_array($GLOBALS['TCA'][$tableName])) { $tcaCtrl = $GLOBALS['TCA'][$tableName]['ctrl']; $icon = null; $iconIdentifier = 'tcarecords-' . $tableName . '-default'; if ($this->isRegistered($iconIdentifier)) { continue; } if (isset($tcaCtrl['iconfile'])) { if (StringUtility::beginsWith($tcaCtrl['iconfile'], 'EXT:')) { $icon = $tcaCtrl['iconfile']; } elseif (strpos($tcaCtrl['iconfile'], '/') !== false) { $icon = TYPO3_mainDir . GeneralUtility::resolveBackPath($tcaCtrl['iconfile']); } if ($icon !== null) { $resultArray[$iconIdentifier] = $icon; } } } } if (!empty($GLOBALS['TBE_STYLES']['spritemanager']['singleIcons'])) { foreach ($GLOBALS['TBE_STYLES']['spritemanager']['singleIcons'] as $iconIdentifier => $iconFile) { if (StringUtility::beginsWith($iconFile, '../typo3conf/ext/')) { $iconFile = str_replace('../typo3conf/ext/', 'EXT:', $iconFile); } if (StringUtility::beginsWith($iconFile, 'sysext/')) { $iconFile = str_replace('sysext/', 'EXT:', $iconFile); } $resultArray[$iconIdentifier] = $iconFile; } } foreach ($resultArray as $iconIdentifier => $iconFilePath) { if (StringUtility::endsWith(strtolower($iconFilePath), 'svg')) { $iconProviderClass = SvgIconProvider::class; } else { $iconProviderClass = BitmapIconProvider::class; } $this->icons[$iconIdentifier] = array('provider' => $iconProviderClass, 'options' => array('source' => $iconFilePath)); } $this->tcaInitialized = true; }
/** * Applies stdWrap on Fluid path definitions * * @param array $paths * * @return array */ protected function applyStandardWrapToFluidPaths(array $paths) { $finalPaths = []; foreach ($paths as $key => $path) { if (StringUtility::endsWith($key, '.')) { if (isset($paths[substr($key, 0, -1)])) { continue; } $path = $this->cObj->stdWrap('', $path); } elseif (isset($paths[$key . '.'])) { $path = $this->cObj->stdWrap($path, $paths[$key . '.']); } $finalPaths[$key] = GeneralUtility::getFileAbsFileName($path); } return $finalPaths; }
/** * Renders the $icon, supports a filename for skinImg or sprite-icon-name * * @param string $icon The icon passed, could be a file-reference or a sprite Icon name * @param string $alt Alt attribute of the icon returned * @param string $title Title attribute of the icon return * @return string A tag representing to show the asked icon * @internal */ public static function getIconHtml($icon, $alt = '', $title = '') { $icon = (string) $icon; $absoluteFilePath = GeneralUtility::getFileAbsFileName($icon); if (!empty($absoluteFilePath) && is_file($absoluteFilePath)) { $iconInfo = StringUtility::endsWith($absoluteFilePath, '.svg') ? true : getimagesize($absoluteFilePath); if ($iconInfo !== false) { return '<img' . ' src="' . htmlspecialchars(PathUtility::getAbsoluteWebPath($absoluteFilePath)) . '"' . ' alt="' . htmlspecialchars($alt) . '" ' . ($title ? 'title="' . htmlspecialchars($title) . '"' : '') . ' />'; } } $iconFactory = GeneralUtility::makeInstance(IconFactory::class); return '<span alt="' . htmlspecialchars($alt) . '" title="' . htmlspecialchars($title) . '">' . $iconFactory->getIcon($icon, Icon::SIZE_SMALL)->render() . '</span>'; }