Issues (16)

Security Analysis    no request data  

This project does not seem to handle request data directly as such no vulnerable execution paths were found.

  Cross-Site Scripting
Cross-Site Scripting enables an attacker to inject code into the response of a web-request that is viewed by other users. It can for example be used to bypass access controls, or even to take over other users' accounts.
  File Exposure
File Exposure allows an attacker to gain access to local files that he should not be able to access. These files can for example include database credentials, or other configuration files.
  File Manipulation
File Manipulation enables an attacker to write custom data to files. This potentially leads to injection of arbitrary code on the server.
  Object Injection
Object Injection enables an attacker to inject an object into PHP code, and can lead to arbitrary code execution, file exposure, or file manipulation attacks.
  Code Injection
Code Injection enables an attacker to execute arbitrary code on the server.
  Response Splitting
Response Splitting can be used to send arbitrary responses.
  File Inclusion
File Inclusion enables an attacker to inject custom files into PHP's file loading mechanism, either explicitly passed to include, or for example via PHP's auto-loading mechanism.
  Command Injection
Command Injection enables an attacker to inject a shell command that is execute with the privileges of the web-server. This can be used to expose sensitive data, or gain access of your server.
  SQL Injection
SQL Injection enables an attacker to execute arbitrary SQL code on your database server gaining access to user data, or manipulating user data.
  XPath Injection
XPath Injection enables an attacker to modify the parts of XML document that are read. If that XML document is for example used for authentication, this can lead to further vulnerabilities similar to SQL Injection.
  LDAP Injection
LDAP Injection enables an attacker to inject LDAP statements potentially granting permission to run unauthorized queries, or modify content inside the LDAP tree.
  Header Injection
  Other Vulnerability
This category comprises other attack vectors such as manipulating the PHP runtime, loading custom extensions, freezing the runtime, or similar.
  Regex Injection
Regex Injection enables an attacker to execute arbitrary code in your PHP process.
  XML Injection
XML Injection enables an attacker to read files on your local filesystem including configuration files, or can be abused to freeze your web-server process.
  Variable Injection
Variable Injection enables an attacker to overwrite program variables with custom data, and can lead to further vulnerabilities.
Unfortunately, the security analysis is currently not available for your project. If you are a non-commercial open-source project, please contact support to gain access.

inline/LinkTrait.php (2 issues)

Upgrade to new PHP Analysis Engine

These results are based on our legacy PHP analysis, consider migrating to our new PHP analysis engine instead. Learn more

1
<?php
2
/**
3
 * @copyright Copyright (c) 2014 Carsten Brandt
4
 * @license https://github.com/cebe/markdown/blob/master/LICENSE
5
 * @link https://github.com/cebe/markdown#readme
6
 */
7
8
namespace cebe\markdown\inline;
9
10
// work around https://github.com/facebook/hhvm/issues/1120
11 1
defined('ENT_HTML401') || define('ENT_HTML401', 0);
12
13
/**
14
 * Addes links and images as well as url markers.
15
 *
16
 * This trait conflicts with the HtmlTrait. If both are used together,
17
 * you have to define a resolution, by defining the HtmlTrait::parseInlineHtml
18
 * as private so it is not used directly:
19
 *
20
 * ```php
21
 * use block\HtmlTrait {
22
 *     parseInlineHtml as private parseInlineHtml;
23
 * }
24
 * ```
25
 *
26
 * If the method exists it is called internally by this trait.
27
 *
28
 * Also make sure to reset references on prepare():
29
 *
30
 * ```php
31
 * protected function prepare()
32
 * {
33
 *     // reset references
34
 *     $this->references = [];
35
 * }
36
 * ```
37
 */
38
trait LinkTrait
39
{
40
	/**
41
	 * @var array a list of defined references in this document.
42
	 */
43
	protected $references = [];
44
45
	/**
46
	 * Remove backslash from escaped characters
47
	 * @param $text
48
	 * @return string
49
	 */
50 58
	protected function replaceEscape($text)
51
	{
52 58
		$strtr = [];
53 58
		foreach($this->escapeCharacters as $char) {
54 58
			$strtr["\\$char"] = $char;
55
		}
56 58
		return strtr($text, $strtr);
57
	}
58
59
	/**
60
	 * Parses a link indicated by `[`.
61
	 * @marker [
62
	 */
63 53
	protected function parseLink($markdown)
64
	{
65 53
		if (!in_array('parseLink', array_slice($this->context, 1)) && ($parts = $this->parseLinkOrImage($markdown)) !== false) {
66 53
			list($text, $url, $title, $offset, $key) = $parts;
67
			return [
68
				[
69 53
					'link',
70 53
					'text' => $this->parseInline($text),
71 53
					'url' => $url,
72 53
					'title' => $title,
73 53
					'refkey' => $key,
74 53
					'orig' => substr($markdown, 0, $offset),
75
				],
76 53
				$offset
77
			];
78 View Code Duplication
		} else {
79
			// remove all starting [ markers to avoid next one to be parsed as link
80 11
			$result = '[';
81 11
			$i = 1;
82 11
			while (isset($markdown[$i]) && $markdown[$i] === '[') {
83
				$result .= '[';
84
				$i++;
85
			}
86 11
			return [['text', $result], $i];
87
		}
88
	}
89
90
	/**
91
	 * Parses an image indicated by `![`.
92
	 * @marker ![
93
	 */
94 10
	protected function parseImage($markdown)
95
	{
96 10
		if (($parts = $this->parseLinkOrImage(substr($markdown, 1))) !== false) {
97 10
			list($text, $url, $title, $offset, $key) = $parts;
98
99
			return [
100
				[
101 10
					'image',
102 10
					'text' => $text,
103 10
					'url' => $url,
104 10
					'title' => $title,
105 10
					'refkey' => $key,
106 10
					'orig' => substr($markdown, 0, $offset + 1),
107
				],
108 10
				$offset + 1
109
			];
110 View Code Duplication
		} else {
111
			// remove all starting [ markers to avoid next one to be parsed as link
112 3
			$result = '!';
113 3
			$i = 1;
114 3
			while (isset($markdown[$i]) && $markdown[$i] === '[') {
115 3
				$result .= '[';
116 3
				$i++;
117
			}
118 3
			return [['text', $result], $i];
119
		}
120
	}
121
122 53
	protected function parseLinkOrImage($markdown)
123
	{
124 53
		if (strpos($markdown, ']') !== false && preg_match('/\[((?>[^\]\[]+|(?R))*)\]/', $markdown, $textMatches)) { // TODO improve bracket regex
125 53
			$text = $textMatches[1];
126 53
			$offset = strlen($textMatches[0]);
127 53
			$markdown = substr($markdown, $offset);
128
129
			$pattern = <<<REGEXP
130 53
				/(?(R) # in case of recursion match parentheses
131
					 \(((?>[^\s()]+)|(?R))*\)
132
				|      # else match a link with title
133
					^\(\s*(((?>[^\s()]+)|(?R))*)(\s+"(.*?)")?\s*\)
134
				)/x
135
REGEXP;
136 53
			if (preg_match($pattern, $markdown, $refMatches)) {
137
				// inline link
138
				return [
139 36
					$text,
140 36
					isset($refMatches[2]) ? $this->replaceEscape($refMatches[2]) : '', // url
141 36
					empty($refMatches[5]) ? null: $refMatches[5], // title
142 36
					$offset + strlen($refMatches[0]), // offset
143
					null, // reference key
144
				];
145 43
			} elseif (preg_match('/^([ \n]?\[(.*?)\])?/s', $markdown, $refMatches)) {
146
				// reference style link
147 43
				if (empty($refMatches[2])) {
148 36
					$key = strtolower($text);
149
				} else {
150 17
					$key = strtolower($refMatches[2]);
151
				}
152
				return [
153 43
					$text,
154
					null, // url
155
					null, // title
156 43
					$offset + strlen($refMatches[0]), // offset
157 43
					$key,
158
				];
159
			}
160
		}
161 3
		return false;
162
	}
163
164
	/**
165
	 * Parses inline HTML.
166
	 * @marker <
167
	 */
168 31
	protected function parseLt($text)
169
	{
170 31
		if (strpos($text, '>') !== false) {
171 27
			if (!in_array('parseLink', $this->context)) { // do not allow links in links
172 27 View Code Duplication
				if (preg_match('/^<([^\s>]*?@[^\s]*?\.\w+?)>/', $text, $matches)) {
173
					// email address
174
					return [
175 6
						['email', $this->replaceEscape($matches[1])],
176 6
						strlen($matches[0])
177
					];
178 27
				} elseif (preg_match('/^<([a-z]{3,}:\/\/[^\s]+?)>/', $text, $matches)) {
179
					// URL
180
					return [
181 13
						['url', $this->replaceEscape($matches[1])],
182 13
						strlen($matches[0])
183
					];
184
				}
185
			}
186
			// try inline HTML if it was neither a URL nor email if HtmlTrait is included.
187 17
			if (method_exists($this, 'parseInlineHtml')) {
188 17
				return $this->parseInlineHtml($text);
0 ignored issues
show
The method parseInlineHtml() does not exist on cebe\markdown\inline\LinkTrait. Did you maybe mean parseInline()?

This check marks calls to methods that do not seem to exist on an object.

This is most likely the result of a method being renamed without all references to it being renamed likewise.

Loading history...
189
			}
190
		}
191 11
		return [['text', '&lt;'], 1];
192
	}
193
194 6
	protected function renderEmail($block)
195
	{
196 6
		$email = htmlspecialchars($block[1], ENT_NOQUOTES | ENT_SUBSTITUTE, 'UTF-8');
197 6
		return "<a href=\"mailto:$email\">$email</a>";
198
	}
199
200 13 View Code Duplication
	protected function renderUrl($block)
0 ignored issues
show
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
201
	{
202 13
		$url = htmlspecialchars($block[1], ENT_COMPAT | ENT_HTML401, 'UTF-8');
203 13
		$decodedUrl = urldecode($block[1]);
204 13
		$secureUrlText = preg_match('//u', $decodedUrl) ? $decodedUrl : $block[1];
205 13
		$text = htmlspecialchars($secureUrlText, ENT_NOQUOTES | ENT_SUBSTITUTE, 'UTF-8');
206 13
		return "<a href=\"$url\">$text</a>";
207
	}
208
209 43
	protected function lookupReference($key)
210
	{
211 43
		$normalizedKey = preg_replace('/\s+/', ' ', $key);
212 43
		if (isset($this->references[$key]) || isset($this->references[$key = $normalizedKey])) {
213 29
			return $this->references[$key];
214
		}
215 23
		return false;
216
	}
217
218 35
	protected function renderLink($block)
219
	{
220 35 View Code Duplication
		if (isset($block['refkey'])) {
221 28
			if (($ref = $this->lookupReference($block['refkey'])) !== false) {
222 19
				$block = array_merge($block, $ref);
223
			} else {
224 15
				if (strncmp($block['orig'], '[', 1) === 0) {
225 15
					return '[' . $this->renderAbsy($this->parseInline(substr($block['orig'], 1)));
226
				}
227
				return $block['orig'];
228
			}
229
		}
230 34
		return '<a href="' . htmlspecialchars($block['url'], ENT_COMPAT | ENT_HTML401, 'UTF-8') . '"'
231 34
			. (empty($block['title']) ? '' : ' title="' . htmlspecialchars($block['title'], ENT_COMPAT | ENT_HTML401 | ENT_SUBSTITUTE, 'UTF-8') . '"')
232 34
			. '>' . $this->renderAbsy($block['text']) . '</a>';
233
	}
234
235 6
	protected function renderImage($block)
236
	{
237 6 View Code Duplication
		if (isset($block['refkey'])) {
238 4
			if (($ref = $this->lookupReference($block['refkey'])) !== false) {
239
				$block = array_merge($block, $ref);
240
			} else {
241 4
				if (strncmp($block['orig'], '![', 2) === 0) {
242 4
					return '![' . $this->renderAbsy($this->parseInline(substr($block['orig'], 2)));
243
				}
244
				return $block['orig'];
245
			}
246
		}
247 4
		return '<img src="' . htmlspecialchars($block['url'], ENT_COMPAT | ENT_HTML401, 'UTF-8') . '"'
248 4
			. ' alt="' . htmlspecialchars($block['text'], ENT_COMPAT | ENT_HTML401 | ENT_SUBSTITUTE, 'UTF-8') . '"'
249 4
			. (empty($block['title']) ? '' : ' title="' . htmlspecialchars($block['title'], ENT_COMPAT | ENT_HTML401 | ENT_SUBSTITUTE, 'UTF-8') . '"')
250 4
			. ($this->html5 ? '>' : ' />');
251
	}
252
253
	// references
254
255 143
	protected function identifyReference($line)
256
	{
257 143
		return isset($line[0]) && ($line[0] === ' ' || $line[0] === '[') && preg_match('/^ {0,3}\[[^\[](.*?)\]:\s*([^\s]+?)(?:\s+[\'"](.+?)[\'"])?\s*$/', $line);
258
	}
259
260
	/**
261
	 * Consume link references
262
	 */
263 19
	protected function consumeReference($lines, $current)
264
	{
265 19
		while (isset($lines[$current]) && preg_match('/^ {0,3}\[(.+?)\]:\s*(.+?)(?:\s+[\(\'"](.+?)[\)\'"])?\s*$/', $lines[$current], $matches)) {
266 19
			$label = strtolower($matches[1]);
267
268 19
			$this->references[$label] = [
269 19
				'url' => $this->replaceEscape($matches[2]),
270
			];
271 19 View Code Duplication
			if (isset($matches[3])) {
272 9
				$this->references[$label]['title'] = $matches[3];
273
			} else {
274
				// title may be on the next line
275 16
				if (isset($lines[$current + 1]) && preg_match('/^\s+[\(\'"](.+?)[\)\'"]\s*$/', $lines[$current + 1], $matches)) {
276 2
					$this->references[$label]['title'] = $matches[1];
277 2
					$current++;
278
				}
279
			}
280 19
			$current++;
281
		}
282 19
		return [false, --$current];
283
	}
284
285
	abstract protected function parseInline($text);
286
	abstract protected function renderAbsy($blocks);
287
}
288