Markdown_Parser   D
last analyzed

Complexity

Total Complexity 112

Size/Duplication

Total Lines 1444
Duplicated Lines 9.28 %

Coupling/Cohesion

Components 1
Dependencies 0

Importance

Changes 2
Bugs 1 Features 0
Metric Value
c 2
b 1
f 0
dl 134
loc 1444
rs 4.4102
wmc 112
lcom 1
cbo 0

52 Methods

Rating   Name   Duplication   Size   Complexity  
A Markdown_Parser() 0 22 1
A setup() 0 12 1
A teardown() 0 9 1
B transform() 0 38 2
B stripLinkDefinitions() 30 30 1
A _stripLinkDefinitions_callback() 0 6 1
B hashHTMLBlocks() 0 137 2
A _hashHTMLBlocks_callback() 0 5 1
A hashPart() 0 21 1
A hashBlock() 0 6 1
A runBlockGamut() 0 13 1
A runBasicBlockGamut() 0 15 2
A doHorizontalRules() 0 16 1
A runSpanGamut() 0 10 2
A doHardBreaks() 0 5 1
A _doHardBreaks_callback() 0 3 1
A doAnchors() 0 70 2
B _doAnchors_reference_callback() 5 34 4
A _doAnchors_inline_callback() 19 19 3
A doImages() 0 55 1
B _doImages_reference_callback() 5 28 4
A _doImages_inline_callback() 17 17 3
B doHeaders() 30 30 1
A _doHeaders_callback_setext() 2 9 4
A _doHeaders_callback_atx() 0 5 1
A doLists() 0 57 3
A _doLists_callback() 0 17 3
B processListItems() 0 46 1
B _processListItems_callback() 13 23 4
A doCodeBlocks() 0 18 1
A _doCodeBlocks_callback() 0 12 1
A makeCodeSpan() 0 7 1
A prepareItalicsAndBold() 0 21 4
D doItalicsAndBold() 13 121 16
A doBlockQuotes() 0 15 1
A _doBlockQuotes_callback() 0 14 1
A _doBlockQuotes_callback2() 0 5 1
A formParagraphs() 0 68 3
A encodeAttribute() 0 9 1
A encodeAmpsAndAngles() 0 19 2
A doAutoLinks() 0 19 1
A _doAutoLinks_url_callback() 0 5 1
A _doAutoLinks_email_callback() 0 5 1
B encodeEmailAddress() 0 39 6
B parseSpan() 0 54 5
B handleSpanToken() 0 22 4
A outdent() 0 6 1
A detab() 0 13 1
A _detab_callback() 0 17 2
A _initDetab() 0 12 2
A unhash() 0 7 1
A _unhash_callback() 0 3 1

How to fix   Duplicated Code    Complexity   

Duplicated Code

Duplicate code is one of the most pungent code smells. A rule that is often used is to re-structure code once it is duplicated in three or more places.

Common duplication problems, and corresponding solutions are:

Complex Class

 Tip:   Before tackling complexity, make sure that you eliminate any duplication first. This often can reduce the size of classes significantly.

Complex classes like Markdown_Parser often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes. You can also have a look at the cohesion graph to spot any un-connected, or weakly-connected components.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

While breaking up the class, it is a good idea to analyze how other classes use Markdown_Parser, and based on these observations, apply Extract Interface, too.

1
<?php
2
#
3
# Markdown Extra  -  A text-to-HTML conversion tool for web writers
4
#
5
# PHP Markdown & Extra
6
# Copyright (c) 2004-2008 Michel Fortin  
7
# <http://www.michelf.com/projects/php-markdown/>
8
#
9
# Original Markdown
10
# Copyright (c) 2004-2006 John Gruber  
11
# <http://daringfireball.net/projects/markdown/>
12
#
13
14
15
define( 'MARKDOWN_VERSION',  "1.0.1m" ); # Sat 21 Jun 2008
16
define( 'MARKDOWNEXTRA_VERSION',  "1.2.3" ); # Wed 31 Dec 2008
17
18
19
#
20
# Global default settings:
21
#
22
23
# Change to ">" for HTML output
24
@define( 'MARKDOWN_EMPTY_ELEMENT_SUFFIX',  " />");
0 ignored issues
show
Security Best Practice introduced by
It seems like you do not handle an error condition here. This can introduce security issues, and is generally not recommended.

If you suppress an error, we recommend checking for the error condition explicitly:

// For example instead of
@mkdir($dir);

// Better use
if (@mkdir($dir) === false) {
    throw new \RuntimeException('The directory '.$dir.' could not be created.');
}
Loading history...
25
26
# Define the width of a tab for code blocks.
27
@define( 'MARKDOWN_TAB_WIDTH',     4 );
0 ignored issues
show
Security Best Practice introduced by
It seems like you do not handle an error condition here. This can introduce security issues, and is generally not recommended.

If you suppress an error, we recommend checking for the error condition explicitly:

// For example instead of
@mkdir($dir);

// Better use
if (@mkdir($dir) === false) {
    throw new \RuntimeException('The directory '.$dir.' could not be created.');
}
Loading history...
28
29
# Optional title attribute for footnote links and backlinks.
30
@define( 'MARKDOWN_FN_LINK_TITLE',         "" );
0 ignored issues
show
Security Best Practice introduced by
It seems like you do not handle an error condition here. This can introduce security issues, and is generally not recommended.

If you suppress an error, we recommend checking for the error condition explicitly:

// For example instead of
@mkdir($dir);

// Better use
if (@mkdir($dir) === false) {
    throw new \RuntimeException('The directory '.$dir.' could not be created.');
}
Loading history...
31
@define( 'MARKDOWN_FN_BACKLINK_TITLE',     "" );
0 ignored issues
show
Security Best Practice introduced by
It seems like you do not handle an error condition here. This can introduce security issues, and is generally not recommended.

If you suppress an error, we recommend checking for the error condition explicitly:

// For example instead of
@mkdir($dir);

// Better use
if (@mkdir($dir) === false) {
    throw new \RuntimeException('The directory '.$dir.' could not be created.');
}
Loading history...
32
33
# Optional class attribute for footnote links and backlinks.
34
@define( 'MARKDOWN_FN_LINK_CLASS',         "" );
0 ignored issues
show
Security Best Practice introduced by
It seems like you do not handle an error condition here. This can introduce security issues, and is generally not recommended.

If you suppress an error, we recommend checking for the error condition explicitly:

// For example instead of
@mkdir($dir);

// Better use
if (@mkdir($dir) === false) {
    throw new \RuntimeException('The directory '.$dir.' could not be created.');
}
Loading history...
35
@define( 'MARKDOWN_FN_BACKLINK_CLASS',     "" );
0 ignored issues
show
Security Best Practice introduced by
It seems like you do not handle an error condition here. This can introduce security issues, and is generally not recommended.

If you suppress an error, we recommend checking for the error condition explicitly:

// For example instead of
@mkdir($dir);

// Better use
if (@mkdir($dir) === false) {
    throw new \RuntimeException('The directory '.$dir.' could not be created.');
}
Loading history...
36
37
38
#
39
# WordPress settings:
40
#
41
42
# Change to false to remove Markdown from posts and/or comments.
43
@define( 'MARKDOWN_WP_POSTS',      true );
0 ignored issues
show
Security Best Practice introduced by
It seems like you do not handle an error condition here. This can introduce security issues, and is generally not recommended.

If you suppress an error, we recommend checking for the error condition explicitly:

// For example instead of
@mkdir($dir);

// Better use
if (@mkdir($dir) === false) {
    throw new \RuntimeException('The directory '.$dir.' could not be created.');
}
Loading history...
44
@define( 'MARKDOWN_WP_COMMENTS',   true );
0 ignored issues
show
Security Best Practice introduced by
It seems like you do not handle an error condition here. This can introduce security issues, and is generally not recommended.

If you suppress an error, we recommend checking for the error condition explicitly:

// For example instead of
@mkdir($dir);

// Better use
if (@mkdir($dir) === false) {
    throw new \RuntimeException('The directory '.$dir.' could not be created.');
}
Loading history...
45
46
47
48
### Standard Function Interface ###
49
50
@define( 'MARKDOWN_PARSER_CLASS',  'MarkdownExtra_Parser' );
0 ignored issues
show
Security Best Practice introduced by
It seems like you do not handle an error condition here. This can introduce security issues, and is generally not recommended.

If you suppress an error, we recommend checking for the error condition explicitly:

// For example instead of
@mkdir($dir);

// Better use
if (@mkdir($dir) === false) {
    throw new \RuntimeException('The directory '.$dir.' could not be created.');
}
Loading history...
51
52
function Markdown($text) {
0 ignored issues
show
Documentation introduced by
The return type could not be reliably inferred; please add a @return annotation.

Our type inference engine in quite powerful, but sometimes the code does not provide enough clues to go by. In these cases we request you to add a @return annotation as described here.

Loading history...
53
#
54
# Initialize the parser and return the result of its transform method.
55
#
56
	# Setup static parser variable.
57
	static $parser;
58
	if (!isset($parser)) {
59
		$parser_class = MARKDOWN_PARSER_CLASS;
60
		$parser = new $parser_class;
61
	}
62
63
	# Transform text using parser.
64
	return $parser->transform($text);
65
}
66
67
68
### WordPress Plugin Interface ###
69
70
/*
71
Plugin Name: Markdown Extra
72
Plugin URI: http://www.michelf.com/projects/php-markdown/
73
Description: <a href="http://daringfireball.net/projects/markdown/syntax">Markdown syntax</a> allows you to write using an easy-to-read, easy-to-write plain text format. Based on the original Perl version by <a href="http://daringfireball.net/">John Gruber</a>. <a href="http://www.michelf.com/projects/php-markdown/">More...</a>
74
Version: 1.2.2
75
Author: Michel Fortin
76
Author URI: http://www.michelf.com/
77
*/
78
79
if (isset($wp_version)) {
80
	# More details about how it works here:
81
	# <http://www.michelf.com/weblog/2005/wordpress-text-flow-vs-markdown/>
82
	
83
	# Post content and excerpts
84
	# - Remove WordPress paragraph generator.
85
	# - Run Markdown on excerpt, then remove all tags.
86
	# - Add paragraph tag around the excerpt, but remove it for the excerpt rss.
87
	if (MARKDOWN_WP_POSTS) {
88
		remove_filter('the_content',     'wpautop');
89
        remove_filter('the_content_rss', 'wpautop');
90
		remove_filter('the_excerpt',     'wpautop');
91
		add_filter('the_content',     'mdwp_MarkdownPost', 6);
92
        add_filter('the_content_rss', 'mdwp_MarkdownPost', 6);
93
		add_filter('get_the_excerpt', 'mdwp_MarkdownPost', 6);
94
		add_filter('get_the_excerpt', 'trim', 7);
95
		add_filter('the_excerpt',     'mdwp_add_p');
96
		add_filter('the_excerpt_rss', 'mdwp_strip_p');
97
		
98
		remove_filter('content_save_pre',  'balanceTags', 50);
99
		remove_filter('excerpt_save_pre',  'balanceTags', 50);
100
		add_filter('the_content',  	  'balanceTags', 50);
101
		add_filter('get_the_excerpt', 'balanceTags', 9);
102
	}
103
	
104
	# Add a footnote id prefix to posts when inside a loop.
105
	function mdwp_MarkdownPost($text) {
0 ignored issues
show
Documentation introduced by
The return type could not be reliably inferred; please add a @return annotation.

Our type inference engine in quite powerful, but sometimes the code does not provide enough clues to go by. In these cases we request you to add a @return annotation as described here.

Loading history...
106
		static $parser;
107
		if (!$parser) {
108
			$parser_class = MARKDOWN_PARSER_CLASS;
109
			$parser = new $parser_class;
110
		}
111
		if (is_single() || is_page() || is_feed()) {
112
			$parser->fn_id_prefix = "";
113
		} else {
114
			$parser->fn_id_prefix = get_the_ID() . ".";
115
		}
116
		return $parser->transform($text);
117
	}
118
	
119
	# Comments
120
	# - Remove WordPress paragraph generator.
121
	# - Remove WordPress auto-link generator.
122
	# - Scramble important tags before passing them to the kses filter.
123
	# - Run Markdown on excerpt then remove paragraph tags.
124
	if (MARKDOWN_WP_COMMENTS) {
125
		remove_filter('comment_text', 'wpautop', 30);
126
		remove_filter('comment_text', 'make_clickable');
127
		add_filter('pre_comment_content', 'Markdown', 6);
128
		add_filter('pre_comment_content', 'mdwp_hide_tags', 8);
129
		add_filter('pre_comment_content', 'mdwp_show_tags', 12);
130
		add_filter('get_comment_text',    'Markdown', 6);
131
		add_filter('get_comment_excerpt', 'Markdown', 6);
132
		add_filter('get_comment_excerpt', 'mdwp_strip_p', 7);
133
	
134
		global $mdwp_hidden_tags, $mdwp_placeholders;
135
		$mdwp_hidden_tags = explode(' ',
136
			'<p> </p> <pre> </pre> <ol> </ol> <ul> </ul> <li> </li>');
137
		$mdwp_placeholders = explode(' ', str_rot13(
138
			'pEj07ZbbBZ U1kqgh4w4p pre2zmeN6K QTi31t9pre ol0MP1jzJR '.
139
			'ML5IjmbRol ulANi1NsGY J7zRLJqPul liA8ctl16T K9nhooUHli'));
140
	}
141
	
142
	function mdwp_add_p($text) {
0 ignored issues
show
Documentation introduced by
The return type could not be reliably inferred; please add a @return annotation.

Our type inference engine in quite powerful, but sometimes the code does not provide enough clues to go by. In these cases we request you to add a @return annotation as described here.

Loading history...
143
		if (!preg_match('{^$|^<(p|ul|ol|dl|pre|blockquote)>}i', $text)) {
144
			$text = '<p>'.$text.'</p>';
145
			$text = preg_replace('{\n{2,}}', "</p>\n\n<p>", $text);
146
		}
147
		return $text;
148
	}
149
	
150
	function mdwp_strip_p($t) { return preg_replace('{</?p>}i', '', $t); }
0 ignored issues
show
Documentation introduced by
The return type could not be reliably inferred; please add a @return annotation.

Our type inference engine in quite powerful, but sometimes the code does not provide enough clues to go by. In these cases we request you to add a @return annotation as described here.

Loading history...
Comprehensibility introduced by
Avoid variables with short names like $t. Configured minimum length is 3.

Short variable names may make your code harder to understand. Variable names should be self-descriptive. This check looks for variable names who are shorter than a configured minimum.

Loading history...
151
152
	function mdwp_hide_tags($text) {
0 ignored issues
show
Documentation introduced by
The return type could not be reliably inferred; please add a @return annotation.

Our type inference engine in quite powerful, but sometimes the code does not provide enough clues to go by. In these cases we request you to add a @return annotation as described here.

Loading history...
153
		global $mdwp_hidden_tags, $mdwp_placeholders;
154
		return str_replace($mdwp_hidden_tags, $mdwp_placeholders, $text);
155
	}
156
	function mdwp_show_tags($text) {
0 ignored issues
show
Documentation introduced by
The return type could not be reliably inferred; please add a @return annotation.

Our type inference engine in quite powerful, but sometimes the code does not provide enough clues to go by. In these cases we request you to add a @return annotation as described here.

Loading history...
157
		global $mdwp_hidden_tags, $mdwp_placeholders;
158
		return str_replace($mdwp_placeholders, $mdwp_hidden_tags, $text);
159
	}
160
}
161
162
163
### bBlog Plugin Info ###
164
165
function identify_modifier_markdown() {
166
	return array(
167
		'name' => 'markdown',
168
		'type' => 'modifier',
169
		'nicename' => 'PHP Markdown Extra',
170
		'description' => 'A text-to-HTML conversion tool for web writers',
171
		'authors' => 'Michel Fortin and John Gruber',
172
		'licence' => 'GPL',
173
		'version' => MARKDOWNEXTRA_VERSION,
174
		'help' => '<a href="http://daringfireball.net/projects/markdown/syntax">Markdown syntax</a> allows you to write using an easy-to-read, easy-to-write plain text format. Based on the original Perl version by <a href="http://daringfireball.net/">John Gruber</a>. <a href="http://www.michelf.com/projects/php-markdown/">More...</a>',
175
		);
176
}
177
178
179
### Smarty Modifier Interface ###
180
181
function smarty_modifier_markdown($text) {
0 ignored issues
show
Documentation introduced by
The return type could not be reliably inferred; please add a @return annotation.

Our type inference engine in quite powerful, but sometimes the code does not provide enough clues to go by. In these cases we request you to add a @return annotation as described here.

Loading history...
182
	return Markdown($text);
183
}
184
185
186
### Textile Compatibility Mode ###
187
188
# Rename this file to "classTextile.php" and it can replace Textile everywhere.
189
190
if (strcasecmp(substr(__FILE__, -16), "classTextile.php") == 0) {
191
	# Try to include PHP SmartyPants. Should be in the same directory.
192
	@include_once 'smartypants.php';
0 ignored issues
show
Security Best Practice introduced by
It seems like you do not handle an error condition here. This can introduce security issues, and is generally not recommended.

If you suppress an error, we recommend checking for the error condition explicitly:

// For example instead of
@mkdir($dir);

// Better use
if (@mkdir($dir) === false) {
    throw new \RuntimeException('The directory '.$dir.' could not be created.');
}
Loading history...
193
	# Fake Textile class. It calls Markdown instead.
194
	class Textile {
195
		function TextileThis($text, $lite='', $encode='') {
0 ignored issues
show
Documentation introduced by
The return type could not be reliably inferred; please add a @return annotation.

Our type inference engine in quite powerful, but sometimes the code does not provide enough clues to go by. In these cases we request you to add a @return annotation as described here.

Loading history...
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
196
			if ($lite == '' && $encode == '')    $text = Markdown($text);
197
			if (function_exists('SmartyPants'))  $text = SmartyPants($text);
198
			return $text;
199
		}
200
		# Fake restricted version: restrictions are not supported for now.
201
		function TextileRestricted($text, $lite='', $noimage='') {
0 ignored issues
show
Documentation introduced by
The return type could not be reliably inferred; please add a @return annotation.

Our type inference engine in quite powerful, but sometimes the code does not provide enough clues to go by. In these cases we request you to add a @return annotation as described here.

Loading history...
Unused Code introduced by
The parameter $noimage is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
202
			return $this->TextileThis($text, $lite);
203
		}
204
		# Workaround to ensure compatibility with TextPattern 4.0.3.
205
		function blockLite($text) { return $text; }
0 ignored issues
show
Documentation introduced by
The return type could not be reliably inferred; please add a @return annotation.

Our type inference engine in quite powerful, but sometimes the code does not provide enough clues to go by. In these cases we request you to add a @return annotation as described here.

Loading history...
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
206
	}
207
}
208
209
210
211
#
212
# Markdown Parser Class
213
#
214
215
class Markdown_Parser {
216
217
	# Regex to match balanced [brackets].
218
	# Needed to insert a maximum bracked depth while converting to PHP.
219
	var $nested_brackets_depth = 6;
0 ignored issues
show
Comprehensibility Naming introduced by
The variable name $nested_brackets_depth exceeds the maximum configured length of 20.

Very long variable names usually make code harder to read. It is therefore recommended not to make variable names too verbose.

Loading history...
220
	var $nested_brackets_re;
221
	
222
	var $nested_url_parenthesis_depth = 4;
0 ignored issues
show
Comprehensibility Naming introduced by
The variable name $nested_url_parenthesis_depth exceeds the maximum configured length of 20.

Very long variable names usually make code harder to read. It is therefore recommended not to make variable names too verbose.

Loading history...
223
	var $nested_url_parenthesis_re;
0 ignored issues
show
Comprehensibility Naming introduced by
The variable name $nested_url_parenthesis_re exceeds the maximum configured length of 20.

Very long variable names usually make code harder to read. It is therefore recommended not to make variable names too verbose.

Loading history...
224
225
	# Table of hash values for escaped characters:
226
	var $escape_chars = '\`*_{}[]()>#+-.!';
227
	var $escape_chars_re;
228
229
	# Change to ">" for HTML output.
230
	var $empty_element_suffix = MARKDOWN_EMPTY_ELEMENT_SUFFIX;
231
	var $tab_width = MARKDOWN_TAB_WIDTH;
232
	
233
	# Change to `true` to disallow markup or entities.
234
	var $no_markup = false;
235
	var $no_entities = false;
236
	
237
	# Predefined urls and titles for reference links and images.
238
	var $predef_urls = array();
239
	var $predef_titles = array();
240
241
242
	function Markdown_Parser() {
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
243
	#
244
	# Constructor function. Initialize appropriate member variables.
245
	#
246
		$this->_initDetab();
247
		$this->prepareItalicsAndBold();
248
	
249
		$this->nested_brackets_re = 
250
			str_repeat('(?>[^\[\]]+|\[', $this->nested_brackets_depth).
251
			str_repeat('\])*', $this->nested_brackets_depth);
252
	
253
		$this->nested_url_parenthesis_re = 
254
			str_repeat('(?>[^()\s]+|\(', $this->nested_url_parenthesis_depth).
255
			str_repeat('(?>\)))*', $this->nested_url_parenthesis_depth);
256
		
257
		$this->escape_chars_re = '['.preg_quote($this->escape_chars).']';
258
		
259
		# Sort document, block, and span gamut in ascendent priority order.
260
		asort($this->document_gamut);
261
		asort($this->block_gamut);
262
		asort($this->span_gamut);
263
	}
264
265
266
	# Internal hashes used during transformation.
267
	var $urls = array();
268
	var $titles = array();
269
	var $html_hashes = array();
270
	
271
	# Status flag to avoid invalid nesting.
272
	var $in_anchor = false;
273
	
274
	
275
	function setup() {
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
276
	#
277
	# Called before the transformation process starts to setup parser 
278
	# states.
279
	#
280
		# Clear global hashes.
281
		$this->urls = $this->predef_urls;
282
		$this->titles = $this->predef_titles;
283
		$this->html_hashes = array();
284
		
285
		$in_anchor = false;
0 ignored issues
show
Unused Code introduced by
$in_anchor is not used, you could remove the assignment.

This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.

$myVar = 'Value';
$higher = false;

if (rand(1, 6) > 3) {
    $higher = true;
} else {
    $higher = false;
}

Both the $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

Loading history...
286
	}
287
	
288
	function teardown() {
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
289
	#
290
	# Called after the transformation process to clear any variable 
291
	# which may be taking up memory unnecessarly.
292
	#
293
		$this->urls = array();
294
		$this->titles = array();
295
		$this->html_hashes = array();
296
	}
297
298
299
	function transform($text) {
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
300
	#
301
	# Main function. Performs some preprocessing on the input text
302
	# and pass it through the document gamut.
303
	#
304
		$this->setup();
305
	
306
		# Remove UTF-8 BOM and marker character in input, if present.
307
		$text = preg_replace('{^\xEF\xBB\xBF|\x1A}', '', $text);
308
309
		# Standardize line endings:
310
		#   DOS to Unix and Mac to Unix
311
		$text = preg_replace('{\r\n?}', "\n", $text);
312
313
		# Make sure $text ends with a couple of newlines:
314
		$text .= "\n\n";
315
316
		# Convert all tabs to spaces.
317
		$text = $this->detab($text);
318
319
		# Turn block-level HTML blocks into hash entries
320
		$text = $this->hashHTMLBlocks($text);
321
322
		# Strip any lines consisting only of spaces and tabs.
323
		# This makes subsequent regexen easier to write, because we can
324
		# match consecutive blank lines with /\n+/ instead of something
325
		# contorted like /[ ]*\n+/ .
326
		$text = preg_replace('/^[ ]+$/m', '', $text);
327
328
		# Run document gamut methods.
329
		foreach ($this->document_gamut as $method => $priority) {
330
			$text = $this->$method($text);
331
		}
332
		
333
		$this->teardown();
334
335
		return $text . "\n";
336
	}
337
	
338
	var $document_gamut = array(
339
		# Strip link definitions, store in hashes.
340
		"stripLinkDefinitions" => 20,
341
		
342
		"runBasicBlockGamut"   => 30,
343
		);
344
345
346 View Code Duplication
	function stripLinkDefinitions($text) {
0 ignored issues
show
Documentation introduced by
The return type could not be reliably inferred; please add a @return annotation.

Our type inference engine in quite powerful, but sometimes the code does not provide enough clues to go by. In these cases we request you to add a @return annotation as described here.

Loading history...
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
Duplication introduced by
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...
347
	#
348
	# Strips link definitions from text, stores the URLs and titles in
349
	# hash references.
350
	#
351
		$less_than_tab = $this->tab_width - 1;
352
353
		# Link defs are in the form: ^[id]: url "optional title"
354
		$text = preg_replace_callback('{
355
							^[ ]{0,'.$less_than_tab.'}\[(.+)\][ ]?:	# id = $1
356
							  [ ]*
357
							  \n?				# maybe *one* newline
358
							  [ ]*
359
							<?(\S+?)>?			# url = $2
360
							  [ ]*
361
							  \n?				# maybe one newline
362
							  [ ]*
363
							(?:
364
								(?<=\s)			# lookbehind for whitespace
365
								["(]
366
								(.*?)			# title = $3
367
								[")]
368
								[ ]*
369
							)?	# title is optional
370
							(?:\n+|\Z)
371
			}xm',
372
			array(&$this, '_stripLinkDefinitions_callback'),
373
			$text);
374
		return $text;
375
	}
376
	function _stripLinkDefinitions_callback($matches) {
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
377
		$link_id = strtolower($matches[1]);
378
		$this->urls[$link_id] = $matches[2];
379
		$this->titles[$link_id] =& $matches[3];
380
		return ''; # String that will replace the block
381
	}
382
383
384
	function hashHTMLBlocks($text) {
0 ignored issues
show
Documentation introduced by
The return type could not be reliably inferred; please add a @return annotation.

Our type inference engine in quite powerful, but sometimes the code does not provide enough clues to go by. In these cases we request you to add a @return annotation as described here.

Loading history...
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
385
		if ($this->no_markup)  return $text;
386
387
		$less_than_tab = $this->tab_width - 1;
388
389
		# Hashify HTML blocks:
390
		# We only want to do this for block-level HTML tags, such as headers,
391
		# lists, and tables. That's because we still want to wrap <p>s around
392
		# "paragraphs" that are wrapped in non-block-level tags, such as anchors,
393
		# phrase emphasis, and spans. The list of tags we're looking for is
394
		# hard-coded:
395
		#
396
		# *  List "a" is made of tags which can be both inline or block-level.
397
		#    These will be treated block-level when the start tag is alone on 
398
		#    its line, otherwise they're not matched here and will be taken as 
399
		#    inline later.
400
		# *  List "b" is made of tags which are always block-level;
401
		#
402
		$block_tags_a_re = 'ins|del';
403
		$block_tags_b_re = 'p|div|h[1-6]|blockquote|pre|table|dl|ol|ul|address|'.
404
						   'script|noscript|form|fieldset|iframe|math';
405
406
		# Regular expression for the content of a block tag.
407
		$nested_tags_level = 4;
408
		$attr = '
409
			(?>				# optional tag attributes
410
			  \s			# starts with whitespace
411
			  (?>
412
				[^>"/]+		# text outside quotes
413
			  |
414
				/+(?!>)		# slash not followed by ">"
415
			  |
416
				"[^"]*"		# text inside double quotes (tolerate ">")
417
			  |
418
				\'[^\']*\'	# text inside single quotes (tolerate ">")
419
			  )*
420
			)?	
421
			';
422
		$content =
423
			str_repeat('
424
				(?>
425
				  [^<]+			# content without tag
426
				|
427
				  <\2			# nested opening tag
428
					'.$attr.'	# attributes
429
					(?>
430
					  />
431
					|
432
					  >', $nested_tags_level).	# end of opening tag
433
					  '.*?'.					# last level nested tag content
434
			str_repeat('
435
					  </\2\s*>	# closing nested tag
436
					)
437
				  |				
438
					<(?!/\2\s*>	# other tags with a different name
439
				  )
440
				)*',
441
				$nested_tags_level);
442
		$content2 = str_replace('\2', '\3', $content);
443
444
		# First, look for nested blocks, e.g.:
445
		# 	<div>
446
		# 		<div>
447
		# 		tags for inner block must be indented.
448
		# 		</div>
449
		# 	</div>
450
		#
451
		# The outermost tags must start at the left margin for this to match, and
452
		# the inner nested divs must be indented.
453
		# We need to do this before the next, more liberal match, because the next
454
		# match will start at the first `<div>` and stop at the first `</div>`.
455
		$text = preg_replace_callback('{(?>
456
			(?>
457
				(?<=\n\n)		# Starting after a blank line
458
				|				# or
459
				\A\n?			# the beginning of the doc
460
			)
461
			(						# save in $1
462
463
			  # Match from `\n<tag>` to `</tag>\n`, handling nested tags 
464
			  # in between.
465
					
466
						[ ]{0,'.$less_than_tab.'}
467
						<('.$block_tags_b_re.')# start tag = $2
468
						'.$attr.'>			# attributes followed by > and \n
469
						'.$content.'		# content, support nesting
470
						</\2>				# the matching end tag
471
						[ ]*				# trailing spaces/tabs
472
						(?=\n+|\Z)	# followed by a newline or end of document
473
474
			| # Special version for tags of group a.
475
476
						[ ]{0,'.$less_than_tab.'}
477
						<('.$block_tags_a_re.')# start tag = $3
478
						'.$attr.'>[ ]*\n	# attributes followed by >
479
						'.$content2.'		# content, support nesting
480
						</\3>				# the matching end tag
481
						[ ]*				# trailing spaces/tabs
482
						(?=\n+|\Z)	# followed by a newline or end of document
483
					
484
			| # Special case just for <hr />. It was easier to make a special 
485
			  # case than to make the other regex more complicated.
486
			
487
						[ ]{0,'.$less_than_tab.'}
488
						<(hr)				# start tag = $2
489
						'.$attr.'			# attributes
490
						/?>					# the matching end tag
491
						[ ]*
492
						(?=\n{2,}|\Z)		# followed by a blank line or end of document
493
			
494
			| # Special case for standalone HTML comments:
495
			
496
					[ ]{0,'.$less_than_tab.'}
497
					(?s:
498
						<!-- .*? -->
499
					)
500
					[ ]*
501
					(?=\n{2,}|\Z)		# followed by a blank line or end of document
502
			
503
			| # PHP and ASP-style processor instructions (<? and <%)
504
			
505
					[ ]{0,'.$less_than_tab.'}
506
					(?s:
507
						<([?%])			# $2
508
						.*?
509
						\2>
510
					)
511
					[ ]*
512
					(?=\n{2,}|\Z)		# followed by a blank line or end of document
513
					
514
			)
515
			)}Sxmi',
516
			array(&$this, '_hashHTMLBlocks_callback'),
517
			$text);
518
519
		return $text;
520
	}
521
	function _hashHTMLBlocks_callback($matches) {
0 ignored issues
show
Documentation introduced by
The return type could not be reliably inferred; please add a @return annotation.

Our type inference engine in quite powerful, but sometimes the code does not provide enough clues to go by. In these cases we request you to add a @return annotation as described here.

Loading history...
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
522
		$text = $matches[1];
523
		$key  = $this->hashBlock($text);
524
		return "\n\n$key\n\n";
525
	}
526
	
527
	
528
	function hashPart($text, $boundary = 'X') {
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
529
	#
530
	# Called whenever a tag must be hashed when a function insert an atomic 
531
	# element in the text stream. Passing $text to through this function gives
532
	# a unique text-token which will be reverted back when calling unhash.
533
	#
534
	# The $boundary argument specify what character should be used to surround
535
	# the token. By convension, "B" is used for block elements that needs not
536
	# to be wrapped into paragraph tags at the end, ":" is used for elements
537
	# that are word separators and "X" is used in the general case.
538
	#
539
		# Swap back any tag hash found in $text so we do not have to `unhash`
540
		# multiple times at the end.
541
		$text = $this->unhash($text);
542
		
543
		# Then hash the block.
544
		static $i = 0;
545
		$key = "$boundary\x1A" . ++$i . $boundary;
546
		$this->html_hashes[$key] = $text;
547
		return $key; # String that will replace the tag.
548
	}
549
550
551
	function hashBlock($text) {
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
552
	#
553
	# Shortcut function for hashPart with block-level boundaries.
554
	#
555
		return $this->hashPart($text, 'B');
556
	}
557
558
559
	var $block_gamut = array(
560
	#
561
	# These are all the transformations that form block-level
562
	# tags like paragraphs, headers, and list items.
563
	#
564
		"doHeaders"         => 10,
565
		"doHorizontalRules" => 20,
566
		
567
		"doLists"           => 40,
568
		"doCodeBlocks"      => 50,
569
		"doBlockQuotes"     => 60,
570
		);
571
572
	function runBlockGamut($text) {
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
573
	#
574
	# Run block gamut tranformations.
575
	#
576
		# We need to escape raw HTML in Markdown source before doing anything 
577
		# else. This need to be done for each block, and not only at the 
578
		# begining in the Markdown function since hashed blocks can be part of
579
		# list items and could have been indented. Indented blocks would have 
580
		# been seen as a code block in a previous pass of hashHTMLBlocks.
581
		$text = $this->hashHTMLBlocks($text);
582
		
583
		return $this->runBasicBlockGamut($text);
584
	}
585
	
586
	function runBasicBlockGamut($text) {
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
587
	#
588
	# Run block gamut tranformations, without hashing HTML blocks. This is 
589
	# useful when HTML blocks are known to be already hashed, like in the first
590
	# whole-document pass.
591
	#
592
		foreach ($this->block_gamut as $method => $priority) {
593
			$text = $this->$method($text);
594
		}
595
		
596
		# Finally form paragraph and restore hashed blocks.
597
		$text = $this->formParagraphs($text);
598
599
		return $text;
600
	}
601
	
602
	
603
	function doHorizontalRules($text) {
0 ignored issues
show
Documentation introduced by
The return type could not be reliably inferred; please add a @return annotation.

Our type inference engine in quite powerful, but sometimes the code does not provide enough clues to go by. In these cases we request you to add a @return annotation as described here.

Loading history...
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
604
		# Do Horizontal Rules:
605
		return preg_replace(
606
			'{
607
				^[ ]{0,3}	# Leading space
608
				([-*_])		# $1: First marker
609
				(?>			# Repeated marker group
610
					[ ]{0,2}	# Zero, one, or two spaces.
611
					\1			# Marker character
612
				){2,}		# Group repeated at least twice
613
				[ ]*		# Tailing spaces
614
				$			# End of line.
615
			}mx',
616
			"\n".$this->hashBlock("<hr$this->empty_element_suffix")."\n", 
617
			$text);
618
	}
619
620
621
	var $span_gamut = array(
622
	#
623
	# These are all the transformations that occur *within* block-level
624
	# tags like paragraphs, headers, and list items.
625
	#
626
		# Process character escapes, code spans, and inline HTML
627
		# in one shot.
628
		"parseSpan"           => -30,
629
630
		# Process anchor and image tags. Images must come first,
631
		# because ![foo][f] looks like an anchor.
632
		"doImages"            =>  10,
633
		"doAnchors"           =>  20,
634
		
635
		# Make links out of things like `<http://example.com/>`
636
		# Must come after doAnchors, because you can use < and >
637
		# delimiters in inline links like [this](<url>).
638
		"doAutoLinks"         =>  30,
639
		"encodeAmpsAndAngles" =>  40,
640
641
		"doItalicsAndBold"    =>  50,
642
		"doHardBreaks"        =>  60,
643
		);
644
645
	function runSpanGamut($text) {
0 ignored issues
show
Documentation introduced by
The return type could not be reliably inferred; please add a @return annotation.

Our type inference engine in quite powerful, but sometimes the code does not provide enough clues to go by. In these cases we request you to add a @return annotation as described here.

Loading history...
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
646
	#
647
	# Run span gamut tranformations.
648
	#
649
		foreach ($this->span_gamut as $method => $priority) {
650
			$text = $this->$method($text);
651
		}
652
653
		return $text;
654
	}
655
	
656
	
657
	function doHardBreaks($text) {
0 ignored issues
show
Documentation introduced by
The return type could not be reliably inferred; please add a @return annotation.

Our type inference engine in quite powerful, but sometimes the code does not provide enough clues to go by. In these cases we request you to add a @return annotation as described here.

Loading history...
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
658
		# Do hard breaks:
659
		return preg_replace_callback('/ {2,}\n/', 
660
			array(&$this, '_doHardBreaks_callback'), $text);
661
	}
662
	function _doHardBreaks_callback($matches) {
0 ignored issues
show
Unused Code introduced by
The parameter $matches is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
663
		return $this->hashPart("<br$this->empty_element_suffix\n");
664
	}
665
666
667
	function doAnchors($text) {
0 ignored issues
show
Documentation introduced by
The return type could not be reliably inferred; please add a @return annotation.

Our type inference engine in quite powerful, but sometimes the code does not provide enough clues to go by. In these cases we request you to add a @return annotation as described here.

Loading history...
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
668
	#
669
	# Turn Markdown link shortcuts into XHTML <a> tags.
670
	#
671
		if ($this->in_anchor) return $text;
672
		$this->in_anchor = true;
673
		
674
		#
675
		# First, handle reference-style links: [link text] [id]
676
		#
677
		$text = preg_replace_callback('{
678
			(					# wrap whole match in $1
679
			  \[
680
				('.$this->nested_brackets_re.')	# link text = $2
681
			  \]
682
683
			  [ ]?				# one optional space
684
			  (?:\n[ ]*)?		# one optional newline followed by spaces
685
686
			  \[
687
				(.*?)		# id = $3
688
			  \]
689
			)
690
			}xs',
691
			array(&$this, '_doAnchors_reference_callback'), $text);
692
693
		#
694
		# Next, inline-style links: [link text](url "optional title")
695
		#
696
		$text = preg_replace_callback('{
697
			(				# wrap whole match in $1
698
			  \[
699
				('.$this->nested_brackets_re.')	# link text = $2
700
			  \]
701
			  \(			# literal paren
702
				[ ]*
703
				(?:
704
					<(\S*)>	# href = $3
705
				|
706
					('.$this->nested_url_parenthesis_re.')	# href = $4
707
				)
708
				[ ]*
709
				(			# $5
710
				  ([\'"])	# quote char = $6
711
				  (.*?)		# Title = $7
712
				  \6		# matching quote
713
				  [ ]*	# ignore any spaces/tabs between closing quote and )
714
				)?			# title is optional
715
			  \)
716
			)
717
			}xs',
718
			array(&$this, '_DoAnchors_inline_callback'), $text);
719
720
		#
721
		# Last, handle reference-style shortcuts: [link text]
722
		# These must come last in case you've also got [link test][1]
723
		# or [link test](/foo)
724
		#
725
//		$text = preg_replace_callback('{
726
//			(					# wrap whole match in $1
727
//			  \[
728
//				([^\[\]]+)		# link text = $2; can\'t contain [ or ]
729
//			  \]
730
//			)
731
//			}xs',
732
//			array(&$this, '_doAnchors_reference_callback'), $text);
733
734
		$this->in_anchor = false;
735
		return $text;
736
	}
737
	function _doAnchors_reference_callback($matches) {
0 ignored issues
show
Documentation introduced by
The return type could not be reliably inferred; please add a @return annotation.

Our type inference engine in quite powerful, but sometimes the code does not provide enough clues to go by. In these cases we request you to add a @return annotation as described here.

Loading history...
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
738
		$whole_match =  $matches[1];
739
		$link_text   =  $matches[2];
740
		$link_id     =& $matches[3];
741
742
		if ($link_id == "") {
743
			# for shortcut links like [this][] or [this].
744
			$link_id = $link_text;
745
		}
746
		
747
		# lower-case and turn embedded newlines into spaces
748
		$link_id = strtolower($link_id);
749
		$link_id = preg_replace('{[ ]?\n}', ' ', $link_id);
750
751
		if (isset($this->urls[$link_id])) {
752
			$url = $this->urls[$link_id];
753
			$url = $this->encodeAttribute($url);
754
			
755
			$result = "<a href=\"$url\"";
756 View Code Duplication
			if ( isset( $this->titles[$link_id] ) ) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across 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...
757
				$title = $this->titles[$link_id];
758
				$title = $this->encodeAttribute($title);
759
				$result .=  " title=\"$title\"";
760
			}
761
		
762
			$link_text = $this->runSpanGamut($link_text);
763
			$result .= ">$link_text</a>";
764
			$result = $this->hashPart($result);
765
		}
766
		else {
767
			$result = $whole_match;
768
		}
769
		return $result;
770
	}
771 View Code Duplication
	function _doAnchors_inline_callback($matches) {
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
Duplication introduced by
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...
772
		$whole_match	=  $matches[1];
0 ignored issues
show
Unused Code introduced by
$whole_match is not used, you could remove the assignment.

This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.

$myVar = 'Value';
$higher = false;

if (rand(1, 6) > 3) {
    $higher = true;
} else {
    $higher = false;
}

Both the $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

Loading history...
773
		$link_text		=  $this->runSpanGamut($matches[2]);
774
		$url			=  $matches[3] == '' ? $matches[4] : $matches[3];
775
		$title			=& $matches[7];
776
777
		$url = $this->encodeAttribute($url);
778
779
		$result = "<a href=\"$url\"";
780
		if (isset($title)) {
781
			$title = $this->encodeAttribute($title);
782
			$result .=  " title=\"$title\"";
783
		}
784
		
785
		$link_text = $this->runSpanGamut($link_text);
786
		$result .= ">$link_text</a>";
787
788
		return $this->hashPart($result);
789
	}
790
791
792
	function doImages($text) {
0 ignored issues
show
Documentation introduced by
The return type could not be reliably inferred; please add a @return annotation.

Our type inference engine in quite powerful, but sometimes the code does not provide enough clues to go by. In these cases we request you to add a @return annotation as described here.

Loading history...
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
793
	#
794
	# Turn Markdown image shortcuts into <img> tags.
795
	#
796
		#
797
		# First, handle reference-style labeled images: ![alt text][id]
798
		#
799
		$text = preg_replace_callback('{
800
			(				# wrap whole match in $1
801
			  !\[
802
				('.$this->nested_brackets_re.')		# alt text = $2
803
			  \]
804
805
			  [ ]?				# one optional space
806
			  (?:\n[ ]*)?		# one optional newline followed by spaces
807
808
			  \[
809
				(.*?)		# id = $3
810
			  \]
811
812
			)
813
			}xs', 
814
			array(&$this, '_doImages_reference_callback'), $text);
815
816
		#
817
		# Next, handle inline images:  ![alt text](url "optional title")
818
		# Don't forget: encode * and _
819
		#
820
		$text = preg_replace_callback('{
821
			(				# wrap whole match in $1
822
			  !\[
823
				('.$this->nested_brackets_re.')		# alt text = $2
824
			  \]
825
			  \s?			# One optional whitespace character
826
			  \(			# literal paren
827
				[ ]*
828
				(?:
829
					<(\S*)>	# src url = $3
830
				|
831
					('.$this->nested_url_parenthesis_re.')	# src url = $4
832
				)
833
				[ ]*
834
				(			# $5
835
				  ([\'"])	# quote char = $6
836
				  (.*?)		# title = $7
837
				  \6		# matching quote
838
				  [ ]*
839
				)?			# title is optional
840
			  \)
841
			)
842
			}xs',
843
			array(&$this, '_doImages_inline_callback'), $text);
844
845
		return $text;
846
	}
847
	function _doImages_reference_callback($matches) {
0 ignored issues
show
Documentation introduced by
The return type could not be reliably inferred; please add a @return annotation.

Our type inference engine in quite powerful, but sometimes the code does not provide enough clues to go by. In these cases we request you to add a @return annotation as described here.

Loading history...
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
848
		$whole_match = $matches[1];
849
		$alt_text    = $matches[2];
850
		$link_id     = strtolower($matches[3]);
851
852
		if ($link_id == "") {
853
			$link_id = strtolower($alt_text); # for shortcut links like ![this][].
854
		}
855
856
		$alt_text = $this->encodeAttribute($alt_text);
857
		if (isset($this->urls[$link_id])) {
858
			$url = $this->encodeAttribute($this->urls[$link_id]);
859
			$result = "<img src=\"$url\" alt=\"$alt_text\"";
860 View Code Duplication
			if (isset($this->titles[$link_id])) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across 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...
861
				$title = $this->titles[$link_id];
862
				$title = $this->encodeAttribute($title);
863
				$result .=  " title=\"$title\"";
864
			}
865
			$result .= $this->empty_element_suffix;
866
			$result = $this->hashPart($result);
867
		}
868
		else {
869
			# If there's no such link ID, leave intact:
870
			$result = $whole_match;
871
		}
872
873
		return $result;
874
	}
875 View Code Duplication
	function _doImages_inline_callback($matches) {
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
Duplication introduced by
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...
876
		$whole_match	= $matches[1];
0 ignored issues
show
Unused Code introduced by
$whole_match is not used, you could remove the assignment.

This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.

$myVar = 'Value';
$higher = false;

if (rand(1, 6) > 3) {
    $higher = true;
} else {
    $higher = false;
}

Both the $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

Loading history...
877
		$alt_text		= $matches[2];
878
		$url			= $matches[3] == '' ? $matches[4] : $matches[3];
879
		$title			=& $matches[7];
880
881
		$alt_text = $this->encodeAttribute($alt_text);
882
		$url = $this->encodeAttribute($url);
883
		$result = "<img src=\"$url\" alt=\"$alt_text\"";
884
		if (isset($title)) {
885
			$title = $this->encodeAttribute($title);
886
			$result .=  " title=\"$title\""; # $title already quoted
887
		}
888
		$result .= $this->empty_element_suffix;
889
890
		return $this->hashPart($result);
891
	}
892
893
894 View Code Duplication
	function doHeaders($text) {
0 ignored issues
show
Documentation introduced by
The return type could not be reliably inferred; please add a @return annotation.

Our type inference engine in quite powerful, but sometimes the code does not provide enough clues to go by. In these cases we request you to add a @return annotation as described here.

Loading history...
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
Duplication introduced by
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...
895
		# Setext-style headers:
896
		#	  Header 1
897
		#	  ========
898
		#  
899
		#	  Header 2
900
		#	  --------
901
		#
902
		$text = preg_replace_callback('{ ^(.+?)[ ]*\n(=+|-+)[ ]*\n+ }mx',
903
			array(&$this, '_doHeaders_callback_setext'), $text);
904
905
		# atx-style headers:
906
		#	# Header 1
907
		#	## Header 2
908
		#	## Header 2 with closing hashes ##
909
		#	...
910
		#	###### Header 6
911
		#
912
		$text = preg_replace_callback('{
913
				^(\#{1,6})	# $1 = string of #\'s
914
				[ ]*
915
				(.+?)		# $2 = Header text
916
				[ ]*
917
				\#*			# optional closing #\'s (not counted)
918
				\n+
919
			}xm',
920
			array(&$this, '_doHeaders_callback_atx'), $text);
921
922
		return $text;
923
	}
924
	function _doHeaders_callback_setext($matches) {
0 ignored issues
show
Documentation introduced by
The return type could not be reliably inferred; please add a @return annotation.

Our type inference engine in quite powerful, but sometimes the code does not provide enough clues to go by. In these cases we request you to add a @return annotation as described here.

Loading history...
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
925
		# Terrible hack to check we haven't found an empty list item.
926 View Code Duplication
		if ($matches[2] == '-' && preg_match('{^-(?: |$)}', $matches[1]))
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across 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...
927
			return $matches[0];
928
		
929
		$level = $matches[2]{0} == '=' ? 1 : 2;
930
		$block = "<h$level>".$this->runSpanGamut($matches[1])."</h$level>";
931
		return "\n" . $this->hashBlock($block) . "\n\n";
932
	}
933
	function _doHeaders_callback_atx($matches) {
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
934
		$level = strlen($matches[1]);
935
		$block = "<h$level>".$this->runSpanGamut($matches[2])."</h$level>";
936
		return "\n" . $this->hashBlock($block) . "\n\n";
937
	}
938
939
940
	function doLists($text) {
0 ignored issues
show
Documentation introduced by
The return type could not be reliably inferred; please add a @return annotation.

Our type inference engine in quite powerful, but sometimes the code does not provide enough clues to go by. In these cases we request you to add a @return annotation as described here.

Loading history...
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
941
	#
942
	# Form HTML ordered (numbered) and unordered (bulleted) lists.
943
	#
944
		$less_than_tab = $this->tab_width - 1;
945
946
		# Re-usable patterns to match list item bullets and number markers:
947
		$marker_ul_re  = '[*+-]';
948
		$marker_ol_re  = '\d+[.]';
949
		$marker_any_re = "(?:$marker_ul_re|$marker_ol_re)";
0 ignored issues
show
Unused Code introduced by
$marker_any_re is not used, you could remove the assignment.

This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.

$myVar = 'Value';
$higher = false;

if (rand(1, 6) > 3) {
    $higher = true;
} else {
    $higher = false;
}

Both the $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

Loading history...
950
951
		$markers_relist = array($marker_ul_re, $marker_ol_re);
952
953
		foreach ($markers_relist as $marker_re) {
954
			# Re-usable pattern to match any entirel ul or ol list:
955
			$whole_list_re = '
956
				(								# $1 = whole list
957
				  (								# $2
958
					[ ]{0,'.$less_than_tab.'}
959
					('.$marker_re.')			# $3 = first list item marker
960
					[ ]+
961
				  )
962
				  (?s:.+?)
963
				  (								# $4
964
					  \z
965
					|
966
					  \n{2,}
967
					  (?=\S)
968
					  (?!						# Negative lookahead for another list item marker
969
						[ ]*
970
						'.$marker_re.'[ ]+
971
					  )
972
				  )
973
				)
974
			'; // mx
975
			
976
			# We use a different prefix before nested lists than top-level lists.
977
			# See extended comment in _ProcessListItems().
978
		
979
			if ($this->list_level) {
980
				$text = preg_replace_callback('{
981
						^
982
						'.$whole_list_re.'
983
					}mx',
984
					array(&$this, '_doLists_callback'), $text);
985
			}
986
			else {
987
				$text = preg_replace_callback('{
988
						(?:(?<=\n)\n|\A\n?) # Must eat the newline
989
						'.$whole_list_re.'
990
					}mx',
991
					array(&$this, '_doLists_callback'), $text);
992
			}
993
		}
994
995
		return $text;
996
	}
997
	function _doLists_callback($matches) {
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
998
		# Re-usable patterns to match list item bullets and number markers:
999
		$marker_ul_re  = '[*+-]';
1000
		$marker_ol_re  = '\d+[.]';
1001
		$marker_any_re = "(?:$marker_ul_re|$marker_ol_re)";
0 ignored issues
show
Unused Code introduced by
$marker_any_re is not used, you could remove the assignment.

This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.

$myVar = 'Value';
$higher = false;

if (rand(1, 6) > 3) {
    $higher = true;
} else {
    $higher = false;
}

Both the $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

Loading history...
1002
		
1003
		$list = $matches[1];
1004
		$list_type = preg_match("/$marker_ul_re/", $matches[3]) ? "ul" : "ol";
1005
		
1006
		$marker_any_re = ( $list_type == "ul" ? $marker_ul_re : $marker_ol_re );
1007
		
1008
		$list .= "\n";
1009
		$result = $this->processListItems($list, $marker_any_re);
1010
		
1011
		$result = $this->hashBlock("<$list_type>\n" . $result . "</$list_type>");
1012
		return "\n". $result ."\n\n";
1013
	}
1014
1015
	var $list_level = 0;
1016
1017
	/**
1018
	 * @param string $list_str
1019
	 * @param string $marker_any_re
1020
	 */
1021
	function processListItems($list_str, $marker_any_re) {
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
1022
	#
1023
	#	Process the contents of a single ordered or unordered list, splitting it
1024
	#	into individual list items.
1025
	#
1026
		# The $this->list_level global keeps track of when we're inside a list.
1027
		# Each time we enter a list, we increment it; when we leave a list,
1028
		# we decrement. If it's zero, we're not in a list anymore.
1029
		#
1030
		# We do this because when we're not inside a list, we want to treat
1031
		# something like this:
1032
		#
1033
		#		I recommend upgrading to version
1034
		#		8. Oops, now this line is treated
1035
		#		as a sub-list.
1036
		#
1037
		# As a single paragraph, despite the fact that the second line starts
1038
		# with a digit-period-space sequence.
1039
		#
1040
		# Whereas when we're inside a list (or sub-list), that line will be
1041
		# treated as the start of a sub-list. What a kludge, huh? This is
1042
		# an aspect of Markdown's syntax that's hard to parse perfectly
1043
		# without resorting to mind-reading. Perhaps the solution is to
1044
		# change the syntax rules such that sub-lists must start with a
1045
		# starting cardinal number; e.g. "1." or "a.".
1046
		
1047
		$this->list_level++;
1048
1049
		# trim trailing blank lines:
1050
		$list_str = preg_replace("/\n{2,}\\z/", "\n", $list_str);
1051
1052
		$list_str = preg_replace_callback('{
1053
			(\n)?							# leading line = $1
1054
			(^[ ]*)							# leading whitespace = $2
1055
			('.$marker_any_re.'				# list marker and space = $3
1056
				(?:[ ]+|(?=\n))	# space only required if item is not empty
1057
			)
1058
			((?s:.*?))						# list item text   = $4
1059
			(?:(\n+(?=\n))|\n)				# tailing blank line = $5
1060
			(?= \n* (\z | \2 ('.$marker_any_re.') (?:[ ]+|(?=\n))))
1061
			}xm',
1062
			array(&$this, '_processListItems_callback'), $list_str);
1063
1064
		$this->list_level--;
1065
		return $list_str;
1066
	}
1067
	function _processListItems_callback($matches) {
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
1068
		$item = $matches[4];
1069
		$leading_line =& $matches[1];
1070
		$leading_space =& $matches[2];
1071
		$marker_space = $matches[3];
1072
		$tailing_blank_line =& $matches[5];
1073
1074 View Code Duplication
		if ($leading_line || $tailing_blank_line || 
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across 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...
1075
			preg_match('/\n{2,}/', $item))
1076
		{
1077
			# Replace marker with the appropriate whitespace indentation
1078
			$item = $leading_space . str_repeat(' ', strlen($marker_space)) . $item;
1079
			$item = $this->runBlockGamut($this->outdent($item)."\n");
1080
		}
1081
		else {
1082
			# Recursion for sub-lists:
1083
			$item = $this->doLists($this->outdent($item));
1084
			$item = preg_replace('/\n+$/', '', $item);
1085
			$item = $this->runSpanGamut($item);
1086
		}
1087
1088
		return "<li>" . $item . "</li>\n";
1089
	}
1090
1091
1092
	function doCodeBlocks($text) {
0 ignored issues
show
Documentation introduced by
The return type could not be reliably inferred; please add a @return annotation.

Our type inference engine in quite powerful, but sometimes the code does not provide enough clues to go by. In these cases we request you to add a @return annotation as described here.

Loading history...
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
1093
	#
1094
	#	Process Markdown `<pre><code>` blocks.
1095
	#
1096
		$text = preg_replace_callback('{
1097
				(?:\n\n|\A\n?)
1098
				(	            # $1 = the code block -- one or more lines, starting with a space/tab
1099
				  (?>
1100
					[ ]{'.$this->tab_width.'}  # Lines must start with a tab or a tab-width of spaces
1101
					.*\n+
1102
				  )+
1103
				)
1104
				((?=^[ ]{0,'.$this->tab_width.'}\S)|\Z)	# Lookahead for non-space at line-start, or end of doc
1105
			}xm',
1106
			array(&$this, '_doCodeBlocks_callback'), $text);
1107
1108
		return $text;
1109
	}
1110
	function _doCodeBlocks_callback($matches) {
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
1111
		$codeblock = $matches[1];
1112
1113
		$codeblock = $this->outdent($codeblock);
1114
		$codeblock = htmlspecialchars($codeblock, ENT_NOQUOTES);
1115
1116
		# trim leading newlines and trailing newlines
1117
		$codeblock = preg_replace('/\A\n+|\n+\z/', '', $codeblock);
1118
1119
		$codeblock = "<pre><code>$codeblock\n</code></pre>";
1120
		return "\n\n".$this->hashBlock($codeblock)."\n\n";
1121
	}
1122
1123
1124
	/**
1125
	 * @param string $code
1126
	 */
1127
	function makeCodeSpan($code) {
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
1128
	#
1129
	# Create a code span markup for $code. Called from handleSpanToken.
1130
	#
1131
		$code = htmlspecialchars(trim($code), ENT_NOQUOTES);
1132
		return $this->hashPart("<code>$code</code>");
1133
	}
1134
1135
1136
	var $em_relist = array(
1137
		''  => '(?:(?<!\*)\*(?!\*)|(?<!_)_(?!_))(?=\S)(?![.,:;]\s)',
1138
		'*' => '(?<=\S)(?<!\*)\*(?!\*)',
1139
		'_' => '(?<=\S)(?<!_)_(?!_)',
1140
		);
1141
	var $strong_relist = array(
1142
		''   => '(?:(?<!\*)\*\*(?!\*)|(?<!_)__(?!_))(?=\S)(?![.,:;]\s)',
1143
		'**' => '(?<=\S)(?<!\*)\*\*(?!\*)',
1144
		'__' => '(?<=\S)(?<!_)__(?!_)',
1145
		);
1146
	var $em_strong_relist = array(
1147
		''    => '(?:(?<!\*)\*\*\*(?!\*)|(?<!_)___(?!_))(?=\S)(?![.,:;]\s)',
1148
		'***' => '(?<=\S)(?<!\*)\*\*\*(?!\*)',
1149
		'___' => '(?<=\S)(?<!_)___(?!_)',
1150
		);
1151
	var $em_strong_prepared_relist;
0 ignored issues
show
Comprehensibility Naming introduced by
The variable name $em_strong_prepared_relist exceeds the maximum configured length of 20.

Very long variable names usually make code harder to read. It is therefore recommended not to make variable names too verbose.

Loading history...
1152
	
1153
	function prepareItalicsAndBold() {
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
1154
	#
1155
	# Prepare regular expressions for seraching emphasis tokens in any
1156
	# context.
1157
	#
1158
		foreach ($this->em_relist as $em => $em_re) {
1159
			foreach ($this->strong_relist as $strong => $strong_re) {
1160
				# Construct list of allowed token expressions.
1161
				$token_relist = array();
1162
				if (isset($this->em_strong_relist["$em$strong"])) {
1163
					$token_relist[] = $this->em_strong_relist["$em$strong"];
1164
				}
1165
				$token_relist[] = $em_re;
1166
				$token_relist[] = $strong_re;
1167
				
1168
				# Construct master expression from list.
1169
				$token_re = '{('. implode('|', $token_relist) .')}';
1170
				$this->em_strong_prepared_relist["$em$strong"] = $token_re;
1171
			}
1172
		}
1173
	}
1174
	
1175
	function doItalicsAndBold($text) {
0 ignored issues
show
Documentation introduced by
The return type could not be reliably inferred; please add a @return annotation.

Our type inference engine in quite powerful, but sometimes the code does not provide enough clues to go by. In these cases we request you to add a @return annotation as described here.

Loading history...
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
1176
		$token_stack = array('');
1177
		$text_stack = array('');
1178
		$em = '';
0 ignored issues
show
Comprehensibility introduced by
Avoid variables with short names like $em. Configured minimum length is 3.

Short variable names may make your code harder to understand. Variable names should be self-descriptive. This check looks for variable names who are shorter than a configured minimum.

Loading history...
1179
		$strong = '';
1180
		$tree_char_em = false;
1181
		
1182
		while (1) {
1183
			#
1184
			# Get prepared regular expression for seraching emphasis tokens
1185
			# in current context.
1186
			#
1187
			$token_re = $this->em_strong_prepared_relist["$em$strong"];
1188
			
1189
			#
1190
			# Each loop iteration seach for the next emphasis token. 
1191
			# Each token is then passed to handleSpanToken.
1192
			#
1193
			$parts = preg_split($token_re, $text, 2, PREG_SPLIT_DELIM_CAPTURE);
1194
			$text_stack[0] .= $parts[0];
1195
			$token =& $parts[1];
1196
			$text =& $parts[2];
1197
			
1198 View Code Duplication
			if (empty($token)) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across 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...
1199
				# Reached end of text span: empty stack without emitting.
1200
				# any more emphasis.
1201
				while ($token_stack[0]) {
1202
					$text_stack[1] .= array_shift($token_stack);
1203
					$text_stack[0] .= array_shift($text_stack);
1204
				}
1205
				break;
1206
			}
1207
			
1208
			$token_len = strlen($token);
1209
			if ($tree_char_em) {
1210
				# Reached closing marker while inside a three-char emphasis.
1211
				if ($token_len == 3) {
1212
					# Three-char closing marker, close em and strong.
1213
					array_shift($token_stack);
1214
					$span = array_shift($text_stack);
1215
					$span = $this->runSpanGamut($span);
1216
					$span = "<strong><em>$span</em></strong>";
1217
					$text_stack[0] .= $this->hashPart($span);
1218
					$em = '';
1219
					$strong = '';
1220
				} else {
1221
					# Other closing marker: close one em or strong and
1222
					# change current token state to match the other
1223
					$token_stack[0] = str_repeat($token{0}, 3-$token_len);
1224
					$tag = $token_len == 2 ? "strong" : "em";
1225
					$span = $text_stack[0];
1226
					$span = $this->runSpanGamut($span);
1227
					$span = "<$tag>$span</$tag>";
1228
					$text_stack[0] = $this->hashPart($span);
1229
					$$tag = ''; # $$tag stands for $em or $strong
1230
				}
1231
				$tree_char_em = false;
1232
			} else if ($token_len == 3) {
1233
				if ($em) {
1234
					# Reached closing marker for both em and strong.
1235
					# Closing strong marker:
1236
					for ($i = 0; $i < 2; ++$i) {
1237
						$shifted_token = array_shift($token_stack);
1238
						$tag = strlen($shifted_token) == 2 ? "strong" : "em";
1239
						$span = array_shift($text_stack);
1240
						$span = $this->runSpanGamut($span);
1241
						$span = "<$tag>$span</$tag>";
1242
						$text_stack[0] .= $this->hashPart($span);
1243
						$$tag = ''; # $$tag stands for $em or $strong
1244
					}
1245
				} else {
1246
					# Reached opening three-char emphasis marker. Push on token 
1247
					# stack; will be handled by the special condition above.
1248
					$em = $token{0};
1249
					$strong = "$em$em";
1250
					array_unshift($token_stack, $token);
1251
					array_unshift($text_stack, '');
1252
					$tree_char_em = true;
1253
				}
1254
			} else if ($token_len == 2) {
1255
				if ($strong) {
1256
					# Unwind any dangling emphasis marker:
1257 View Code Duplication
					if (strlen($token_stack[0]) == 1) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across 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...
1258
						$text_stack[1] .= array_shift($token_stack);
1259
						$text_stack[0] .= array_shift($text_stack);
1260
					}
1261
					# Closing strong marker:
1262
					array_shift($token_stack);
1263
					$span = array_shift($text_stack);
1264
					$span = $this->runSpanGamut($span);
1265
					$span = "<strong>$span</strong>";
1266
					$text_stack[0] .= $this->hashPart($span);
1267
					$strong = '';
1268
				} else {
1269
					array_unshift($token_stack, $token);
1270
					array_unshift($text_stack, '');
1271
					$strong = $token;
1272
				}
1273
			} else {
1274
				# Here $token_len == 1
1275
				if ($em) {
1276
					if (strlen($token_stack[0]) == 1) {
1277
						# Closing emphasis marker:
1278
						array_shift($token_stack);
1279
						$span = array_shift($text_stack);
1280
						$span = $this->runSpanGamut($span);
1281
						$span = "<em>$span</em>";
1282
						$text_stack[0] .= $this->hashPart($span);
1283
						$em = '';
1284
					} else {
1285
						$text_stack[0] .= $token;
1286
					}
1287
				} else {
1288
					array_unshift($token_stack, $token);
1289
					array_unshift($text_stack, '');
1290
					$em = $token;
1291
				}
1292
			}
1293
		}
1294
		return $text_stack[0];
1295
	}
1296
1297
1298
	function doBlockQuotes($text) {
0 ignored issues
show
Documentation introduced by
The return type could not be reliably inferred; please add a @return annotation.

Our type inference engine in quite powerful, but sometimes the code does not provide enough clues to go by. In these cases we request you to add a @return annotation as described here.

Loading history...
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
1299
		$text = preg_replace_callback('/
1300
			  (								# Wrap whole match in $1
1301
				(?>
1302
				  ^[ ]*>[ ]?			# ">" at the start of a line
1303
					.+\n					# rest of the first line
1304
				  (.+\n)*					# subsequent consecutive lines
1305
				  \n*						# blanks
1306
				)+
1307
			  )
1308
			/xm',
1309
			array(&$this, '_doBlockQuotes_callback'), $text);
1310
1311
		return $text;
1312
	}
1313
	function _doBlockQuotes_callback($matches) {
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
1314
		$bq = $matches[1];
0 ignored issues
show
Comprehensibility introduced by
Avoid variables with short names like $bq. Configured minimum length is 3.

Short variable names may make your code harder to understand. Variable names should be self-descriptive. This check looks for variable names who are shorter than a configured minimum.

Loading history...
1315
		# trim one level of quoting - trim whitespace-only lines
1316
		$bq = preg_replace('/^[ ]*>[ ]?|^[ ]+$/m', '', $bq);
1317
		$bq = $this->runBlockGamut($bq);		# recurse
1318
1319
		$bq = preg_replace('/^/m', "  ", $bq);
1320
		# These leading spaces cause problem with <pre> content, 
1321
		# so we need to fix that:
1322
		$bq = preg_replace_callback('{(\s*<pre>.+?</pre>)}sx', 
1323
			array(&$this, '_DoBlockQuotes_callback2'), $bq);
1324
1325
		return "\n". $this->hashBlock("<blockquote>\n$bq\n</blockquote>")."\n\n";
1326
	}
1327
	function _doBlockQuotes_callback2($matches) {
0 ignored issues
show
Documentation introduced by
The return type could not be reliably inferred; please add a @return annotation.

Our type inference engine in quite powerful, but sometimes the code does not provide enough clues to go by. In these cases we request you to add a @return annotation as described here.

Loading history...
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
1328
		$pre = $matches[1];
1329
		$pre = preg_replace('/^  /m', '', $pre);
1330
		return $pre;
1331
	}
1332
1333
1334
	function formParagraphs($text) {
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
1335
	#
1336
	#	Params:
1337
	#		$text - string to process with html <p> tags
1338
	#
1339
		# Strip leading and trailing lines:
1340
		$text = preg_replace('/\A\n+|\n+\z/', '', $text);
1341
1342
		$grafs = preg_split('/\n{2,}/', $text, -1, PREG_SPLIT_NO_EMPTY);
1343
1344
		#
1345
		# Wrap <p> tags and unhashify HTML blocks
1346
		#
1347
		foreach ($grafs as $key => $value) {
1348
			if (!preg_match('/^B\x1A[0-9]+B$/', $value)) {
1349
				# Is a paragraph.
1350
				$value = $this->runSpanGamut($value);
1351
				$value = preg_replace('/^([ ]*)/', "<p>", $value);
1352
				$value .= "</p>";
1353
				$grafs[$key] = $this->unhash($value);
1354
			}
1355
			else {
1356
				# Is a block.
1357
				# Modify elements of @grafs in-place...
1358
				$graf = $value;
1359
				$block = $this->html_hashes[$graf];
1360
				$graf = $block;
1361
//				if (preg_match('{
1362
//					\A
1363
//					(							# $1 = <div> tag
1364
//					  <div  \s+
1365
//					  [^>]*
1366
//					  \b
1367
//					  markdown\s*=\s*  ([\'"])	#	$2 = attr quote char
1368
//					  1
1369
//					  \2
1370
//					  [^>]*
1371
//					  >
1372
//					)
1373
//					(							# $3 = contents
1374
//					.*
1375
//					)
1376
//					(</div>)					# $4 = closing tag
1377
//					\z
1378
//					}xs', $block, $matches))
1379
//				{
1380
//					list(, $div_open, , $div_content, $div_close) = $matches;
1381
//
1382
//					# We can't call Markdown(), because that resets the hash;
1383
//					# that initialization code should be pulled into its own sub, though.
1384
//					$div_content = $this->hashHTMLBlocks($div_content);
1385
//					
1386
//					# Run document gamut methods on the content.
1387
//					foreach ($this->document_gamut as $method => $priority) {
1388
//						$div_content = $this->$method($div_content);
1389
//					}
1390
//
1391
//					$div_open = preg_replace(
1392
//						'{\smarkdown\s*=\s*([\'"]).+?\1}', '', $div_open);
1393
//
1394
//					$graf = $div_open . "\n" . $div_content . "\n" . $div_close;
1395
//				}
1396
				$grafs[$key] = $graf;
1397
			}
1398
		}
1399
1400
		return implode("\n\n", $grafs);
1401
	}
1402
1403
1404
	function encodeAttribute($text) {
0 ignored issues
show
Documentation introduced by
The return type could not be reliably inferred; please add a @return annotation.

Our type inference engine in quite powerful, but sometimes the code does not provide enough clues to go by. In these cases we request you to add a @return annotation as described here.

Loading history...
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
1405
	#
1406
	# Encode text for a double-quoted HTML attribute. This function
1407
	# is *not* suitable for attributes enclosed in single quotes.
1408
	#
1409
		$text = $this->encodeAmpsAndAngles($text);
1410
		$text = str_replace('"', '&quot;', $text);
1411
		return $text;
1412
	}
1413
	
1414
	
1415
	function encodeAmpsAndAngles($text) {
0 ignored issues
show
Documentation introduced by
The return type could not be reliably inferred; please add a @return annotation.

Our type inference engine in quite powerful, but sometimes the code does not provide enough clues to go by. In these cases we request you to add a @return annotation as described here.

Loading history...
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
1416
	#
1417
	# Smart processing for ampersands and angle brackets that need to 
1418
	# be encoded. Valid character entities are left alone unless the
1419
	# no-entities mode is set.
1420
	#
1421
		if ($this->no_entities) {
1422
			$text = str_replace('&', '&amp;', $text);
1423
		} else {
1424
			# Ampersand-encoding based entirely on Nat Irons's Amputator
1425
			# MT plugin: <http://bumppo.net/projects/amputator/>
1426
			$text = preg_replace('/&(?!#?[xX]?(?:[0-9a-fA-F]+|\w+);)/', 
1427
								'&amp;', $text);;
1428
		}
1429
		# Encode remaining <'s
1430
		$text = str_replace('<', '&lt;', $text);
1431
1432
		return $text;
1433
	}
1434
1435
1436
	function doAutoLinks($text) {
0 ignored issues
show
Documentation introduced by
The return type could not be reliably inferred; please add a @return annotation.

Our type inference engine in quite powerful, but sometimes the code does not provide enough clues to go by. In these cases we request you to add a @return annotation as described here.

Loading history...
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
1437
		$text = preg_replace_callback('{<((https?|ftp|dict):[^\'">\s]+)>}i', 
1438
			array(&$this, '_doAutoLinks_url_callback'), $text);
1439
1440
		# Email addresses: <[email protected]>
1441
		$text = preg_replace_callback('{
1442
			<
1443
			(?:mailto:)?
1444
			(
1445
				[-.\w\x80-\xFF]+
1446
				\@
1447
				[-a-z0-9\x80-\xFF]+(\.[-a-z0-9\x80-\xFF]+)*\.[a-z]+
1448
			)
1449
			>
1450
			}xi',
1451
			array(&$this, '_doAutoLinks_email_callback'), $text);
1452
1453
		return $text;
1454
	}
1455
	function _doAutoLinks_url_callback($matches) {
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
1456
		$url = $this->encodeAttribute($matches[1]);
1457
		$link = "<a href=\"$url\">$url</a>";
1458
		return $this->hashPart($link);
1459
	}
1460
	function _doAutoLinks_email_callback($matches) {
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
1461
		$address = $matches[1];
1462
		$link = $this->encodeEmailAddress($address);
1463
		return $this->hashPart($link);
1464
	}
1465
1466
1467
	function encodeEmailAddress($addr) {
0 ignored issues
show
Documentation introduced by
The return type could not be reliably inferred; please add a @return annotation.

Our type inference engine in quite powerful, but sometimes the code does not provide enough clues to go by. In these cases we request you to add a @return annotation as described here.

Loading history...
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
1468
	#
1469
	#	Input: an email address, e.g. "[email protected]"
1470
	#
1471
	#	Output: the email address as a mailto link, with each character
1472
	#		of the address encoded as either a decimal or hex entity, in
1473
	#		the hopes of foiling most address harvesting spam bots. E.g.:
1474
	#
1475
	#	  <p><a href="&#109;&#x61;&#105;&#x6c;&#116;&#x6f;&#58;&#x66;o&#111;
1476
	#        &#x40;&#101;&#x78;&#97;&#x6d;&#112;&#x6c;&#101;&#46;&#x63;&#111;
1477
	#        &#x6d;">&#x66;o&#111;&#x40;&#101;&#x78;&#97;&#x6d;&#112;&#x6c;
1478
	#        &#101;&#46;&#x63;&#111;&#x6d;</a></p>
1479
	#
1480
	#	Based by a filter by Matthew Wickline, posted to BBEdit-Talk.
1481
	#   With some optimizations by Milian Wolff.
1482
	#
1483
		$addr = "mailto:" . $addr;
1484
		$chars = preg_split('/(?<!^)(?!$)/', $addr);
1485
		$seed = (int)abs(crc32($addr) / strlen($addr)); # Deterministic seed.
1486
		
1487
		foreach ($chars as $key => $char) {
1488
			$ord = ord($char);
1489
			# Ignore non-ascii chars.
1490
			if ($ord < 128) {
1491
				$r = ($seed * (1 + $key)) % 100; # Pseudo-random function.
1492
				# roughly 10% raw, 45% hex, 45% dec
1493
				# '@' *must* be encoded. I insist.
1494
				if ($r > 90 && $char != '@') /* do nothing */;
1495
				else if ($r < 45) $chars[$key] = '&#x'.dechex($ord).';';
1496
				else              $chars[$key] = '&#'.$ord.';';
1497
			}
1498
		}
1499
		
1500
		$addr = implode('', $chars);
1501
		$text = implode('', array_slice($chars, 7)); # text without `mailto:`
1502
		$addr = "<a href=\"$addr\">$text</a>";
1503
1504
		return $addr;
1505
	}
1506
1507
1508
	function parseSpan($str) {
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
1509
	#
1510
	# Take the string $str and parse it into tokens, hashing embeded HTML,
1511
	# escaped characters and handling code spans.
1512
	#
1513
		$output = '';
1514
		
1515
		$span_re = '{
1516
				(
1517
					\\\\'.$this->escape_chars_re.'
1518
				|
1519
					(?<![`\\\\])
1520
					`+						# code span marker
1521
			'.( $this->no_markup ? '' : '
1522
				|
1523
					<!--    .*?     -->		# comment
1524
				|
1525
					<\?.*?\?> | <%.*?%>		# processing instruction
1526
				|
1527
					<[/!$]?[-a-zA-Z0-9:]+	# regular tags
1528
					(?>
1529
						\s
1530
						(?>[^"\'>]+|"[^"]*"|\'[^\']*\')*
1531
					)?
1532
					>
1533
			').'
1534
				)
1535
				}xs';
1536
1537
		while (1) {
1538
			#
1539
			# Each loop iteration seach for either the next tag, the next 
1540
			# openning code span marker, or the next escaped character. 
1541
			# Each token is then passed to handleSpanToken.
1542
			#
1543
			$parts = preg_split($span_re, $str, 2, PREG_SPLIT_DELIM_CAPTURE);
1544
			
1545
			# Create token from text preceding tag.
1546
			if ($parts[0] != "") {
1547
				$output .= $parts[0];
1548
			}
1549
			
1550
			# Check if we reach the end.
1551
			if (isset($parts[1])) {
1552
				$output .= $this->handleSpanToken($parts[1], $parts[2]);
1553
				$str = $parts[2];
1554
			}
1555
			else {
1556
				break;
1557
			}
1558
		}
1559
		
1560
		return $output;
1561
	}
1562
	
1563
	
1564
	function handleSpanToken($token, &$str) {
0 ignored issues
show
Documentation introduced by
The return type could not be reliably inferred; please add a @return annotation.

Our type inference engine in quite powerful, but sometimes the code does not provide enough clues to go by. In these cases we request you to add a @return annotation as described here.

Loading history...
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
1565
	#
1566
	# Handle $token provided by parseSpan by determining its nature and 
1567
	# returning the corresponding value that should replace it.
1568
	#
1569
		switch ($token{0}) {
1570
			case "\\":
1571
				return $this->hashPart("&#". ord($token{1}). ";");
1572
			case "`":
1573
				# Search for end marker in remaining text.
1574
				if (preg_match('/^(.*?[^`])'.preg_quote($token).'(?!`)(.*)$/sm', 
1575
					$str, $matches))
1576
				{
1577
					$str = $matches[2];
1578
					$codespan = $this->makeCodeSpan($matches[1]);
1579
					return $this->hashPart($codespan);
1580
				}
1581
				return $token; // return as text since no ending marker found.
1582
			default:
1583
				return $this->hashPart($token);
1584
		}
1585
	}
1586
1587
1588
	function outdent($text) {
0 ignored issues
show
Documentation introduced by
The return type could not be reliably inferred; please add a @return annotation.

Our type inference engine in quite powerful, but sometimes the code does not provide enough clues to go by. In these cases we request you to add a @return annotation as described here.

Loading history...
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
1589
	#
1590
	# Remove one level of line-leading tabs or spaces
1591
	#
1592
		return preg_replace('/^(\t|[ ]{1,'.$this->tab_width.'})/m', '', $text);
1593
	}
1594
1595
1596
	# String length function for detab. `_initDetab` will create a function to 
1597
	# hanlde UTF-8 if the default function does not exist.
1598
	var $utf8_strlen = 'mb_strlen';
1599
	
1600
	/**
1601
	 * @param string $text
1602
	 */
1603
	function detab($text) {
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
1604
	#
1605
	# Replace tabs with the appropriate amount of space.
1606
	#
1607
		# For each line we separate the line in blocks delemited by
1608
		# tab characters. Then we reconstruct every line by adding the 
1609
		# appropriate number of space between each blocks.
1610
		
1611
		$text = preg_replace_callback('/^.*\t.*$/m',
1612
			array(&$this, '_detab_callback'), $text);
1613
1614
		return $text;
1615
	}
1616
	function _detab_callback($matches) {
0 ignored issues
show
Documentation introduced by
The return type could not be reliably inferred; please add a @return annotation.

Our type inference engine in quite powerful, but sometimes the code does not provide enough clues to go by. In these cases we request you to add a @return annotation as described here.

Loading history...
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
1617
		$line = $matches[0];
1618
		$strlen = $this->utf8_strlen; # strlen function for UTF-8.
1619
		
1620
		# Split in blocks.
1621
		$blocks = explode("\t", $line);
1622
		# Add each blocks to the line.
1623
		$line = $blocks[0];
1624
		unset($blocks[0]); # Do not add first block twice.
1625
		foreach ($blocks as $block) {
1626
			# Calculate amount of space, insert spaces, insert block.
1627
			$amount = $this->tab_width - 
1628
				$strlen($line, 'UTF-8') % $this->tab_width;
1629
			$line .= str_repeat(" ", $amount) . $block;
1630
		}
1631
		return $line;
1632
	}
1633
	function _initDetab() {
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
1634
	#
1635
	# Check for the availability of the function in the `utf8_strlen` property
1636
	# (initially `mb_strlen`). If the function is not available, create a 
1637
	# function that will loosely count the number of UTF-8 characters with a
1638
	# regular expression.
1639
	#
1640
		if (function_exists($this->utf8_strlen)) return;
1641
		$this->utf8_strlen = create_function('$text', 'return preg_match_all(
1642
			"/[\\\\x00-\\\\xBF]|[\\\\xC0-\\\\xFF][\\\\x80-\\\\xBF]*/", 
1643
			$text, $m);');
1644
	}
1645
1646
1647
	function unhash($text) {
0 ignored issues
show
Documentation introduced by
The return type could not be reliably inferred; please add a @return annotation.

Our type inference engine in quite powerful, but sometimes the code does not provide enough clues to go by. In these cases we request you to add a @return annotation as described here.

Loading history...
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
1648
	#
1649
	# Swap back in all the tags hashed by _HashHTMLBlocks.
1650
	#
1651
		return preg_replace_callback('/(.)\x1A[0-9]+\1/', 
1652
			array(&$this, '_unhash_callback'), $text);
1653
	}
1654
	function _unhash_callback($matches) {
0 ignored issues
show
Documentation introduced by
The return type could not be reliably inferred; please add a @return annotation.

Our type inference engine in quite powerful, but sometimes the code does not provide enough clues to go by. In these cases we request you to add a @return annotation as described here.

Loading history...
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
1655
		return $this->html_hashes[$matches[0]];
1656
	}
1657
1658
}
1659
1660
1661
#
1662
# Markdown Extra Parser Class
1663
#
1664
1665
class MarkdownExtra_Parser extends Markdown_Parser {
1666
1667
	# Prefix for footnote ids.
1668
	var $fn_id_prefix = "";
1669
	
1670
	# Optional title attribute for footnote links and backlinks.
1671
	var $fn_link_title = MARKDOWN_FN_LINK_TITLE;
1672
	var $fn_backlink_title = MARKDOWN_FN_BACKLINK_TITLE;
1673
	
1674
	# Optional class attribute for footnote links and backlinks.
1675
	var $fn_link_class = MARKDOWN_FN_LINK_CLASS;
1676
	var $fn_backlink_class = MARKDOWN_FN_BACKLINK_CLASS;
1677
	
1678
	# Predefined abbreviations.
1679
	var $predef_abbr = array();
1680
1681
1682
	function MarkdownExtra_Parser() {
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
1683
	#
1684
	# Constructor function. Initialize the parser object.
1685
	#
1686
		# Add extra escapable characters before parent constructor 
1687
		# initialize the table.
1688
		$this->escape_chars .= ':|';
1689
		
1690
		# Insert extra document, block, and span transformations. 
1691
		# Parent constructor will do the sorting.
1692
		$this->document_gamut += array(
1693
			"doFencedCodeBlocks" => 5,
1694
			"stripFootnotes"     => 15,
1695
			"stripAbbreviations" => 25,
1696
			"appendFootnotes"    => 50,
1697
			);
1698
		$this->block_gamut += array(
1699
			"doFencedCodeBlocks" => 5,
1700
			"doTables"           => 15,
1701
			"doDefLists"         => 45,
1702
			);
1703
		$this->span_gamut += array(
1704
			"doFootnotes"        => 5,
1705
			"doAbbreviations"    => 70,
1706
			);
1707
		
1708
		parent::Markdown_Parser();
0 ignored issues
show
Comprehensibility Bug introduced by
It seems like you call parent on a different method (Markdown_Parser() instead of MarkdownExtra_Parser()). Are you sure this is correct? If so, you might want to change this to $this->Markdown_Parser().

This check looks for a call to a parent method whose name is different than the method from which it is called.

Consider the following code:

class Daddy
{
    protected function getFirstName()
    {
        return "Eidur";
    }

    protected function getSurName()
    {
        return "Gudjohnsen";
    }
}

class Son
{
    public function getFirstName()
    {
        return parent::getSurname();
    }
}

The getFirstName() method in the Son calls the wrong method in the parent class.

Loading history...
1709
	}
1710
	
1711
	
1712
	# Extra variables used during extra transformations.
1713
	var $footnotes = array();
1714
	var $footnotes_ordered = array();
1715
	var $abbr_desciptions = array();
1716
	var $abbr_word_re = '';
1717
	
1718
	# Give the current footnote number.
1719
	var $footnote_counter = 1;
1720
	
1721
	
1722
	function setup() {
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
1723
	#
1724
	# Setting up Extra-specific variables.
1725
	#
1726
		parent::setup();
1727
		
1728
		$this->footnotes = array();
1729
		$this->footnotes_ordered = array();
1730
		$this->abbr_desciptions = array();
1731
		$this->abbr_word_re = '';
1732
		$this->footnote_counter = 1;
1733
		
1734
		foreach ($this->predef_abbr as $abbr_word => $abbr_desc) {
1735
			if ($this->abbr_word_re)
1736
				$this->abbr_word_re .= '|';
1737
			$this->abbr_word_re .= preg_quote($abbr_word);
1738
			$this->abbr_desciptions[$abbr_word] = trim($abbr_desc);
1739
		}
1740
	}
1741
	
1742
	function teardown() {
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
1743
	#
1744
	# Clearing Extra-specific variables.
1745
	#
1746
		$this->footnotes = array();
1747
		$this->footnotes_ordered = array();
1748
		$this->abbr_desciptions = array();
1749
		$this->abbr_word_re = '';
1750
		
1751
		parent::teardown();
1752
	}
1753
	
1754
	
1755
	### HTML Block Parser ###
1756
	
1757
	# Tags that are always treated as block tags:
1758
	var $block_tags_re = 'p|div|h[1-6]|blockquote|pre|table|dl|ol|ul|address|form|fieldset|iframe|hr|legend';
1759
	
1760
	# Tags treated as block tags only if the opening tag is alone on it's line:
1761
	var $context_block_tags_re = 'script|noscript|math|ins|del';
0 ignored issues
show
Comprehensibility Naming introduced by
The variable name $context_block_tags_re exceeds the maximum configured length of 20.

Very long variable names usually make code harder to read. It is therefore recommended not to make variable names too verbose.

Loading history...
1762
	
1763
	# Tags where markdown="1" default to span mode:
1764
	var $contain_span_tags_re = 'p|h[1-6]|li|dd|dt|td|th|legend|address';
1765
	
1766
	# Tags which must not have their contents modified, no matter where 
1767
	# they appear:
1768
	var $clean_tags_re = 'script|math';
1769
	
1770
	# Tags that do not need to be closed.
1771
	var $auto_close_tags_re = 'hr|img';
1772
	
1773
1774
	function hashHTMLBlocks($text) {
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
1775
	#
1776
	# Hashify HTML Blocks and "clean tags".
1777
	#
1778
	# We only want to do this for block-level HTML tags, such as headers,
1779
	# lists, and tables. That's because we still want to wrap <p>s around
1780
	# "paragraphs" that are wrapped in non-block-level tags, such as anchors,
1781
	# phrase emphasis, and spans. The list of tags we're looking for is
1782
	# hard-coded.
1783
	#
1784
	# This works by calling _HashHTMLBlocks_InMarkdown, which then calls
1785
	# _HashHTMLBlocks_InHTML when it encounter block tags. When the markdown="1" 
1786
	# attribute is found whitin a tag, _HashHTMLBlocks_InHTML calls back
1787
	#  _HashHTMLBlocks_InMarkdown to handle the Markdown syntax within the tag.
1788
	# These two functions are calling each other. It's recursive!
1789
	#
1790
		#
1791
		# Call the HTML-in-Markdown hasher.
1792
		#
1793
		list($text, ) = $this->_hashHTMLBlocks_inMarkdown($text);
1794
		
1795
		return $text;
1796
	}
1797
	function _hashHTMLBlocks_inMarkdown($text, $indent = 0, 
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
1798
										$enclosing_tag_re = '', $span = false)
1799
	{
1800
	#
1801
	# Parse markdown text, calling _HashHTMLBlocks_InHTML for block tags.
1802
	#
1803
	# *   $indent is the number of space to be ignored when checking for code 
1804
	#     blocks. This is important because if we don't take the indent into 
1805
	#     account, something like this (which looks right) won't work as expected:
1806
	#
1807
	#     <div>
1808
	#         <div markdown="1">
1809
	#         Hello World.  <-- Is this a Markdown code block or text?
1810
	#         </div>  <-- Is this a Markdown code block or a real tag?
1811
	#     <div>
1812
	#
1813
	#     If you don't like this, just don't indent the tag on which
1814
	#     you apply the markdown="1" attribute.
1815
	#
1816
	# *   If $enclosing_tag_re is not empty, stops at the first unmatched closing 
1817
	#     tag with that name. Nested tags supported.
1818
	#
1819
	# *   If $span is true, text inside must treated as span. So any double 
1820
	#     newline will be replaced by a single newline so that it does not create 
1821
	#     paragraphs.
1822
	#
1823
	# Returns an array of that form: ( processed text , remaining text )
1824
	#
1825
		if ($text === '') return array('', '');
1826
1827
		# Regex to check for the presense of newlines around a block tag.
1828
		$newline_before_re = '/(?:^\n?|\n\n)*$/';
1829
		$newline_after_re = 
1830
			'{
1831
				^						# Start of text following the tag.
1832
				(?>[ ]*<!--.*?-->)?		# Optional comment.
1833
				[ ]*\n					# Must be followed by newline.
1834
			}xs';
1835
		
1836
		# Regex to match any tag.
1837
		$block_tag_re =
1838
			'{
1839
				(					# $2: Capture hole tag.
1840
					</?					# Any opening or closing tag.
1841
						(?>				# Tag name.
1842
							'.$this->block_tags_re.'			|
1843
							'.$this->context_block_tags_re.'	|
1844
							'.$this->clean_tags_re.'        	|
1845
							(?!\s)'.$enclosing_tag_re.'
1846
						)
1847
						(?:
1848
							(?=[\s"\'/a-zA-Z0-9])	# Allowed characters after tag name.
1849
							(?>
1850
								".*?"		|	# Double quotes (can contain `>`)
1851
								\'.*?\'   	|	# Single quotes (can contain `>`)
1852
								.+?				# Anything but quotes and `>`.
1853
							)*?
1854
						)?
1855
					>					# End of tag.
1856
				|
1857
					<!--    .*?     -->	# HTML Comment
1858
				|
1859
					<\?.*?\?> | <%.*?%>	# Processing instruction
1860
				|
1861
					<!\[CDATA\[.*?\]\]>	# CData Block
1862
				|
1863
					# Code span marker
1864
					`+
1865
				'. ( !$span ? ' # If not in span.
1866
				|
1867
					# Indented code block
1868
					(?> ^[ ]*\n? | \n[ ]*\n )
1869
					[ ]{'.($indent+4).'}[^\n]* \n
1870
					(?>
1871
						(?: [ ]{'.($indent+4).'}[^\n]* | [ ]* ) \n
1872
					)*
1873
				|
1874
					# Fenced code block marker
1875
					(?> ^ | \n )
1876
					[ ]{'.($indent).'}~~~+[ ]*\n
1877
				' : '' ). ' # End (if not is span).
1878
				)
1879
			}xs';
1880
1881
		
1882
		$depth = 0;		# Current depth inside the tag tree.
1883
		$parsed = "";	# Parsed text that will be returned.
1884
1885
		#
1886
		# Loop through every tag until we find the closing tag of the parent
1887
		# or loop until reaching the end of text if no parent tag specified.
1888
		#
1889
		do {
1890
			#
1891
			# Split the text using the first $tag_match pattern found.
1892
			# Text before  pattern will be first in the array, text after
1893
			# pattern will be at the end, and between will be any catches made 
1894
			# by the pattern.
1895
			#
1896
			$parts = preg_split($block_tag_re, $text, 2, 
1897
								PREG_SPLIT_DELIM_CAPTURE);
1898
			
1899
			# If in Markdown span mode, add a empty-string span-level hash 
1900
			# after each newline to prevent triggering any block element.
1901
			if ($span) {
1902
				$void = $this->hashPart("", ':');
1903
				$newline = "$void\n";
1904
				$parts[0] = $void . str_replace("\n", $newline, $parts[0]) . $void;
1905
			}
1906
			
1907
			$parsed .= $parts[0]; # Text before current tag.
1908
			
1909
			# If end of $text has been reached. Stop loop.
1910
			if (count($parts) < 3) {
1911
				$text = "";
1912
				break;
1913
			}
1914
			
1915
			$tag  = $parts[1]; # Tag to handle.
1916
			$text = $parts[2]; # Remaining text after current tag.
1917
			$tag_re = preg_quote($tag); # For use in a regular expression.
0 ignored issues
show
Unused Code introduced by
$tag_re is not used, you could remove the assignment.

This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.

$myVar = 'Value';
$higher = false;

if (rand(1, 6) > 3) {
    $higher = true;
} else {
    $higher = false;
}

Both the $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

Loading history...
1918
			
1919
			#
1920
			# Check for: Code span marker
1921
			#
1922
			if ($tag{0} == "`") {
1923
				# Find corresponding end marker.
1924
				$tag_re = preg_quote($tag);
1925 View Code Duplication
				if (preg_match('{^(?>.+?|\n(?!\n))*?(?<!`)'.$tag_re.'(?!`)}',
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across 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...
1926
					$text, $matches))
1927
				{
1928
					# End marker found: pass text unchanged until marker.
1929
					$parsed .= $tag . $matches[0];
1930
					$text = substr($text, strlen($matches[0]));
1931
				}
1932
				else {
1933
					# Unmatched marker: just skip it.
1934
					$parsed .= $tag;
1935
				}
1936
			}
1937
			#
1938
			# Check for: Indented code block or fenced code block marker.
1939
			#
1940
			else if ($tag{0} == "\n" || $tag{0} == "~") {
1941
				if ($tag{1} == "\n" || $tag{1} == " ") {
1942
					# Indented code block: pass it unchanged, will be handled 
1943
					# later.
1944
					$parsed .= $tag;
1945
				}
1946
				else {
1947
					# Fenced code block marker: find matching end marker.
1948
					$tag_re = preg_quote(trim($tag));
1949 View Code Duplication
					if (preg_match('{^(?>.*\n)+?'.$tag_re.' *\n}', $text, 
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across 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...
1950
						$matches)) 
1951
					{
1952
						# End marker found: pass text unchanged until marker.
1953
						$parsed .= $tag . $matches[0];
1954
						$text = substr($text, strlen($matches[0]));
1955
					}
1956
					else {
1957
						# No end marker: just skip it.
1958
						$parsed .= $tag;
1959
					}
1960
				}
1961
			}
1962
			#
1963
			# Check for: Opening Block level tag or
1964
			#            Opening Context Block tag (like ins and del) 
1965
			#               used as a block tag (tag is alone on it's line).
1966
			#
1967
			else if (preg_match('{^<(?:'.$this->block_tags_re.')\b}', $tag) ||
1968
				(	preg_match('{^<(?:'.$this->context_block_tags_re.')\b}', $tag) &&
1969
					preg_match($newline_before_re, $parsed) &&
1970
					preg_match($newline_after_re, $text)	)
1971
				)
1972
			{
1973
				# Need to parse tag and following text using the HTML parser.
1974
				list($block_text, $text) = 
1975
					$this->_hashHTMLBlocks_inHTML($tag . $text, "hashBlock", true);
1976
				
1977
				# Make sure it stays outside of any paragraph by adding newlines.
1978
				$parsed .= "\n\n$block_text\n\n";
1979
			}
1980
			#
1981
			# Check for: Clean tag (like script, math)
1982
			#            HTML Comments, processing instructions.
1983
			#
1984
			else if (preg_match('{^<(?:'.$this->clean_tags_re.')\b}', $tag) ||
1985
				$tag{1} == '!' || $tag{1} == '?')
1986
			{
1987
				# Need to parse tag and following text using the HTML parser.
1988
				# (don't check for markdown attribute)
1989
				list($block_text, $text) = 
1990
					$this->_hashHTMLBlocks_inHTML($tag . $text, "hashClean", false);
1991
				
1992
				$parsed .= $block_text;
1993
			}
1994
			#
1995
			# Check for: Tag with same name as enclosing tag.
1996
			#
1997
			else if ($enclosing_tag_re !== '' &&
1998
				# Same name as enclosing tag.
1999
				preg_match('{^</?(?:'.$enclosing_tag_re.')\b}', $tag))
2000
			{
2001
				#
2002
				# Increase/decrease nested tag count.
2003
				#
2004 View Code Duplication
				if ($tag{1} == '/')						$depth--;
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across 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...
2005
				else if ($tag{strlen($tag)-2} != '/')	$depth++;
2006
2007
				if ($depth < 0) {
2008
					#
2009
					# Going out of parent element. Clean up and break so we
2010
					# return to the calling function.
2011
					#
2012
					$text = $tag . $text;
2013
					break;
2014
				}
2015
				
2016
				$parsed .= $tag;
2017
			}
2018
			else {
2019
				$parsed .= $tag;
2020
			}
2021
		} while ($depth >= 0);
2022
		
2023
		return array($parsed, $text);
2024
	}
2025
2026
	/**
2027
	 * @param string $text
2028
	 * @param string $hash_method
2029
	 * @param boolean $md_attr
2030
	 */
2031
	function _hashHTMLBlocks_inHTML($text, $hash_method, $md_attr) {
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
2032
	#
2033
	# Parse HTML, calling _HashHTMLBlocks_InMarkdown for block tags.
2034
	#
2035
	# *   Calls $hash_method to convert any blocks.
2036
	# *   Stops when the first opening tag closes.
2037
	# *   $md_attr indicate if the use of the `markdown="1"` attribute is allowed.
2038
	#     (it is not inside clean tags)
2039
	#
2040
	# Returns an array of that form: ( processed text , remaining text )
2041
	#
2042
		if ($text === '') return array('', '');
2043
		
2044
		# Regex to match `markdown` attribute inside of a tag.
2045
		$markdown_attr_re = '
2046
			{
2047
				\s*			# Eat whitespace before the `markdown` attribute
2048
				markdown
2049
				\s*=\s*
2050
				(?>
2051
					(["\'])		# $1: quote delimiter		
2052
					(.*?)		# $2: attribute value
2053
					\1			# matching delimiter	
2054
				|
2055
					([^\s>]*)	# $3: unquoted attribute value
2056
				)
2057
				()				# $4: make $3 always defined (avoid warnings)
2058
			}xs';
2059
		
2060
		# Regex to match any tag.
2061
		$tag_re = '{
2062
				(					# $2: Capture hole tag.
2063
					</?					# Any opening or closing tag.
2064
						[\w:$]+			# Tag name.
2065
						(?:
2066
							(?=[\s"\'/a-zA-Z0-9])	# Allowed characters after tag name.
2067
							(?>
2068
								".*?"		|	# Double quotes (can contain `>`)
2069
								\'.*?\'   	|	# Single quotes (can contain `>`)
2070
								.+?				# Anything but quotes and `>`.
2071
							)*?
2072
						)?
2073
					>					# End of tag.
2074
				|
2075
					<!--    .*?     -->	# HTML Comment
2076
				|
2077
					<\?.*?\?> | <%.*?%>	# Processing instruction
2078
				|
2079
					<!\[CDATA\[.*?\]\]>	# CData Block
2080
				)
2081
			}xs';
2082
		
2083
		$original_text = $text;		# Save original text in case of faliure.
2084
		
2085
		$depth		= 0;	# Current depth inside the tag tree.
2086
		$block_text	= "";	# Temporary text holder for current text.
2087
		$parsed		= "";	# Parsed text that will be returned.
2088
2089
		#
2090
		# Get the name of the starting tag.
2091
		# (This pattern makes $base_tag_name_re safe without quoting.)
2092
		#
2093
		if (preg_match('/^<([\w:$]*)\b/', $text, $matches))
2094
			$base_tag_name_re = $matches[1];
2095
2096
		#
2097
		# Loop through every tag until we find the corresponding closing tag.
2098
		#
2099
		do {
2100
			#
2101
			# Split the text using the first $tag_match pattern found.
2102
			# Text before  pattern will be first in the array, text after
2103
			# pattern will be at the end, and between will be any catches made 
2104
			# by the pattern.
2105
			#
2106
			$parts = preg_split($tag_re, $text, 2, PREG_SPLIT_DELIM_CAPTURE);
2107
			
2108
			if (count($parts) < 3) {
2109
				#
2110
				# End of $text reached with unbalenced tag(s).
2111
				# In that case, we return original text unchanged and pass the
2112
				# first character as filtered to prevent an infinite loop in the 
2113
				# parent function.
2114
				#
2115
				return array($original_text{0}, substr($original_text, 1));
2116
			}
2117
			
2118
			$block_text .= $parts[0]; # Text before current tag.
2119
			$tag         = $parts[1]; # Tag to handle.
2120
			$text        = $parts[2]; # Remaining text after current tag.
2121
			
2122
			#
2123
			# Check for: Auto-close tag (like <hr/>)
2124
			#			 Comments and Processing Instructions.
2125
			#
2126
			if (preg_match('{^</?(?:'.$this->auto_close_tags_re.')\b}', $tag) ||
2127
				$tag{1} == '!' || $tag{1} == '?')
2128
			{
2129
				# Just add the tag to the block as if it was text.
2130
				$block_text .= $tag;
2131
			}
2132
			else {
2133
				#
2134
				# Increase/decrease nested tag count. Only do so if
2135
				# the tag's name match base tag's.
2136
				#
2137
				if (preg_match('{^</?'.$base_tag_name_re.'\b}', $tag)) {
0 ignored issues
show
Bug introduced by
The variable $base_tag_name_re does not seem to be defined for all execution paths leading up to this point.

If you define a variable conditionally, it can happen that it is not defined for all execution paths.

Let’s take a look at an example:

function myFunction($a) {
    switch ($a) {
        case 'foo':
            $x = 1;
            break;

        case 'bar':
            $x = 2;
            break;
    }

    // $x is potentially undefined here.
    echo $x;
}

In the above example, the variable $x is defined if you pass “foo” or “bar” as argument for $a. However, since the switch statement has no default case statement, if you pass any other value, the variable $x would be undefined.

Available Fixes

  1. Check for existence of the variable explicitly:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        if (isset($x)) { // Make sure it's always set.
            echo $x;
        }
    }
    
  2. Define a default value for the variable:

    function myFunction($a) {
        $x = ''; // Set a default which gets overridden for certain paths.
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        echo $x;
    }
    
  3. Add a value for the missing path:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
    
            // We add support for the missing case.
            default:
                $x = '';
                break;
        }
    
        echo $x;
    }
    
Loading history...
2138 View Code Duplication
					if ($tag{1} == '/')						$depth--;
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across 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...
2139
					else if ($tag{strlen($tag)-2} != '/')	$depth++;
2140
				}
2141
				
2142
				#
2143
				# Check for `markdown="1"` attribute and handle it.
2144
				#
2145
				if ($md_attr && 
2146
					preg_match($markdown_attr_re, $tag, $attr_m) &&
2147
					preg_match('/^1|block|span$/', $attr_m[2] . $attr_m[3]))
2148
				{
2149
					# Remove `markdown` attribute from opening tag.
2150
					$tag = preg_replace($markdown_attr_re, '', $tag);
2151
					
2152
					# Check if text inside this tag must be parsed in span mode.
2153
					$this->mode = $attr_m[2] . $attr_m[3];
0 ignored issues
show
Bug introduced by
The property mode does not exist. Did you maybe forget to declare it?

In PHP it is possible to write to properties without declaring them. For example, the following is perfectly valid PHP code:

class MyClass { }

$x = new MyClass();
$x->foo = true;

Generally, it is a good practice to explictly declare properties to avoid accidental typos and provide IDE auto-completion:

class MyClass {
    public $foo;
}

$x = new MyClass();
$x->foo = true;
Loading history...
2154
					$span_mode = $this->mode == 'span' || $this->mode != 'block' &&
2155
						preg_match('{^<(?:'.$this->contain_span_tags_re.')\b}', $tag);
2156
					
2157
					# Calculate indent before tag.
2158
					if (preg_match('/(?:^|\n)( *?)(?! ).*?$/', $block_text, $matches)) {
2159
						$strlen = $this->utf8_strlen;
2160
						$indent = $strlen($matches[1], 'UTF-8');
2161
					} else {
2162
						$indent = 0;
2163
					}
2164
					
2165
					# End preceding block with this tag.
2166
					$block_text .= $tag;
2167
					$parsed .= $this->$hash_method($block_text);
2168
					
2169
					# Get enclosing tag name for the ParseMarkdown function.
2170
					# (This pattern makes $tag_name_re safe without quoting.)
2171
					preg_match('/^<([\w:$]*)\b/', $tag, $matches);
2172
					$tag_name_re = $matches[1];
2173
					
2174
					# Parse the content using the HTML-in-Markdown parser.
2175
					list ($block_text, $text)
2176
						= $this->_hashHTMLBlocks_inMarkdown($text, $indent, 
2177
							$tag_name_re, $span_mode);
2178
					
2179
					# Outdent markdown text.
2180
					if ($indent > 0) {
2181
						$block_text = preg_replace("/^[ ]{1,$indent}/m", "", 
2182
													$block_text);
2183
					}
2184
					
2185
					# Append tag content to parsed text.
2186
					if (!$span_mode)	$parsed .= "\n\n$block_text\n\n";
2187
					else				$parsed .= "$block_text";
2188
					
2189
					# Start over a new block.
2190
					$block_text = "";
2191
				}
2192
				else $block_text .= $tag;
2193
			}
2194
			
2195
		} while ($depth > 0);
2196
		
2197
		#
2198
		# Hash last block text that wasn't processed inside the loop.
2199
		#
2200
		$parsed .= $this->$hash_method($block_text);
2201
		
2202
		return array($parsed, $text);
2203
	}
2204
2205
2206
	function hashClean($text) {
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
2207
	#
2208
	# Called whenever a tag must be hashed when a function insert a "clean" tag
2209
	# in $text, it pass through this function and is automaticaly escaped, 
2210
	# blocking invalid nested overlap.
2211
	#
2212
		return $this->hashPart($text, 'C');
2213
	}
2214
2215
2216 View Code Duplication
	function doHeaders($text) {
0 ignored issues
show
Documentation introduced by
The return type could not be reliably inferred; please add a @return annotation.

Our type inference engine in quite powerful, but sometimes the code does not provide enough clues to go by. In these cases we request you to add a @return annotation as described here.

Loading history...
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
Duplication introduced by
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...
2217
	#
2218
	# Redefined to add id attribute support.
2219
	#
2220
		# Setext-style headers:
2221
		#	  Header 1  {#header1}
2222
		#	  ========
2223
		#  
2224
		#	  Header 2  {#header2}
2225
		#	  --------
2226
		#
2227
		$text = preg_replace_callback(
2228
			'{
2229
				(^.+?)								# $1: Header text
2230
				(?:[ ]+\{\#([-_:a-zA-Z0-9]+)\})?	# $2: Id attribute
2231
				[ ]*\n(=+|-+)[ ]*\n+				# $3: Header footer
2232
			}mx',
2233
			array(&$this, '_doHeaders_callback_setext'), $text);
2234
2235
		# atx-style headers:
2236
		#	# Header 1        {#header1}
2237
		#	## Header 2       {#header2}
2238
		#	## Header 2 with closing hashes ##  {#header3}
2239
		#	...
2240
		#	###### Header 6   {#header2}
2241
		#
2242
		$text = preg_replace_callback('{
2243
				^(\#{1,6})	# $1 = string of #\'s
2244
				[ ]*
2245
				(.+?)		# $2 = Header text
2246
				[ ]*
2247
				\#*			# optional closing #\'s (not counted)
2248
				(?:[ ]+\{\#([-_:a-zA-Z0-9]+)\})? # id attribute
2249
				[ ]*
2250
				\n+
2251
			}xm',
2252
			array(&$this, '_doHeaders_callback_atx'), $text);
2253
2254
		return $text;
2255
	}
2256
	function _doHeaders_attr($attr) {
0 ignored issues
show
Documentation introduced by
The return type could not be reliably inferred; please add a @return annotation.

Our type inference engine in quite powerful, but sometimes the code does not provide enough clues to go by. In these cases we request you to add a @return annotation as described here.

Loading history...
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
2257
		if (empty($attr))  return "";
2258
		return " id=\"$attr\"";
2259
	}
2260
	function _doHeaders_callback_setext($matches) {
0 ignored issues
show
Documentation introduced by
The return type could not be reliably inferred; please add a @return annotation.

Our type inference engine in quite powerful, but sometimes the code does not provide enough clues to go by. In these cases we request you to add a @return annotation as described here.

Loading history...
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
2261 View Code Duplication
		if ($matches[3] == '-' && preg_match('{^- }', $matches[1]))
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across 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...
2262
			return $matches[0];
2263
		$level = $matches[3]{0} == '=' ? 1 : 2;
2264
		$attr  = $this->_doHeaders_attr($id =& $matches[2]);
2265
		$block = "<h$level$attr>".$this->runSpanGamut($matches[1])."</h$level>";
2266
		return "\n" . $this->hashBlock($block) . "\n\n";
2267
	}
2268
	function _doHeaders_callback_atx($matches) {
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
2269
		$level = strlen($matches[1]);
2270
		$attr  = $this->_doHeaders_attr($id =& $matches[3]);
2271
		$block = "<h$level$attr>".$this->runSpanGamut($matches[2])."</h$level>";
2272
		return "\n" . $this->hashBlock($block) . "\n\n";
2273
	}
2274
2275
2276
	function doTables($text) {
0 ignored issues
show
Documentation introduced by
The return type could not be reliably inferred; please add a @return annotation.

Our type inference engine in quite powerful, but sometimes the code does not provide enough clues to go by. In these cases we request you to add a @return annotation as described here.

Loading history...
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
2277
	#
2278
	# Form HTML tables.
2279
	#
2280
		$less_than_tab = $this->tab_width - 1;
2281
		#
2282
		# Find tables with leading pipe.
2283
		#
2284
		#	| Header 1 | Header 2
2285
		#	| -------- | --------
2286
		#	| Cell 1   | Cell 2
2287
		#	| Cell 3   | Cell 4
2288
		#
2289
		$text = preg_replace_callback('
2290
			{
2291
				^							# Start of a line
2292
				[ ]{0,'.$less_than_tab.'}	# Allowed whitespace.
2293
				[|]							# Optional leading pipe (present)
2294
				(.+) \n						# $1: Header row (at least one pipe)
2295
				
2296
				[ ]{0,'.$less_than_tab.'}	# Allowed whitespace.
2297
				[|] ([ ]*[-:]+[-| :]*) \n	# $2: Header underline
2298
				
2299
				(							# $3: Cells
2300
					(?>
2301
						[ ]*				# Allowed whitespace.
2302
						[|] .* \n			# Row content.
2303
					)*
2304
				)
2305
				(?=\n|\Z)					# Stop at final double newline.
2306
			}xm',
2307
			array(&$this, '_doTable_leadingPipe_callback'), $text);
2308
		
2309
		#
2310
		# Find tables without leading pipe.
2311
		#
2312
		#	Header 1 | Header 2
2313
		#	-------- | --------
2314
		#	Cell 1   | Cell 2
2315
		#	Cell 3   | Cell 4
2316
		#
2317
		$text = preg_replace_callback('
2318
			{
2319
				^							# Start of a line
2320
				[ ]{0,'.$less_than_tab.'}	# Allowed whitespace.
2321
				(\S.*[|].*) \n				# $1: Header row (at least one pipe)
2322
				
2323
				[ ]{0,'.$less_than_tab.'}	# Allowed whitespace.
2324
				([-:]+[ ]*[|][-| :]*) \n	# $2: Header underline
2325
				
2326
				(							# $3: Cells
2327
					(?>
2328
						.* [|] .* \n		# Row content
2329
					)*
2330
				)
2331
				(?=\n|\Z)					# Stop at final double newline.
2332
			}xm',
2333
			array(&$this, '_DoTable_callback'), $text);
2334
2335
		return $text;
2336
	}
2337
	function _doTable_leadingPipe_callback($matches) {
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
2338
		$head		= $matches[1];
2339
		$underline	= $matches[2];
2340
		$content	= $matches[3];
2341
		
2342
		# Remove leading pipe for each row.
2343
		$content	= preg_replace('/^ *[|]/m', '', $content);
2344
		
2345
		return $this->_doTable_callback(array($matches[0], $head, $underline, $content));
2346
	}
2347
	function _doTable_callback($matches) {
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
2348
		$head		= $matches[1];
2349
		$underline	= $matches[2];
2350
		$content	= $matches[3];
2351
2352
		# Remove any tailing pipes for each line.
2353
		$head		= preg_replace('/[|] *$/m', '', $head);
2354
		$underline	= preg_replace('/[|] *$/m', '', $underline);
2355
		$content	= preg_replace('/[|] *$/m', '', $content);
2356
		
2357
		# Reading alignement from header underline.
2358
		$separators	= preg_split('/ *[|] */', $underline);
2359
		foreach ($separators as $n => $s) {
2360
			if (preg_match('/^ *-+: *$/', $s))		$attr[$n] = ' align="right"';
0 ignored issues
show
Coding Style Comprehensibility introduced by
$attr was never initialized. Although not strictly required by PHP, it is generally a good practice to add $attr = array(); before regardless.

Adding an explicit array definition is generally preferable to implicit array definition as it guarantees a stable state of the code.

Let’s take a look at an example:

foreach ($collection as $item) {
    $myArray['foo'] = $item->getFoo();

    if ($item->hasBar()) {
        $myArray['bar'] = $item->getBar();
    }

    // do something with $myArray
}

As you can see in this example, the array $myArray is initialized the first time when the foreach loop is entered. You can also see that the value of the bar key is only written conditionally; thus, its value might result from a previous iteration.

This might or might not be intended. To make your intention clear, your code more readible and to avoid accidental bugs, we recommend to add an explicit initialization $myArray = array() either outside or inside the foreach loop.

Loading history...
2361
			else if (preg_match('/^ *:-+: *$/', $s))$attr[$n] = ' align="center"';
0 ignored issues
show
Bug introduced by
The variable $attr does not seem to be defined for all execution paths leading up to this point.

If you define a variable conditionally, it can happen that it is not defined for all execution paths.

Let’s take a look at an example:

function myFunction($a) {
    switch ($a) {
        case 'foo':
            $x = 1;
            break;

        case 'bar':
            $x = 2;
            break;
    }

    // $x is potentially undefined here.
    echo $x;
}

In the above example, the variable $x is defined if you pass “foo” or “bar” as argument for $a. However, since the switch statement has no default case statement, if you pass any other value, the variable $x would be undefined.

Available Fixes

  1. Check for existence of the variable explicitly:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        if (isset($x)) { // Make sure it's always set.
            echo $x;
        }
    }
    
  2. Define a default value for the variable:

    function myFunction($a) {
        $x = ''; // Set a default which gets overridden for certain paths.
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        echo $x;
    }
    
  3. Add a value for the missing path:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
    
            // We add support for the missing case.
            default:
                $x = '';
                break;
        }
    
        echo $x;
    }
    
Loading history...
2362
			else if (preg_match('/^ *:-+ *$/', $s))	$attr[$n] = ' align="left"';
2363
			else									$attr[$n] = '';
2364
		}
2365
		
2366
		# Parsing span elements, including code spans, character escapes, 
2367
		# and inline HTML tags, so that pipes inside those gets ignored.
2368
		$head		= $this->parseSpan($head);
2369
		$headers	= preg_split('/ *[|] */', $head);
2370
		$col_count	= count($headers);
2371
		
2372
		# Write column headers.
2373
		$text = "<table>\n";
2374
		$text .= "<thead>\n";
2375
		$text .= "<tr>\n";
2376
		foreach ($headers as $n => $header)
2377
			$text .= "  <th$attr[$n]>".$this->runSpanGamut(trim($header))."</th>\n";
2378
		$text .= "</tr>\n";
2379
		$text .= "</thead>\n";
2380
		
2381
		# Split content by row.
2382
		$rows = explode("\n", trim($content, "\n"));
2383
		
2384
		$text .= "<tbody>\n";
2385
		foreach ($rows as $row) {
2386
			# Parsing span elements, including code spans, character escapes, 
2387
			# and inline HTML tags, so that pipes inside those gets ignored.
2388
			$row = $this->parseSpan($row);
2389
			
2390
			# Split row by cell.
2391
			$row_cells = preg_split('/ *[|] */', $row, $col_count);
2392
			$row_cells = array_pad($row_cells, $col_count, '');
2393
			
2394
			$text .= "<tr>\n";
2395
			foreach ($row_cells as $n => $cell)
2396
				$text .= "  <td$attr[$n]>".$this->runSpanGamut(trim($cell))."</td>\n";
2397
			$text .= "</tr>\n";
2398
		}
2399
		$text .= "</tbody>\n";
2400
		$text .= "</table>";
2401
		
2402
		return $this->hashBlock($text) . "\n";
2403
	}
2404
2405
	
2406
	function doDefLists($text) {
0 ignored issues
show
Documentation introduced by
The return type could not be reliably inferred; please add a @return annotation.

Our type inference engine in quite powerful, but sometimes the code does not provide enough clues to go by. In these cases we request you to add a @return annotation as described here.

Loading history...
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
2407
	#
2408
	# Form HTML definition lists.
2409
	#
2410
		$less_than_tab = $this->tab_width - 1;
2411
2412
		# Re-usable pattern to match any entire dl list:
2413
		$whole_list_re = '(?>
2414
			(								# $1 = whole list
2415
			  (								# $2
2416
				[ ]{0,'.$less_than_tab.'}
2417
				((?>.*\S.*\n)+)				# $3 = defined term
2418
				\n?
2419
				[ ]{0,'.$less_than_tab.'}:[ ]+ # colon starting definition
2420
			  )
2421
			  (?s:.+?)
2422
			  (								# $4
2423
				  \z
2424
				|
2425
				  \n{2,}
2426
				  (?=\S)
2427
				  (?!						# Negative lookahead for another term
2428
					[ ]{0,'.$less_than_tab.'}
2429
					(?: \S.*\n )+?			# defined term
2430
					\n?
2431
					[ ]{0,'.$less_than_tab.'}:[ ]+ # colon starting definition
2432
				  )
2433
				  (?!						# Negative lookahead for another definition
2434
					[ ]{0,'.$less_than_tab.'}:[ ]+ # colon starting definition
2435
				  )
2436
			  )
2437
			)
2438
		)'; // mx
2439
2440
		$text = preg_replace_callback('{
2441
				(?>\A\n?|(?<=\n\n))
2442
				'.$whole_list_re.'
2443
			}mx',
2444
			array(&$this, '_doDefLists_callback'), $text);
2445
2446
		return $text;
2447
	}
2448
	function _doDefLists_callback($matches) {
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
2449
		# Re-usable patterns to match list item bullets and number markers:
2450
		$list = $matches[1];
2451
		
2452
		# Turn double returns into triple returns, so that we can make a
2453
		# paragraph for the last item in a list, if necessary:
2454
		$result = trim($this->processDefListItems($list));
2455
		$result = "<dl>\n" . $result . "\n</dl>";
2456
		return $this->hashBlock($result) . "\n\n";
2457
	}
2458
2459
2460
	/**
2461
	 * @return string
2462
	 */
2463
	function processDefListItems($list_str) {
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
2464
	#
2465
	#	Process the contents of a single definition list, splitting it
2466
	#	into individual term and definition list items.
2467
	#
2468
		$less_than_tab = $this->tab_width - 1;
2469
		
2470
		# trim trailing blank lines:
2471
		$list_str = preg_replace("/\n{2,}\\z/", "\n", $list_str);
2472
2473
		# Process definition terms.
2474
		$list_str = preg_replace_callback('{
2475
			(?>\A\n?|\n\n+)					# leading line
2476
			(								# definition terms = $1
2477
				[ ]{0,'.$less_than_tab.'}	# leading whitespace
2478
				(?![:][ ]|[ ])				# negative lookahead for a definition 
2479
											#   mark (colon) or more whitespace.
2480
				(?> \S.* \n)+?				# actual term (not whitespace).	
2481
			)			
2482
			(?=\n?[ ]{0,3}:[ ])				# lookahead for following line feed 
2483
											#   with a definition mark.
2484
			}xm',
2485
			array(&$this, '_processDefListItems_callback_dt'), $list_str);
2486
2487
		# Process actual definitions.
2488
		$list_str = preg_replace_callback('{
2489
			\n(\n+)?						# leading line = $1
2490
			(								# marker space = $2
2491
				[ ]{0,'.$less_than_tab.'}	# whitespace before colon
2492
				[:][ ]+						# definition mark (colon)
2493
			)
2494
			((?s:.+?))						# definition text = $3
2495
			(?= \n+ 						# stop at next definition mark,
2496
				(?:							# next term or end of text
2497
					[ ]{0,'.$less_than_tab.'} [:][ ]	|
2498
					<dt> | \z
2499
				)						
2500
			)					
2501
			}xm',
2502
			array(&$this, '_processDefListItems_callback_dd'), $list_str);
2503
2504
		return $list_str;
2505
	}
2506
	function _processDefListItems_callback_dt($matches) {
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
2507
		$terms = explode("\n", trim($matches[1]));
2508
		$text = '';
2509
		foreach ($terms as $term) {
2510
			$term = $this->runSpanGamut(trim($term));
2511
			$text .= "\n<dt>" . $term . "</dt>";
2512
		}
2513
		return $text . "\n";
2514
	}
2515
	function _processDefListItems_callback_dd($matches) {
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
2516
		$leading_line	= $matches[1];
2517
		$marker_space	= $matches[2];
2518
		$def			= $matches[3];
2519
2520 View Code Duplication
		if ($leading_line || preg_match('/\n{2,}/', $def)) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across 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...
2521
			# Replace marker with the appropriate whitespace indentation
2522
			$def = str_repeat(' ', strlen($marker_space)) . $def;
2523
			$def = $this->runBlockGamut($this->outdent($def . "\n\n"));
2524
			$def = "\n". $def ."\n";
2525
		}
2526
		else {
2527
			$def = rtrim($def);
2528
			$def = $this->runSpanGamut($this->outdent($def));
2529
		}
2530
2531
		return "\n<dd>" . $def . "</dd>\n";
2532
	}
2533
2534
2535
	function doFencedCodeBlocks($text) {
0 ignored issues
show
Documentation introduced by
The return type could not be reliably inferred; please add a @return annotation.

Our type inference engine in quite powerful, but sometimes the code does not provide enough clues to go by. In these cases we request you to add a @return annotation as described here.

Loading history...
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
2536
	#
2537
	# Adding the fenced code block syntax to regular Markdown:
2538
	#
2539
	# ~~~
2540
	# Code block
2541
	# ~~~
2542
	#
2543
		$less_than_tab = $this->tab_width;
0 ignored issues
show
Unused Code introduced by
$less_than_tab is not used, you could remove the assignment.

This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.

$myVar = 'Value';
$higher = false;

if (rand(1, 6) > 3) {
    $higher = true;
} else {
    $higher = false;
}

Both the $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

Loading history...
2544
		
2545
		$text = preg_replace_callback('{
2546
				(?:\n|\A)
2547
				# 1: Opening marker
2548
				(
2549
					~{3,} # Marker: three tilde or more.
2550
				)
2551
				[ ]* \n # Whitespace and newline following marker.
2552
				
2553
				# 2: Content
2554
				(
2555
					(?>
2556
						(?!\1 [ ]* \n)	# Not a closing marker.
2557
						.*\n+
2558
					)+
2559
				)
2560
				
2561
				# Closing marker.
2562
				\1 [ ]* \n
2563
			}xm',
2564
			array(&$this, '_doFencedCodeBlocks_callback'), $text);
2565
2566
		return $text;
2567
	}
2568
	function _doFencedCodeBlocks_callback($matches) {
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
2569
		$codeblock = $matches[2];
2570
		$codeblock = htmlspecialchars($codeblock, ENT_NOQUOTES);
2571
		$codeblock = preg_replace_callback('/^\n+/',
2572
			array(&$this, '_doFencedCodeBlocks_newlines'), $codeblock);
2573
		$codeblock = "<pre><code>$codeblock</code></pre>";
2574
		return "\n\n".$this->hashBlock($codeblock)."\n\n";
2575
	}
2576
	function _doFencedCodeBlocks_newlines($matches) {
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
2577
		return str_repeat("<br$this->empty_element_suffix", 
2578
			strlen($matches[0]));
2579
	}
2580
2581
2582
	#
2583
	# Redefining emphasis markers so that emphasis by underscore does not
2584
	# work in the middle of a word.
2585
	#
2586
	var $em_relist = array(
2587
		''  => '(?:(?<!\*)\*(?!\*)|(?<![a-zA-Z0-9_])_(?!_))(?=\S)(?![.,:;]\s)',
2588
		'*' => '(?<=\S)(?<!\*)\*(?!\*)',
2589
		'_' => '(?<=\S)(?<!_)_(?![a-zA-Z0-9_])',
2590
		);
2591
	var $strong_relist = array(
2592
		''   => '(?:(?<!\*)\*\*(?!\*)|(?<![a-zA-Z0-9_])__(?!_))(?=\S)(?![.,:;]\s)',
2593
		'**' => '(?<=\S)(?<!\*)\*\*(?!\*)',
2594
		'__' => '(?<=\S)(?<!_)__(?![a-zA-Z0-9_])',
2595
		);
2596
	var $em_strong_relist = array(
2597
		''    => '(?:(?<!\*)\*\*\*(?!\*)|(?<![a-zA-Z0-9_])___(?!_))(?=\S)(?![.,:;]\s)',
2598
		'***' => '(?<=\S)(?<!\*)\*\*\*(?!\*)',
2599
		'___' => '(?<=\S)(?<!_)___(?![a-zA-Z0-9_])',
2600
		);
2601
2602
2603
	function formParagraphs($text) {
0 ignored issues
show
Documentation introduced by
The return type could not be reliably inferred; please add a @return annotation.

Our type inference engine in quite powerful, but sometimes the code does not provide enough clues to go by. In these cases we request you to add a @return annotation as described here.

Loading history...
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
2604
	#
2605
	#	Params:
2606
	#		$text - string to process with html <p> tags
2607
	#
2608
		# Strip leading and trailing lines:
2609
		$text = preg_replace('/\A\n+|\n+\z/', '', $text);
2610
		
2611
		$grafs = preg_split('/\n{2,}/', $text, -1, PREG_SPLIT_NO_EMPTY);
2612
2613
		#
2614
		# Wrap <p> tags and unhashify HTML blocks
2615
		#
2616
		foreach ($grafs as $key => $value) {
2617
			$value = trim($this->runSpanGamut($value));
2618
			
2619
			# Check if this should be enclosed in a paragraph.
2620
			# Clean tag hashes & block tag hashes are left alone.
2621
			$is_p = !preg_match('/^B\x1A[0-9]+B|^C\x1A[0-9]+C$/', $value);
2622
			
2623
			if ($is_p) {
2624
				$value = "<p>$value</p>";
2625
			}
2626
			$grafs[$key] = $value;
2627
		}
2628
		
2629
		# Join grafs in one text, then unhash HTML tags. 
2630
		$text = implode("\n\n", $grafs);
2631
		
2632
		# Finish by removing any tag hashes still present in $text.
2633
		$text = $this->unhash($text);
2634
		
2635
		return $text;
2636
	}
2637
	
2638
	
2639
	### Footnotes
2640
	
2641 View Code Duplication
	function stripFootnotes($text) {
0 ignored issues
show
Documentation introduced by
The return type could not be reliably inferred; please add a @return annotation.

Our type inference engine in quite powerful, but sometimes the code does not provide enough clues to go by. In these cases we request you to add a @return annotation as described here.

Loading history...
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
Duplication introduced by
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...
2642
	#
2643
	# Strips link definitions from text, stores the URLs and titles in
2644
	# hash references.
2645
	#
2646
		$less_than_tab = $this->tab_width - 1;
2647
2648
		# Link defs are in the form: [^id]: url "optional title"
2649
		$text = preg_replace_callback('{
2650
			^[ ]{0,'.$less_than_tab.'}\[\^(.+?)\][ ]?:	# note_id = $1
2651
			  [ ]*
2652
			  \n?					# maybe *one* newline
2653
			(						# text = $2 (no blank lines allowed)
2654
				(?:					
2655
					.+				# actual text
2656
				|
2657
					\n				# newlines but 
2658
					(?!\[\^.+?\]:\s)# negative lookahead for footnote marker.
2659
					(?!\n+[ ]{0,3}\S)# ensure line is not blank and followed 
2660
									# by non-indented content
2661
				)*
2662
			)		
2663
			}xm',
2664
			array(&$this, '_stripFootnotes_callback'),
2665
			$text);
2666
		return $text;
2667
	}
2668
	function _stripFootnotes_callback($matches) {
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
2669
		$note_id = $this->fn_id_prefix . $matches[1];
2670
		$this->footnotes[$note_id] = $this->outdent($matches[2]);
2671
		return ''; # String that will replace the block
2672
	}
2673
2674
2675
	function doFootnotes($text) {
0 ignored issues
show
Documentation introduced by
The return type could not be reliably inferred; please add a @return annotation.

Our type inference engine in quite powerful, but sometimes the code does not provide enough clues to go by. In these cases we request you to add a @return annotation as described here.

Loading history...
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
2676
	#
2677
	# Replace footnote references in $text [^id] with a special text-token 
2678
	# which will be replaced by the actual footnote marker in appendFootnotes.
2679
	#
2680
		if (!$this->in_anchor) {
2681
			$text = preg_replace('{\[\^(.+?)\]}', "F\x1Afn:\\1\x1A:", $text);
2682
		}
2683
		return $text;
2684
	}
2685
2686
	
2687
	function appendFootnotes($text) {
0 ignored issues
show
Documentation introduced by
The return type could not be reliably inferred; please add a @return annotation.

Our type inference engine in quite powerful, but sometimes the code does not provide enough clues to go by. In these cases we request you to add a @return annotation as described here.

Loading history...
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
2688
	#
2689
	# Append footnote list to text.
2690
	#
2691
		$text = preg_replace_callback('{F\x1Afn:(.*?)\x1A:}', 
2692
			array(&$this, '_appendFootnotes_callback'), $text);
2693
	
2694
		if (!empty($this->footnotes_ordered)) {
2695
			$text .= "\n\n";
2696
			$text .= "<div class=\"footnotes\">\n";
2697
			$text .= "<hr". MARKDOWN_EMPTY_ELEMENT_SUFFIX ."\n";
2698
			$text .= "<ol>\n\n";
2699
			
2700
			$attr = " rev=\"footnote\"";
2701
			if ($this->fn_backlink_class != "") {
2702
				$class = $this->fn_backlink_class;
2703
				$class = $this->encodeAttribute($class);
2704
				$attr .= " class=\"$class\"";
2705
			}
2706
			if ($this->fn_backlink_title != "") {
2707
				$title = $this->fn_backlink_title;
2708
				$title = $this->encodeAttribute($title);
2709
				$attr .= " title=\"$title\"";
2710
			}
2711
			$num = 0;
2712
			
2713
			while (!empty($this->footnotes_ordered)) {
2714
				$footnote = reset($this->footnotes_ordered);
2715
				$note_id = key($this->footnotes_ordered);
2716
				unset($this->footnotes_ordered[$note_id]);
2717
				
2718
				$footnote .= "\n"; # Need to append newline before parsing.
2719
				$footnote = $this->runBlockGamut("$footnote\n");				
2720
				$footnote = preg_replace_callback('{F\x1Afn:(.*?)\x1A:}', 
2721
					array(&$this, '_appendFootnotes_callback'), $footnote);
2722
				
2723
				$attr = str_replace("%%", ++$num, $attr);
2724
				$note_id = $this->encodeAttribute($note_id);
2725
				
2726
				# Add backlink to last paragraph; create new paragraph if needed.
2727
				$backlink = "<a href=\"#fnref:$note_id\"$attr>&#8617;</a>";
2728
				if (preg_match('{</p>$}', $footnote)) {
2729
					$footnote = substr($footnote, 0, -4) . "&#160;$backlink</p>";
2730
				} else {
2731
					$footnote .= "\n\n<p>$backlink</p>";
2732
				}
2733
				
2734
				$text .= "<li id=\"fn:$note_id\">\n";
2735
				$text .= $footnote . "\n";
2736
				$text .= "</li>\n\n";
2737
			}
2738
			
2739
			$text .= "</ol>\n";
2740
			$text .= "</div>";
2741
		}
2742
		return $text;
2743
	}
2744
	function _appendFootnotes_callback($matches) {
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
2745
		$node_id = $this->fn_id_prefix . $matches[1];
2746
		
2747
		# Create footnote marker only if it has a corresponding footnote *and*
2748
		# the footnote hasn't been used by another marker.
2749
		if (isset($this->footnotes[$node_id])) {
2750
			# Transfert footnote content to the ordered list.
2751
			$this->footnotes_ordered[$node_id] = $this->footnotes[$node_id];
2752
			unset($this->footnotes[$node_id]);
2753
			
2754
			$num = $this->footnote_counter++;
2755
			$attr = " rel=\"footnote\"";
2756
			if ($this->fn_link_class != "") {
2757
				$class = $this->fn_link_class;
2758
				$class = $this->encodeAttribute($class);
2759
				$attr .= " class=\"$class\"";
2760
			}
2761
			if ($this->fn_link_title != "") {
2762
				$title = $this->fn_link_title;
2763
				$title = $this->encodeAttribute($title);
2764
				$attr .= " title=\"$title\"";
2765
			}
2766
			
2767
			$attr = str_replace("%%", $num, $attr);
2768
			$node_id = $this->encodeAttribute($node_id);
2769
			
2770
			return
2771
				"<sup id=\"fnref:$node_id\">".
2772
				"<a href=\"#fn:$node_id\"$attr>$num</a>".
2773
				"</sup>";
2774
		}
2775
		
2776
		return "[^".$matches[1]."]";
2777
	}
2778
		
2779
	
2780
	### Abbreviations ###
2781
	
2782 View Code Duplication
	function stripAbbreviations($text) {
0 ignored issues
show
Documentation introduced by
The return type could not be reliably inferred; please add a @return annotation.

Our type inference engine in quite powerful, but sometimes the code does not provide enough clues to go by. In these cases we request you to add a @return annotation as described here.

Loading history...
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
Duplication introduced by
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...
2783
	#
2784
	# Strips abbreviations from text, stores titles in hash references.
2785
	#
2786
		$less_than_tab = $this->tab_width - 1;
2787
2788
		# Link defs are in the form: [id]*: url "optional title"
2789
		$text = preg_replace_callback('{
2790
			^[ ]{0,'.$less_than_tab.'}\*\[(.+?)\][ ]?:	# abbr_id = $1
2791
			(.*)					# text = $2 (no blank lines allowed)	
2792
			}xm',
2793
			array(&$this, '_stripAbbreviations_callback'),
2794
			$text);
2795
		return $text;
2796
	}
2797
	function _stripAbbreviations_callback($matches) {
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
2798
		$abbr_word = $matches[1];
2799
		$abbr_desc = $matches[2];
2800
		if ($this->abbr_word_re)
2801
			$this->abbr_word_re .= '|';
2802
		$this->abbr_word_re .= preg_quote($abbr_word);
2803
		$this->abbr_desciptions[$abbr_word] = trim($abbr_desc);
2804
		return ''; # String that will replace the block
2805
	}
2806
	
2807
	
2808
	function doAbbreviations($text) {
0 ignored issues
show
Documentation introduced by
The return type could not be reliably inferred; please add a @return annotation.

Our type inference engine in quite powerful, but sometimes the code does not provide enough clues to go by. In these cases we request you to add a @return annotation as described here.

Loading history...
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
2809
	#
2810
	# Find defined abbreviations in text and wrap them in <abbr> elements.
2811
	#
2812
		if ($this->abbr_word_re) {
2813
			// cannot use the /x modifier because abbr_word_re may 
2814
			// contain significant spaces:
2815
			$text = preg_replace_callback('{'.
2816
				'(?<![\w\x1A])'.
2817
				'(?:'.$this->abbr_word_re.')'.
2818
				'(?![\w\x1A])'.
2819
				'}', 
2820
				array(&$this, '_doAbbreviations_callback'), $text);
2821
		}
2822
		return $text;
2823
	}
2824
	function _doAbbreviations_callback($matches) {
0 ignored issues
show
Documentation introduced by
The return type could not be reliably inferred; please add a @return annotation.

Our type inference engine in quite powerful, but sometimes the code does not provide enough clues to go by. In these cases we request you to add a @return annotation as described here.

Loading history...
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
2825
		$abbr = $matches[0];
2826
		if (isset($this->abbr_desciptions[$abbr])) {
2827
			$desc = $this->abbr_desciptions[$abbr];
2828
			if (empty($desc)) {
2829
				return $this->hashPart("<abbr>$abbr</abbr>");
2830
			} else {
2831
				$desc = $this->encodeAttribute($desc);
2832
				return $this->hashPart("<abbr title=\"$desc\">$abbr</abbr>");
2833
			}
2834
		} else {
2835
			return $matches[0];
2836
		}
2837
	}
2838
2839
}
2840
2841
2842
/*
2843
2844
PHP Markdown Extra
2845
==================
2846
2847
Description
2848
-----------
2849
2850
This is a PHP port of the original Markdown formatter written in Perl 
2851
by John Gruber. This special "Extra" version of PHP Markdown features 
2852
further enhancements to the syntax for making additional constructs 
2853
such as tables and definition list.
2854
2855
Markdown is a text-to-HTML filter; it translates an easy-to-read /
2856
easy-to-write structured text format into HTML. Markdown's text format
2857
is most similar to that of plain text email, and supports features such
2858
as headers, *emphasis*, code blocks, blockquotes, and links.
2859
2860
Markdown's syntax is designed not as a generic markup language, but
2861
specifically to serve as a front-end to (X)HTML. You can use span-level
2862
HTML tags anywhere in a Markdown document, and you can use block level
2863
HTML tags (like <div> and <table> as well).
2864
2865
For more information about Markdown's syntax, see:
2866
2867
<http://daringfireball.net/projects/markdown/>
2868
2869
2870
Bugs
2871
----
2872
2873
To file bug reports please send email to:
2874
2875
<[email protected]>
2876
2877
Please include with your report: (1) the example input; (2) the output you
2878
expected; (3) the output Markdown actually produced.
2879
2880
2881
Version History
2882
--------------- 
2883
2884
See the readme file for detailed release notes for this version.
2885
2886
2887
Copyright and License
2888
---------------------
2889
2890
PHP Markdown & Extra
2891
Copyright (c) 2004-2008 Michel Fortin  
2892
<http://www.michelf.com/>  
2893
All rights reserved.
2894
2895
Based on Markdown  
2896
Copyright (c) 2003-2006 John Gruber   
2897
<http://daringfireball.net/>   
2898
All rights reserved.
2899
2900
Redistribution and use in source and binary forms, with or without
2901
modification, are permitted provided that the following conditions are
2902
met:
2903
2904
*	Redistributions of source code must retain the above copyright notice,
2905
	this list of conditions and the following disclaimer.
2906
2907
*	Redistributions in binary form must reproduce the above copyright
2908
	notice, this list of conditions and the following disclaimer in the
2909
	documentation and/or other materials provided with the distribution.
2910
2911
*	Neither the name "Markdown" nor the names of its contributors may
2912
	be used to endorse or promote products derived from this software
2913
	without specific prior written permission.
2914
2915
This software is provided by the copyright holders and contributors "as
2916
is" and any express or implied warranties, including, but not limited
2917
to, the implied warranties of merchantability and fitness for a
2918
particular purpose are disclaimed. In no event shall the copyright owner
2919
or contributors be liable for any direct, indirect, incidental, special,
2920
exemplary, or consequential damages (including, but not limited to,
2921
procurement of substitute goods or services; loss of use, data, or
2922
profits; or business interruption) however caused and on any theory of
2923
liability, whether in contract, strict liability, or tort (including
2924
negligence or otherwise) arising in any way out of the use of this
2925
software, even if advised of the possibility of such damage.
2926
2927
*/
2928
?>
0 ignored issues
show
Best Practice introduced by
It is not recommended to use PHP's closing tag ?> in files other than templates.

Using a closing tag in PHP files that only contain PHP code is not recommended as you might accidentally add whitespace after the closing tag which would then be output by PHP. This can cause severe problems, for example headers cannot be sent anymore.

A simple precaution is to leave off the closing tag as it is not required, and it also has no negative effects whatsoever.

Loading history...