<commit_before><?php
namespace wcf\system\html\output\node;
use wcf\data\smiley\Smiley;
use wcf\data\smiley\SmileyCache;
use wcf\system\application\ApplicationHandler;
use wcf\system\html\node\AbstractHtmlNodeProcessor;
use wcf\system\request\LinkHandler;
use wcf\system\request\RouteHandler;
use wcf\system\WCF;
use wcf\util\exception\CryptoException;
use wcf\util\CryptoUtil;
use wcf\util\DOMUtil;
use wcf\util\StringUtil;
use wcf\util\Url;

/**
 * Processes images.
 * 
 * @author      <NAME>
 * @copyright   2001-2018 WoltLab GmbH
 * @license     GNU Lesser General Public License <http://opensource.org/licenses/lgpl-license.php>
 * @package     WoltLabSuite\Core\System\Html\Output\Node
 * @since       3.0
 */
class HtmlOutputNodeImg extends AbstractHtmlOutputNode {
	/**
	 * @inheritDoc
	 */
	protected $tagName = 'img';
	
	/**
	 * @inheritDoc
	 */
	public function process(array $elements, AbstractHtmlNodeProcessor $htmlNodeProcessor) {
		/** @var \DOMElement $element */
		foreach ($elements as $element) {
			$class = $element->getAttribute('class');
			if (preg_match('~\bsmiley\b~', $class)) {
				$code = $element->getAttribute('alt');
				
				/** @var Smiley $smiley */
				$smiley = SmileyCache::getInstance()->getSmileyByCode($code);
				if ($smiley === null || $this->outputType === 'text/plain') {
					// output as raw code instead
					$htmlNodeProcessor->replaceElementWithText($element, ' ' . $code . ' ', false);
				}
				else {
					// enforce database values for src, srcset and style
					$element->setAttribute('src', $smiley->getURL());
					
					if ($smiley->getHeight()) $element->setAttribute('height', $smiley->getHeight());
					else $element->removeAttribute('height');
					
					if ($smiley->smileyPath2x) $element->setAttribute('srcset', $smiley->getURL2x() . ' 2x');
					else $element->removeAttribute('srcset');
					
					$element->setAttribute('title', WCF::getLanguage()->get($smiley->smileyTitle));
				}
			}
			else {
				$src = $element->getAttribute('src');
				if (!$src) {
					DOMUtil::removeNode($element);
					continue;
				}
				
				$class = $element->getAttribute('class');
				if ($class) $class .= ' ';
				$class .= 'jsResizeImage';
				$element->setAttribute('class', $class);
				
				if (MODULE_IMAGE_PROXY) {
					if (!Url::is($src)) {
						// not a valid URL, discard it
						DOMUtil::removeNode($element);
						continue;
					}
					
					$urlComponents = Url::parse($src);
					if (empty($urlComponents['host'])) {
						// relative URL, ignore it
						continue;
					}
					
					if (IMAGE_PROXY_INSECURE_ONLY && $urlComponents['scheme'] === 'https') {
						// proxy is enabled for insecure connections only
						if (!IMAGE_ALLOW_EXTERNAL_SOURCE && !$this->isAllowedOrigin($src)) {
							$this->replaceExternalSource($element, $src);
						}
						
						continue;
					}
					
					if ($this->bypassProxy($urlComponents['host'])) {
						// check if page was requested over a secure connection
						// but the link is insecure
						if ((MESSAGE_FORCE_SECURE_IMAGES || RouteHandler::secureConnection()) && $urlComponents['scheme'] === 'http') {
							// rewrite protocol to `https`
							$element->setAttribute('src', preg_replace('~^http~', 'https', $src));
						}
						
						continue;
					}
					
					$element->setAttribute('data-valid', 'true');
					
					if (!empty($urlComponents['path']) && preg_match('~\.svg~', basename($urlComponents['path']))) {
						// we can't proxy SVG, ignore it
						continue;
					}
					
					$element->setAttribute('src', $this->getProxyLink($src));
					
					$srcset = $element->getAttribute('srcset');
					if ($srcset) {
						// simplified regex to check if it appears to be a valid list of sources
						if (!preg_match('~^[^\s]+\s+[0-9\.]+[wx](,\s*[^\s]+\s+[0-9\.]+[wx])*~', $srcset)) {
							$element->removeAttribute('srcset');
							continue;
						}
						
						$sources = explode(',', $srcset);
						$srcset = '';
						foreach ($sources as $source) {
							$tmp = preg_split('~\s+~', StringUtil::trim($source));
							if (count($tmp) === 2) {
								if (!empty($srcset)) $srcset .= ', ';
								$srcset .= $this->getProxyLink($tmp[0]) . ' ' . $tmp[1];
							}
						}
						
						$element->setAttribute('srcset', $srcset);
					}
				}
				else if (!IMAGE_ALLOW_EXTERNAL_SOURCE && !$this->isAllowedOrigin($src)) {
					$this->replaceExternalSource($element, $src);
				}
				else if (MESSAGE_FORCE_SECURE_IMAGES && Url::parse($src)['scheme'] === 'http') {
					// rewrite protocol to `https`
					$element->setAttribute('src', preg_replace('~^http~', 'https', $src));
				}
			}
		}
	}
	
	/**
	 * Replaces images embedded from external sources that are not handled by the image proxy.
	 * 
	 * @param       \DOMElement     $element
	 * @param       string          $src
	 */
	protected function replaceExternalSource(\DOMElement $element, $src) {
		$element->parentNode->insertBefore($element->ownerDocument->createTextNode('['.WCF::getLanguage()->get('wcf.bbcode.image.blocked').': '), $element);
		
		$link = $element->ownerDocument->createElement('a');
		$link->setAttribute('href', $src);
		$link->textContent = $src;
		HtmlOutputNodeA::markLinkAsExternal($link);
		
		$element->parentNode->insertBefore($link, $element);
		<commit_msg>Fix markup for linked, blocked images in UGC<commit_after><?php
namespace wcf\system\html\output\node;
use wcf\data\smiley\Smiley;
use wcf\data\smiley\SmileyCache;
use wcf\system\application\ApplicationHandler;
use wcf\system\html\node\AbstractHtmlNodeProcessor;
use wcf\system\request\LinkHandler;
use wcf\system\request\RouteHandler;
use wcf\system\WCF;
use wcf\util\exception\CryptoException;
use wcf\util\CryptoUtil;
use wcf\util\DOMUtil;
use wcf\util\StringUtil;
use wcf\util\Url;

/**
 * Processes images.
 * 
 * @author      <NAME>
 * @copyright   2001-2018 WoltLab GmbH
 * @license     GNU Lesser General Public License <http://opensource.org/licenses/lgpl-license.php>
 * @package     WoltLabSuite\Core\System\Html\Output\Node
 * @since       3.0
 */
class HtmlOutputNodeImg extends AbstractHtmlOutputNode {
	/**
	 * @inheritDoc
	 */
	protected $tagName = 'img';
	
	/**
	 * @inheritDoc
	 */
	public function process(array $elements, AbstractHtmlNodeProcessor $htmlNodeProcessor) {
		/** @var \DOMElement $element */
		foreach ($elements as $element) {
			$class = $element->getAttribute('class');
			if (preg_match('~\bsmiley\b~', $class)) {
				$code = $element->getAttribute('alt');
				
				/** @var Smiley $smiley */
				$smiley = SmileyCache::getInstance()->getSmileyByCode($code);
				if ($smiley === null || $this->outputType === 'text/plain') {
					// output as raw code instead
					$htmlNodeProcessor->replaceElementWithText($element, ' ' . $code . ' ', false);
				}
				else {
					// enforce database values for src, srcset and style
					$element->setAttribute('src', $smiley->getURL());
					
					if ($smiley->getHeight()) $element->setAttribute('height', $smiley->getHeight());
					else $element->removeAttribute('height');
					
					if ($smiley->smileyPath2x) $element->setAttribute('srcset', $smiley->getURL2x() . ' 2x');
					else $element->removeAttribute('srcset');
					
					$element->setAttribute('title', WCF::getLanguage()->get($smiley->smileyTitle));
				}
			}
			else {
				$src = $element->getAttribute('src');
				if (!$src) {
					DOMUtil::removeNode($element);
					continue;
				}
				
				$class = $element->getAttribute('class');
				if ($class) $class .= ' ';
				$class .= 'jsResizeImage';
				$element->setAttribute('class', $class);
				
				if (MODULE_IMAGE_PROXY) {
					if (!Url::is($src)) {
						// not a valid URL, discard it
						DOMUtil::removeNode($element);
						continue;
					}
					
					$urlComponents = Url::parse($src);
					if (empty($urlComponents['host'])) {
						// relative URL, ignore it
						continue;
					}
					
					if (IMAGE_PROXY_INSECURE_ONLY && $urlComponents['scheme'] === 'https') {
						// proxy is enabled for insecure connections only
						if (!IMAGE_ALLOW_EXTERNAL_SOURCE && !$this->isAllowedOrigin($src)) {
							$this->replaceExternalSource($element, $src);
						}
						
						continue;
					}
					
					if ($this->bypassProxy($urlComponents['host'])) {
						// check if page was requested over a secure connection
						// but the link is insecure
						if ((MESSAGE_FORCE_SECURE_IMAGES || RouteHandler::secureConnection()) && $urlComponents['scheme'] === 'http') {
							// rewrite protocol to `https`
							$element->setAttribute('src', preg_replace('~^http~', 'https', $src));
						}
						
						continue;
					}
					
					$element->setAttribute('data-valid', 'true');
					
					if (!empty($urlComponents['path']) && preg_match('~\.svg~', basename($urlComponents['path']))) {
						// we can't proxy SVG, ignore it
						continue;
					}
					
					$element->setAttribute('src', $this->getProxyLink($src));
					
					$srcset = $element->getAttribute('srcset');
					if ($srcset) {
						// simplified regex to check if it appears to be a valid list of sources
						if (!preg_match('~^[^\s]+\s+[0-9\.]+[wx](,\s*[^\s]+\s+[0-9\.]+[wx])*~', $srcset)) {
							$element->removeAttribute('srcset');
							continue;
						}
						
						$sources = explode(',', $srcset);
						$srcset = '';
						foreach ($sources as $source) {
							$tmp = preg_split('~\s+~', StringUtil::trim($source));
							if (count($tmp) === 2) {
								if (!empty($srcset)) $srcset .= ', ';
								$srcset .= $this->getProxyLink($tmp[0]) . ' ' . $tmp[1];
							}
						}
						
						$element->setAttribute('srcset', $srcset);
					}
				}
				else if (!IMAGE_ALLOW_EXTERNAL_SOURCE && !$this->isAllowedOrigin($src)) {
					$this->replaceExternalSource($element, $src);
				}
				else if (MESSAGE_FORCE_SECURE_IMAGES && Url::parse($src)['scheme'] === 'http') {
					// rewrite protocol to `https`
					$element->setAttribute('src', preg_replace('~^http~', 'https', $src));
				}
			}
		}
	}
	
	/**
	 * Replaces images embedded from external sources that are not handled by the image proxy.
	 * 
	 * @param       \DOMElement     $element
	 * @param       string          $src
	 */
	protected function replaceExternalSource(\DOMElement $element, $src) {
		$element->parentNode->insertBefore($element->ownerDocument->createTextNode('['.WCF::getLanguage()->get('wcf.bbcode.image.blocked').': '), $element);
		
		if (!DOMUtil::hasParent($element, 'a')) {
			$link = $element->ownerDocument->createElement('a');
			$link->setAttribute('href', $src);
			$link->textContent = $src;
			HtmlOutputNodeA::markLinkAsExternal($link);
		}
		else {
			$link = $element->ownerDocument->createTextNode($src);
		}
		
		$element->parentNode->insertBefore($link, $element);
		
{'fraction_non_alphanumeric': 0.17728712502329047, 'fraction_numerical': 0.003726476616359232, 'mean_word_length': 3.103593272171254, 'pattern_counts': {'":': 0, '<': 9, '<?xml version=': 0, '>': 101, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '3959622', 'n_tokens_mistral': 4336, 'n_tokens_neox': 3347, 'n_words': 649}