| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262 | 
							- <?php
 
- /**
 
-  * @copyright Copyright (c) 2014 Carsten Brandt
 
-  * @license https://github.com/cebe/markdown/blob/master/LICENSE
 
-  * @link https://github.com/cebe/markdown#readme
 
-  */
 
- namespace cebe\markdown\inline;
 
- // work around https://github.com/facebook/hhvm/issues/1120
 
- defined('ENT_HTML401') || define('ENT_HTML401', 0);
 
- /**
 
-  * Addes links and images as well as url markers.
 
-  *
 
-  * This trait conflicts with the HtmlTrait. If both are used together,
 
-  * you have to define a resolution, by defining the HtmlTrait::parseInlineHtml
 
-  * as private so it is not used directly:
 
-  *
 
-  * ```php
 
-  * use block\HtmlTrait {
 
-  *     parseInlineHtml as private parseInlineHtml;
 
-  * }
 
-  * ```
 
-  *
 
-  * If the method exists it is called internally by this trait.
 
-  *
 
-  * Also make sure to reset references on prepare():
 
-  *
 
-  * ```php
 
-  * protected function prepare()
 
-  * {
 
-  *     // reset references
 
-  *     $this->references = [];
 
-  * }
 
-  * ```
 
-  */
 
- trait LinkTrait
 
- {
 
- 	/**
 
- 	 * @var array a list of defined references in this document.
 
- 	 */
 
- 	protected $references = [];
 
- 	/**
 
- 	 * Parses a link indicated by `[`.
 
- 	 * @marker [
 
- 	 */
 
- 	protected function parseLink($markdown)
 
- 	{
 
- 		if (!in_array('parseLink', array_slice($this->context, 1)) && ($parts = $this->parseLinkOrImage($markdown)) !== false) {
 
- 			list($text, $url, $title, $offset, $key) = $parts;
 
- 			return [
 
- 				[
 
- 					'link',
 
- 					'text' => $this->parseInline($text),
 
- 					'url' => $url,
 
- 					'title' => $title,
 
- 					'refkey' => $key,
 
- 					'orig' => substr($markdown, 0, $offset),
 
- 				],
 
- 				$offset
 
- 			];
 
- 		} else {
 
- 			// remove all starting [ markers to avoid next one to be parsed as link
 
- 			$result = '[';
 
- 			$i = 1;
 
- 			while (isset($markdown[$i]) && $markdown[$i] == '[') {
 
- 				$result .= '[';
 
- 				$i++;
 
- 			}
 
- 			return [['text', $result], $i];
 
- 		}
 
- 	}
 
- 	/**
 
- 	 * Parses an image indicated by `![`.
 
- 	 * @marker ![
 
- 	 */
 
- 	protected function parseImage($markdown)
 
- 	{
 
- 		if (($parts = $this->parseLinkOrImage(substr($markdown, 1))) !== false) {
 
- 			list($text, $url, $title, $offset, $key) = $parts;
 
- 			return [
 
- 				[
 
- 					'image',
 
- 					'text' => $text,
 
- 					'url' => $url,
 
- 					'title' => $title,
 
- 					'refkey' => $key,
 
- 					'orig' => substr($markdown, 0, $offset + 1),
 
- 				],
 
- 				$offset + 1
 
- 			];
 
- 		} else {
 
- 			// remove all starting [ markers to avoid next one to be parsed as link
 
- 			$result = '!';
 
- 			$i = 1;
 
- 			while (isset($markdown[$i]) && $markdown[$i] == '[') {
 
- 				$result .= '[';
 
- 				$i++;
 
- 			}
 
- 			return [['text', $result], $i];
 
- 		}
 
- 	}
 
- 	protected function parseLinkOrImage($markdown)
 
- 	{
 
- 		if (strpos($markdown, ']') !== false && preg_match('/\[((?>[^\]\[]+|(?R))*)\]/', $markdown, $textMatches)) { // TODO improve bracket regex
 
- 			$text = $textMatches[1];
 
- 			$offset = strlen($textMatches[0]);
 
- 			$markdown = substr($markdown, $offset);
 
- 			$pattern = <<<REGEXP
 
- 				/(?(R) # in case of recursion match parentheses
 
- 					 \(((?>[^\s()]+)|(?R))*\)
 
- 				|      # else match a link with title
 
- 					^\((((?>[^\s()]+)|(?R))*)(\s+"(.*?)")?\)
 
- 				)/x
 
- REGEXP;
 
- 			if (preg_match($pattern, $markdown, $refMatches)) {
 
- 				// inline link
 
- 				return [
 
- 					$text,
 
- 					isset($refMatches[2]) ? $refMatches[2] : '', // url
 
- 					empty($refMatches[5]) ? null: $refMatches[5], // title
 
- 					$offset + strlen($refMatches[0]), // offset
 
- 					null, // reference key
 
- 				];
 
- 			} elseif (preg_match('/^([ \n]?\[(.*?)\])?/s', $markdown, $refMatches)) {
 
- 				// reference style link
 
- 				if (empty($refMatches[2])) {
 
- 					$key = strtolower($text);
 
- 				} else {
 
- 					$key = strtolower($refMatches[2]);
 
- 				}
 
- 				return [
 
- 					$text,
 
- 					null, // url
 
- 					null, // title
 
- 					$offset + strlen($refMatches[0]), // offset
 
- 					$key,
 
- 				];
 
- 			}
 
- 		}
 
- 		return false;
 
- 	}
 
- 	/**
 
- 	 * Parses inline HTML.
 
- 	 * @marker <
 
- 	 */
 
- 	protected function parseLt($text)
 
- 	{
 
- 		if (strpos($text, '>') !== false) {
 
- 			if (!in_array('parseLink', $this->context)) { // do not allow links in links
 
- 				if (preg_match('/^<([^\s]*?@[^\s]*?\.\w+?)>/', $text, $matches)) {
 
- 					// email address
 
- 					return [
 
- 						['email', $matches[1]],
 
- 						strlen($matches[0])
 
- 					];
 
- 				} elseif (preg_match('/^<([a-z]{3,}:\/\/[^\s]+?)>/', $text, $matches)) {
 
- 					// URL
 
- 					return [
 
- 						['url', $matches[1]],
 
- 						strlen($matches[0])
 
- 					];
 
- 				}
 
- 			}
 
- 			// try inline HTML if it was neither a URL nor email if HtmlTrait is included.
 
- 			if (method_exists($this, 'parseInlineHtml')) {
 
- 				return $this->parseInlineHtml($text);
 
- 			}
 
- 		}
 
- 		return [['text', '<'], 1];
 
- 	}
 
- 	protected function renderEmail($block)
 
- 	{
 
- 		$email = htmlspecialchars($block[1], ENT_NOQUOTES | ENT_SUBSTITUTE, 'UTF-8');
 
- 		return "<a href=\"mailto:$email\">$email</a>";
 
- 	}
 
- 	protected function renderUrl($block)
 
- 	{
 
- 		$url = htmlspecialchars($block[1], ENT_COMPAT | ENT_HTML401, 'UTF-8');
 
- 		$text = htmlspecialchars(urldecode($block[1]), ENT_NOQUOTES | ENT_SUBSTITUTE, 'UTF-8');
 
- 		return "<a href=\"$url\">$text</a>";
 
- 	}
 
- 	protected function lookupReference($key)
 
- 	{
 
- 		$normalizedKey = preg_replace('/\s+/', ' ', $key);
 
- 		if (isset($this->references[$key]) || isset($this->references[$key = $normalizedKey])) {
 
- 			return $this->references[$key];
 
- 		}
 
- 		return false;
 
- 	}
 
- 	protected function renderLink($block)
 
- 	{
 
- 		if (isset($block['refkey'])) {
 
- 			if (($ref = $this->lookupReference($block['refkey'])) !== false) {
 
- 				$block = array_merge($block, $ref);
 
- 			} else {
 
- 				return $block['orig'];
 
- 			}
 
- 		}
 
- 		return '<a href="' . htmlspecialchars($block['url'], ENT_COMPAT | ENT_HTML401, 'UTF-8') . '"'
 
- 			. (empty($block['title']) ? '' : ' title="' . htmlspecialchars($block['title'], ENT_COMPAT | ENT_HTML401 | ENT_SUBSTITUTE, 'UTF-8') . '"')
 
- 			. '>' . $this->renderAbsy($block['text']) . '</a>';
 
- 	}
 
- 	protected function renderImage($block)
 
- 	{
 
- 		if (isset($block['refkey'])) {
 
- 			if (($ref = $this->lookupReference($block['refkey'])) !== false) {
 
- 				$block = array_merge($block, $ref);
 
- 			} else {
 
- 				return $block['orig'];
 
- 			}
 
- 		}
 
- 		return '<img src="' . htmlspecialchars($block['url'], ENT_COMPAT | ENT_HTML401, 'UTF-8') . '"'
 
- 			. ' alt="' . htmlspecialchars($block['text'], ENT_COMPAT | ENT_HTML401 | ENT_SUBSTITUTE, 'UTF-8') . '"'
 
- 			. (empty($block['title']) ? '' : ' title="' . htmlspecialchars($block['title'], ENT_COMPAT | ENT_HTML401 | ENT_SUBSTITUTE, 'UTF-8') . '"')
 
- 			. ($this->html5 ? '>' : ' />');
 
- 	}
 
- 	// references
 
- 	protected function identifyReference($line)
 
- 	{
 
- 		return isset($line[0]) && ($line[0] === ' ' || $line[0] === '[') && preg_match('/^ {0,3}\[[^\[](.*?)\]:\s*([^\s]+?)(?:\s+[\'"](.+?)[\'"])?\s*$/', $line);
 
- 	}
 
- 	/**
 
- 	 * Consume link references
 
- 	 */
 
- 	protected function consumeReference($lines, $current)
 
- 	{
 
- 		while (isset($lines[$current]) && preg_match('/^ {0,3}\[(.+?)\]:\s*(.+?)(?:\s+[\(\'"](.+?)[\)\'"])?\s*$/', $lines[$current], $matches)) {
 
- 			$label = strtolower($matches[1]);
 
- 			$this->references[$label] = [
 
- 				'url' => $matches[2],
 
- 			];
 
- 			if (isset($matches[3])) {
 
- 				$this->references[$label]['title'] = $matches[3];
 
- 			} else {
 
- 				// title may be on the next line
 
- 				if (isset($lines[$current + 1]) && preg_match('/^\s+[\(\'"](.+?)[\)\'"]\s*$/', $lines[$current + 1], $matches)) {
 
- 					$this->references[$label]['title'] = $matches[1];
 
- 					$current++;
 
- 				}
 
- 			}
 
- 			$current++;
 
- 		}
 
- 		return [false, --$current];
 
- 	}
 
- }
 
 
  |