Issues (2873)

Security Analysis    not enabled

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

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

components/Markdown.php (86 issues)

Upgrade to new PHP Analysis Engine

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

1
<?php
0 ignored issues
show
Coding Style Compatibility introduced by
For compatibility and reusability of your code, PSR1 recommends that a file should introduce either new symbols (like classes, functions, etc.) or have side-effects (like outputting something, or including other files), but not both at the same time. The first symbol is defined on line 30 and the first side effect is on line 36.

The PSR-1: Basic Coding Standard recommends that a file should either introduce new symbols, that is classes, functions, constants or similar, or have side effects. Side effects are anything that executes logic, like for example printing output, changing ini settings or writing to a file.

The idea behind this recommendation is that merely auto-loading a class should not change the state of an application. It also promotes a cleaner style of programming and makes your code less prone to errors, because the logic is not spread out all over the place.

To learn more about the PSR-1, please see the PHP-FIG site on the PSR-1.

Loading history...
2
/**
3
 * ID: markdown-syntax
4
 *
5
 * Name: Markdown Syntax
6
 *
7
 * Description: Integration with Markdown (http://michelf.com/projects/php-markdown/); Adds an option to enable
8
 * Markdown syntax for Paragraph text fields.
9
 *
10
 * Version: 1.0
11
 *
12
 * Category: Field Types
13
 *
14
 * @package    Pods\Components
15
 * @subpackage Markdown
16
 */
17
18
if ( ! function_exists( 'Markdown' ) ) :
19
	//
20
	// Markdown  -  A text-to-HTML conversion tool for web writers
21
	//
22
	// PHP Markdown
23
	// Copyright (c) 2004-2013 Michel Fortin
24
	// <http://michelf.ca/projects/php-markdown/>
25
	//
26
	// Original Markdown
27
	// Copyright (c) 2004-2006 John Gruber
28
	// <http://daringfireball.net/projects/markdown/>
29
	//
30
	define( 'MARKDOWN_VERSION', '1.0.2' );
31
	// 29 Nov 2013
32
	//
33
	// Global default settings:
34
	//
35
	// Change to ">" for HTML output
36
	@define( 'MARKDOWN_EMPTY_ELEMENT_SUFFIX', ' />' );
0 ignored issues
show
Silencing errors is discouraged
Loading history...
37
38
	// Define the width of a tab for code blocks.
39
	@define( 'MARKDOWN_TAB_WIDTH', 4 );
0 ignored issues
show
Silencing errors is discouraged
Loading history...
40
41
	//
42
	// WordPress settings:
43
	//
44
	// Change to false to remove Markdown from posts and/or comments.
45
	@define( 'MARKDOWN_WP_POSTS', true );
0 ignored issues
show
Silencing errors is discouraged
Loading history...
46
	@define( 'MARKDOWN_WP_COMMENTS', true );
0 ignored issues
show
Silencing errors is discouraged
Loading history...
47
48
	// Standard Function Interface ###
49
	@define( 'MARKDOWN_PARSER_CLASS', 'Markdown_Parser' );
0 ignored issues
show
Silencing errors is discouraged
Loading history...
50
51
	/**
52
	 * @param $text
53
	 *
54
	 * @return mixed
55
	 */
56
	function Markdown( $text ) {
0 ignored issues
show
The function name Markdown is in camel caps, but expected _markdown instead as per the coding standard.
Loading history...
57
58
		//
59
		// Initialize the parser and return the result of its transform method.
60
		//
61
		// Setup static parser variable.
62
		static $parser;
63
		if ( ! isset( $parser ) ) {
64
			$parser_class = MARKDOWN_PARSER_CLASS;
65
			$parser       = new $parser_class();
66
		}
67
68
		// Transform text using parser.
69
		return $parser->transform( $text );
70
	}
71
72
	// WordPress Plugin Interface ###
73
	if ( isset( $wp_version ) ) {
74
		// More details about how it works here:
75
		// <http://michelf.ca/weblog/2005/wordpress-text-flow-vs-markdown/>
76
		// Post content and excerpts
77
		// - Remove WordPress paragraph generator.
78
		// - Run Markdown on excerpt, then remove all tags.
79
		// - Add paragraph tag around the excerpt, but remove it for the excerpt rss.
80
		if ( MARKDOWN_WP_POSTS ) {
81
			remove_filter( 'the_content', 'wpautop' );
82
			remove_filter( 'the_content_rss', 'wpautop' );
83
			remove_filter( 'the_excerpt', 'wpautop' );
84
			add_filter( 'the_content', 'Markdown', 6 );
85
			add_filter( 'the_content_rss', 'Markdown', 6 );
86
			add_filter( 'get_the_excerpt', 'Markdown', 6 );
87
			add_filter( 'get_the_excerpt', 'trim', 7 );
88
			add_filter( 'the_excerpt', 'mdwp_add_p' );
89
			add_filter( 'the_excerpt_rss', 'mdwp_strip_p' );
90
91
			remove_filter( 'content_save_pre', 'balanceTags', 50 );
92
			remove_filter( 'excerpt_save_pre', 'balanceTags', 50 );
93
			add_filter( 'the_content', 'balanceTags', 50 );
94
			add_filter( 'get_the_excerpt', 'balanceTags', 9 );
95
		}
96
97
		// Comments
98
		// - Remove WordPress paragraph generator.
99
		// - Remove WordPress auto-link generator.
100
		// - Scramble important tags before passing them to the kses filter.
101
		// - Run Markdown on excerpt then remove paragraph tags.
102
		if ( MARKDOWN_WP_COMMENTS ) {
103
			remove_filter( 'comment_text', 'wpautop', 30 );
104
			remove_filter( 'comment_text', 'make_clickable' );
105
			add_filter( 'pre_comment_content', 'Markdown', 6 );
106
			add_filter( 'pre_comment_content', 'mdwp_hide_tags', 8 );
107
			add_filter( 'pre_comment_content', 'mdwp_show_tags', 12 );
108
			add_filter( 'get_comment_text', 'Markdown', 6 );
109
			add_filter( 'get_comment_excerpt', 'Markdown', 6 );
110
			add_filter( 'get_comment_excerpt', 'mdwp_strip_p', 7 );
111
112
			global $mdwp_hidden_tags, $mdwp_placeholders;
0 ignored issues
show
Compatibility Best Practice introduced by
Use of global functionality is not recommended; it makes your code harder to test, and less reusable.

Instead of relying on global state, we recommend one of these alternatives:

1. Pass all data via parameters

function myFunction($a, $b) {
    // Do something
}

2. Create a class that maintains your state

class MyClass {
    private $a;
    private $b;

    public function __construct($a, $b) {
        $this->a = $a;
        $this->b = $b;
    }

    public function myFunction() {
        // Do something
    }
}
Loading history...
113
			$mdwp_hidden_tags  = explode( ' ', '<p> </p> <pre> </pre> <ol> </ol> <ul> </ul> <li> </li>' );
114
			$mdwp_placeholders = explode( ' ', str_rot13( 'pEj07ZbbBZ U1kqgh4w4p pre2zmeN6K QTi31t9pre ol0MP1jzJR ' . 'ML5IjmbRol ulANi1NsGY J7zRLJqPul liA8ctl16T K9nhooUHli' ) );
115
		}
116
117
		/**
118
		 * @param $text
119
		 *
120
		 * @return mixed|string
121
		 */
122
		function mdwp_add_p( $text ) {
123
124
			if ( ! preg_match( '{^$|^<(p|ul|ol|dl|pre|blockquote)>}i', $text ) ) {
125
				$text = '<p>' . $text . '</p>';
126
				$text = preg_replace( '{\n{2,}}', "</p>\n\n<p>", $text );
127
			}
128
129
			return $text;
130
		}
131
132
		/**
133
		 * @param $t
134
		 *
135
		 * @return mixed
136
		 */
137
		function mdwp_strip_p( $t ) {
0 ignored issues
show
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...
138
139
			return preg_replace( '{</?p>}i', '', $t );
140
		}
141
142
		/**
143
		 * @param $text
144
		 *
145
		 * @return mixed
146
		 */
147
		function mdwp_hide_tags( $text ) {
148
149
			global $mdwp_hidden_tags, $mdwp_placeholders;
0 ignored issues
show
Compatibility Best Practice introduced by
Use of global functionality is not recommended; it makes your code harder to test, and less reusable.

Instead of relying on global state, we recommend one of these alternatives:

1. Pass all data via parameters

function myFunction($a, $b) {
    // Do something
}

2. Create a class that maintains your state

class MyClass {
    private $a;
    private $b;

    public function __construct($a, $b) {
        $this->a = $a;
        $this->b = $b;
    }

    public function myFunction() {
        // Do something
    }
}
Loading history...
150
151
			return str_replace( $mdwp_hidden_tags, $mdwp_placeholders, $text );
152
		}
153
154
		/**
155
		 * @param $text
156
		 *
157
		 * @return mixed
158
		 */
159
		function mdwp_show_tags( $text ) {
160
161
			global $mdwp_hidden_tags, $mdwp_placeholders;
0 ignored issues
show
Compatibility Best Practice introduced by
Use of global functionality is not recommended; it makes your code harder to test, and less reusable.

Instead of relying on global state, we recommend one of these alternatives:

1. Pass all data via parameters

function myFunction($a, $b) {
    // Do something
}

2. Create a class that maintains your state

class MyClass {
    private $a;
    private $b;

    public function __construct($a, $b) {
        $this->a = $a;
        $this->b = $b;
    }

    public function myFunction() {
        // Do something
    }
}
Loading history...
162
163
			return str_replace( $mdwp_placeholders, $mdwp_hidden_tags, $text );
164
		}
165
	}//end if
166
167
	// bBlog Plugin Info ###
168
	/**
169
	 * @return array
0 ignored issues
show
Consider making the return type a bit more specific; maybe use array<string,string>.

This check looks for the generic type array as a return type and suggests a more specific type. This type is inferred from the actual code.

Loading history...
170
	 */
171
	function identify_modifier_markdown() {
172
173
		return array(
174
			'name'        => 'markdown',
175
			'type'        => 'modifier',
176
			'nicename'    => 'Markdown',
177
			'description' => 'A text-to-HTML conversion tool for web writers',
178
			'authors'     => 'Michel Fortin and John Gruber',
179
			'licence'     => 'BSD-like',
180
			'version'     => MARKDOWN_VERSION,
181
			'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://michelf.ca/projects/php-markdown/">More...</a>',
182
		);
183
	}
184
185
	// Smarty Modifier Interface ###
186
	/**
187
	 * @param $text
188
	 *
189
	 * @return mixed
190
	 */
191
	function smarty_modifier_markdown( $text ) {
192
193
		return Markdown( $text );
194
	}
195
196
	// Textile Compatibility Mode ###
197
	// Rename this file to "classTextile.php" and it can replace Textile everywhere.
198
	if ( strcasecmp( substr( __FILE__, - 16 ), 'classTextile.php' ) == 0 ) {
0 ignored issues
show
Found "== 0". Use Yoda Condition checks, you must
Loading history...
199
		// Try to include PHP SmartyPants. Should be in the same directory.
200
		@include_once 'smartypants.php';
0 ignored issues
show
Silencing errors is discouraged
Loading history...
201
202
		// Fake Textile class. It calls Markdown instead.
203
204
		/**
205
		 * Class Textile
206
		 */
207
		class Textile {
208
209
			/**
210
			 * @param        $text
211
			 * @param string $lite
212
			 * @param string $encode
213
			 *
214
			 * @return mixed
215
			 */
216
			public function TextileThis( $text, $lite = '', $encode = '' ) {
0 ignored issues
show
The function name TextileThis is in camel caps, but expected _textile_this instead as per the coding standard.
Loading history...
217
218
				if ( $lite == '' && $encode == '' ) {
219
					$text = Markdown( $text );
220
				}
221
				if ( function_exists( 'SmartyPants' ) ) {
222
					$text = SmartyPants( $text );
223
				}
224
225
				return $text;
226
			}
227
228
			// Fake restricted version: restrictions are not supported for now.
229
230
			/**
231
			 * @param        $text
232
			 * @param string $lite
233
			 * @param string $noimage
234
			 *
235
			 * @return mixed
236
			 */
237
			public function TextileRestricted( $text, $lite = '', $noimage = '' ) {
0 ignored issues
show
The function name TextileRestricted is in camel caps, but expected _textile_restricted instead as per the coding standard.
Loading history...
238
239
				return $this->TextileThis( $text, $lite );
240
			}
241
242
			// Workaround to ensure compatibility with TextPattern 4.0.3.
243
244
			/**
245
			 * @param $text
246
			 *
247
			 * @return mixed
248
			 */
249
			public function blockLite( $text ) {
0 ignored issues
show
The function name blockLite is in camel caps, but expected block_lite instead as per the coding standard.
Loading history...
250
251
				return $text;
252
			}
253
		}
254
	}//end if
255
256
	//
257
	// Markdown Parser Class
258
	//
259
260
	/**
261
	 * Class Markdown_Parser
262
	 */
263
	class Markdown_Parser {
264
265
		// Configuration Variables ###
266
		// Change to ">" for HTML output.
267
		public $empty_element_suffix = MARKDOWN_EMPTY_ELEMENT_SUFFIX;
268
		public $tab_width = MARKDOWN_TAB_WIDTH;
269
270
		// Change to `true` to disallow markup or entities.
271
		public $no_markup = false;
272
		public $no_entities = false;
273
274
		// Predefined urls and titles for reference links and images.
275
		public $predef_urls = array();
276
		public $predef_titles = array();
277
278
		// Parser Implementation ###
279
		// Regex to match balanced [brackets].
280
		// Needed to insert a maximum bracked depth while converting to PHP.
281
		public $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...
282
		public $nested_brackets_re;
283
284
		public $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...
285
		public $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...
286
287
		// Table of hash values for escaped characters:
288
		public $escape_chars = '\`*_{}[]()>#+-.!';
289
		public $escape_chars_re;
290
291
		/**
292
		 * Markdown_Parser constructor.
293
		 */
294
		public function __construct() {
295
296
			//
297
			// Constructor function. Initialize appropriate member variables.
298
			//
299
			$this->_initDetab();
300
			$this->prepareItalicsAndBold();
301
302
			$this->nested_brackets_re = str_repeat( '(?>[^\[\]]+|\[', $this->nested_brackets_depth ) . str_repeat( '\])*', $this->nested_brackets_depth );
303
304
			$this->nested_url_parenthesis_re = str_repeat( '(?>[^()\s]+|\(', $this->nested_url_parenthesis_depth ) . str_repeat( '(?>\)))*', $this->nested_url_parenthesis_depth );
305
306
			$this->escape_chars_re = '[' . preg_quote( $this->escape_chars ) . ']';
307
308
			// Sort document, block, and span gamut in ascendent priority order.
309
			asort( $this->document_gamut );
310
			asort( $this->block_gamut );
311
			asort( $this->span_gamut );
312
		}
313
314
		// Internal hashes used during transformation.
315
		public $urls = array();
316
		public $titles = array();
317
		public $html_hashes = array();
318
319
		// Status flag to avoid invalid nesting.
320
		public $in_anchor = false;
321
322
		public function setup() {
323
324
			//
325
			// Called before the transformation process starts to setup parser
326
			// states.
327
			//
328
			// Clear global hashes.
329
			$this->urls        = $this->predef_urls;
330
			$this->titles      = $this->predef_titles;
331
			$this->html_hashes = array();
332
333
			$this->in_anchor = false;
334
		}
335
336
		public function teardown() {
337
338
			//
339
			// Called after the transformation process to clear any variable
340
			// which may be taking up memory unnecessarly.
341
			//
342
			$this->urls        = array();
343
			$this->titles      = array();
344
			$this->html_hashes = array();
345
		}
346
347
		/**
348
		 * @param $text
349
		 *
350
		 * @return string
351
		 */
352
		public function transform( $text ) {
353
354
			//
355
			// Main function. Performs some preprocessing on the input text
356
			// and pass it through the document gamut.
357
			//
358
			$this->setup();
359
360
			// Remove UTF-8 BOM and marker character in input, if present.
361
			$text = preg_replace( '{^\xEF\xBB\xBF|\x1A}', '', $text );
362
363
			// Standardize line endings:
364
			// DOS to Unix and Mac to Unix
365
			$text = preg_replace( '{\r\n?}', "\n", $text );
366
367
			// Make sure $text ends with a couple of newlines:
368
			$text .= "\n\n";
369
370
			// Convert all tabs to spaces.
371
			$text = $this->detab( $text );
372
373
			// Turn block-level HTML blocks into hash entries
374
			$text = $this->hashHTMLBlocks( $text );
375
376
			// Strip any lines consisting only of spaces and tabs.
377
			// This makes subsequent regexen easier to write, because we can
378
			// match consecutive blank lines with /\n+/ instead of something
379
			// contorted like /[ ]*\n+/ .
380
			$text = preg_replace( '/^[ ]+$/m', '', $text );
381
382
			// Run document gamut methods.
383
			foreach ( $this->document_gamut as $method => $priority ) {
384
				$text = $this->$method( $text );
385
			}
386
387
			$this->teardown();
388
389
			return $text . "\n";
390
		}
391
392
		public $document_gamut = array(
393
			// Strip link definitions, store in hashes.
394
			'stripLinkDefinitions' => 20,
395
396
			'runBasicBlockGamut' => 30,
397
		);
398
399
		/**
400
		 * @param $text
401
		 *
402
		 * @return mixed
403
		 */
404
		public function stripLinkDefinitions( $text ) {
0 ignored issues
show
The function name stripLinkDefinitions is in camel caps, but expected strip_link_definitions instead as per the coding standard.
Loading history...
405
406
			//
407
			// Strips link definitions from text, stores the URLs and titles in
408
			// hash references.
409
			//
410
			$less_than_tab = $this->tab_width - 1;
411
412
			// Link defs are in the form: ^[id]: url "optional title"
413
			$text = preg_replace_callback( '{
414
							^[ ]{0,' . $less_than_tab . '}\[(.+)\][ ]?:	# id = $1
415
							  [ ]*
416
							  \n?				# maybe *one* newline
417
							  [ ]*
418
							(?:
419
							  <(.+?)>			# url = $2
420
							|
421
							  (\S+?)			# url = $3
422
							)
423
							  [ ]*
424
							  \n?				# maybe one newline
425
							  [ ]*
426
							(?:
427
								(?<=\s)			# lookbehind for whitespace
428
								["(]
429
								(.*?)			# title = $4
430
								[")]
431
								[ ]*
432
							)?	# title is optional
433
							(?:\n+|\Z)
434
			}xm', array( &$this, '_stripLinkDefinitions_callback' ), $text );
435
436
			return $text;
437
		}
438
439
		/**
440
		 * @param $matches
441
		 *
442
		 * @return string
443
		 */
444
		public function _stripLinkDefinitions_callback( $matches ) {
0 ignored issues
show
The function name _stripLinkDefinitions_callback is in camel caps, but expected _strip_link_definitions_callback instead as per the coding standard.
Loading history...
445
446
			$link_id                  = strtolower( $matches[1] );
447
			$url                      = $matches[2] == '' ? $matches[3] : $matches[2];
448
			$this->urls[ $link_id ]   = $url;
449
			$this->titles[ $link_id ] =& $matches[4];
450
451
			return '';
452
			// String that will replace the block
453
		}
454
455
		/**
456
		 * @param $text
457
		 *
458
		 * @return mixed
459
		 */
460
		public function hashHTMLBlocks( $text ) {
0 ignored issues
show
The function name hashHTMLBlocks is in camel caps, but expected hash_h_t_m_l_blocks instead as per the coding standard.
Loading history...
461
462
			if ( $this->no_markup ) {
463
				return $text;
464
			}
465
466
			$less_than_tab = $this->tab_width - 1;
467
468
			// Hashify HTML blocks:
469
			// We only want to do this for block-level HTML tags, such as headers,
470
			// lists, and tables. That's because we still want to wrap <p>s around
471
			// "paragraphs" that are wrapped in non-block-level tags, such as anchors,
472
			// phrase emphasis, and spans. The list of tags we're looking for is
473
			// hard-coded:
474
			//
475
			// *  List "a" is made of tags which can be both inline or block-level.
476
			// These will be treated block-level when the start tag is alone on
477
			// its line, otherwise they're not matched here and will be taken as
478
			// inline later.
479
			// *  List "b" is made of tags which are always block-level;
480
			//
481
			$block_tags_a_re = 'ins|del';
482
			$block_tags_b_re = 'p|div|h[1-6]|blockquote|pre|table|dl|ol|ul|address|' . 'script|noscript|form|fieldset|iframe|math|svg|' . 'article|section|nav|aside|hgroup|header|footer|' . 'figure';
483
484
			// Regular expression for the content of a block tag.
485
			$nested_tags_level = 4;
486
			$attr              = '
487
			(?>				# optional tag attributes
488
			  \s			# starts with whitespace
489
			  (?>
490
				[^>"/]+		# text outside quotes
491
			  |
492
				/+(?!>)		# slash not followed by ">"
493
			  |
494
				"[^"]*"		# text inside double quotes (tolerate ">")
495
			  |
496
				\'[^\']*\'	# text inside single quotes (tolerate ">")
497
			  )*
498
			)?
499
			';
500
			$content           = str_repeat( '
501
				(?>
502
				  [^<]+			# content without tag
503
				|
504
				  <\2			# nested opening tag
505
					' . $attr . '	# attributes
506
					(?>
507
					  />
508
					|
509
					  >', $nested_tags_level ) . // end of opening tag
510
			                     '.*?' . // last level nested tag content
511
			                     str_repeat( '
512
					  </\2\s*>	# closing nested tag
513
					)
514
				  |
515
					<(?!/\2\s*>	# other tags with a different name
516
				  )
517
				)*', $nested_tags_level );
518
			$content2          = str_replace( '\2', '\3', $content );
519
520
			// First, look for nested blocks, e.g.:
521
			// <div>
522
			// <div>
523
			// tags for inner block must be indented.
524
			// </div>
525
			// </div>
526
			//
527
			// The outermost tags must start at the left margin for this to match, and
528
			// the inner nested divs must be indented.
529
			// We need to do this before the next, more liberal match, because the next
530
			// match will start at the first `<div>` and stop at the first `</div>`.
531
			$text = preg_replace_callback( '{(?>
532
			(?>
533
				(?<=\n\n)		# Starting after a blank line
534
				|				# or
535
				\A\n?			# the beginning of the doc
536
			)
537
			(						# save in $1
538
539
			  # Match from `\n<tag>` to `</tag>\n`, handling nested tags
540
			  # in between.
541
542
						[ ]{0,' . $less_than_tab . '}
543
						<(' . $block_tags_b_re . ')# start tag = $2
544
						' . $attr . '>			# attributes followed by > and \n
545
						' . $content . '		# content, support nesting
546
						</\2>				# the matching end tag
547
						[ ]*				# trailing spaces/tabs
548
						(?=\n+|\Z)	# followed by a newline or end of document
549
550
			| # Special version for tags of group a.
551
552
						[ ]{0,' . $less_than_tab . '}
553
						<(' . $block_tags_a_re . ')# start tag = $3
554
						' . $attr . '>[ ]*\n	# attributes followed by >
555
						' . $content2 . '		# content, support nesting
556
						</\3>				# the matching end tag
557
						[ ]*				# trailing spaces/tabs
558
						(?=\n+|\Z)	# followed by a newline or end of document
559
560
			| # Special case just for <hr />. It was easier to make a special
561
			  # case than to make the other regex more complicated.
562
563
						[ ]{0,' . $less_than_tab . '}
564
						<(hr)				# start tag = $2
565
						' . $attr . '			# attributes
566
						/?>					# the matching end tag
567
						[ ]*
568
						(?=\n{2,}|\Z)		# followed by a blank line or end of document
569
570
			| # Special case for standalone HTML comments:
571
572
					[ ]{0,' . $less_than_tab . '}
573
					(?s:
574
						<!-- .*? -->
575
					)
576
					[ ]*
577
					(?=\n{2,}|\Z)		# followed by a blank line or end of document
578
579
			| # PHP and ASP-style processor instructions (<? and <%)
580
581
					[ ]{0,' . $less_than_tab . '}
582
					(?s:
583
						<([?%])			# $2
584
						.*?
585
						\2>
586
					)
587
					[ ]*
588
					(?=\n{2,}|\Z)		# followed by a blank line or end of document
589
590
			)
591
			)}Sxmi', array( &$this, '_hashHTMLBlocks_callback' ), $text );
592
593
			return $text;
594
		}
595
596
		/**
597
		 * @param $matches
598
		 *
599
		 * @return string
600
		 */
601
		public function _hashHTMLBlocks_callback( $matches ) {
0 ignored issues
show
The function name _hashHTMLBlocks_callback is in camel caps, but expected _hash_h_t_m_l_blocks_callback instead as per the coding standard.
Loading history...
602
603
			$text = $matches[1];
604
			$key  = $this->hashBlock( $text );
605
606
			return "\n\n$key\n\n";
607
		}
608
609
		/**
610
		 * @param        $text
611
		 * @param string $boundary
612
		 *
613
		 * @return string
614
		 */
615
		public function hashPart( $text, $boundary = 'X' ) {
0 ignored issues
show
The function name hashPart is in camel caps, but expected hash_part instead as per the coding standard.
Loading history...
616
617
			//
618
			// Called whenever a tag must be hashed when a function insert an atomic
619
			// element in the text stream. Passing $text to through this function gives
620
			// a unique text-token which will be reverted back when calling unhash.
621
			//
622
			// The $boundary argument specify what character should be used to surround
623
			// the token. By convension, "B" is used for block elements that needs not
624
			// to be wrapped into paragraph tags at the end, ":" is used for elements
625
			// that are word separators and "X" is used in the general case.
626
			//
627
			// Swap back any tag hash found in $text so we do not have to `unhash`
628
			// multiple times at the end.
629
			$text = $this->unhash( $text );
630
631
			// Then hash the block.
632
			static $i = 0;
633
			$key                       = "$boundary\x1A" . ++ $i . $boundary;
634
			$this->html_hashes[ $key ] = $text;
635
636
			return $key;
637
			// String that will replace the tag.
638
		}
639
640
		/**
641
		 * @param $text
642
		 *
643
		 * @return string
644
		 */
645
		public function hashBlock( $text ) {
0 ignored issues
show
The function name hashBlock is in camel caps, but expected hash_block instead as per the coding standard.
Loading history...
646
647
			//
648
			// Shortcut function for hashPart with block-level boundaries.
649
			//
650
			return $this->hashPart( $text, 'B' );
651
		}
652
653
		public $block_gamut = array(
654
			//
655
			// These are all the transformations that form block-level
656
			// tags like paragraphs, headers, and list items.
657
			//
658
			'doHeaders'         => 10,
659
			'doHorizontalRules' => 20,
660
661
			'doLists'       => 40,
662
			'doCodeBlocks'  => 50,
663
			'doBlockQuotes' => 60,
664
		);
665
666
		/**
667
		 * @param $text
668
		 *
669
		 * @return string
670
		 */
671
		public function runBlockGamut( $text ) {
0 ignored issues
show
The function name runBlockGamut is in camel caps, but expected run_block_gamut instead as per the coding standard.
Loading history...
672
673
			//
674
			// Run block gamut tranformations.
675
			//
676
			// We need to escape raw HTML in Markdown source before doing anything
677
			// else. This need to be done for each block, and not only at the
678
			// begining in the Markdown function since hashed blocks can be part of
679
			// list items and could have been indented. Indented blocks would have
680
			// been seen as a code block in a previous pass of hashHTMLBlocks.
681
			$text = $this->hashHTMLBlocks( $text );
682
683
			return $this->runBasicBlockGamut( $text );
684
		}
685
686
		/**
687
		 * @param $text
688
		 *
689
		 * @return string
690
		 */
691
		public function runBasicBlockGamut( $text ) {
0 ignored issues
show
The function name runBasicBlockGamut is in camel caps, but expected run_basic_block_gamut instead as per the coding standard.
Loading history...
692
693
			//
694
			// Run block gamut tranformations, without hashing HTML blocks. This is
695
			// useful when HTML blocks are known to be already hashed, like in the first
696
			// whole-document pass.
697
			//
698
			foreach ( $this->block_gamut as $method => $priority ) {
699
				$text = $this->$method( $text );
700
			}
701
702
			// Finally form paragraph and restore hashed blocks.
703
			$text = $this->formParagraphs( $text );
704
705
			return $text;
706
		}
707
708
		/**
709
		 * @param $text
710
		 *
711
		 * @return mixed
712
		 */
713
		public function doHorizontalRules( $text ) {
0 ignored issues
show
The function name doHorizontalRules is in camel caps, but expected do_horizontal_rules instead as per the coding standard.
Loading history...
714
715
			// Do Horizontal Rules:
716
			return preg_replace( '{
717
				^[ ]{0,3}	# Leading space
718
				([-*_])		# $1: First marker
719
				(?>			# Repeated marker group
720
					[ ]{0,2}	# Zero, one, or two spaces.
721
					\1			# Marker character
722
				){2,}		# Group repeated at least twice
723
				[ ]*		# Tailing spaces
724
				$			# End of line.
725
			}mx', "\n" . $this->hashBlock( "<hr$this->empty_element_suffix" ) . "\n", $text );
726
		}
727
728
		public $span_gamut = array(
729
			//
730
			// These are all the transformations that occur *within* block-level
731
			// tags like paragraphs, headers, and list items.
732
			//
733
			// Process character escapes, code spans, and inline HTML
734
			// in one shot.
735
			'parseSpan'           => - 30,
736
737
			// Process anchor and image tags. Images must come first,
738
			// because ![foo][f] looks like an anchor.
739
			'doImages'            => 10,
740
			'doAnchors'           => 20,
741
742
			// Make links out of things like `<http://example.com/>`
743
			// Must come after doAnchors, because you can use < and >
744
			// delimiters in inline links like [this](<url>).
745
			'doAutoLinks'         => 30,
746
			'encodeAmpsAndAngles' => 40,
747
748
			'doItalicsAndBold' => 50,
749
			'doHardBreaks'     => 60,
750
		);
751
752
		/**
753
		 * @param $text
754
		 *
755
		 * @return mixed
756
		 */
757
		public function runSpanGamut( $text ) {
0 ignored issues
show
The function name runSpanGamut is in camel caps, but expected run_span_gamut instead as per the coding standard.
Loading history...
758
759
			//
760
			// Run span gamut tranformations.
761
			//
762
			foreach ( $this->span_gamut as $method => $priority ) {
763
				$text = $this->$method( $text );
764
			}
765
766
			return $text;
767
		}
768
769
		/**
770
		 * @param $text
771
		 *
772
		 * @return mixed
773
		 */
774
		public function doHardBreaks( $text ) {
0 ignored issues
show
The function name doHardBreaks is in camel caps, but expected do_hard_breaks instead as per the coding standard.
Loading history...
775
776
			// Do hard breaks:
777
			return preg_replace_callback( '/ {2,}\n/', array( &$this, '_doHardBreaks_callback' ), $text );
778
		}
779
780
		/**
781
		 * @param $matches
782
		 *
783
		 * @return string
784
		 */
785
		public function _doHardBreaks_callback( $matches ) {
0 ignored issues
show
The function name _doHardBreaks_callback is in camel caps, but expected _do_hard_breaks_callback instead as per the coding standard.
Loading history...
786
787
			return $this->hashPart( "<br$this->empty_element_suffix\n" );
788
		}
789
790
		/**
791
		 * @param $text
792
		 *
793
		 * @return mixed
794
		 */
795
		public function doAnchors( $text ) {
0 ignored issues
show
The function name doAnchors is in camel caps, but expected do_anchors instead as per the coding standard.
Loading history...
796
797
			//
798
			// Turn Markdown link shortcuts into XHTML <a> tags.
799
			//
800
			if ( $this->in_anchor ) {
801
				return $text;
802
			}
803
			$this->in_anchor = true;
804
805
			//
806
			// First, handle reference-style links: [link text] [id]
807
			//
808
			$text = preg_replace_callback( '{
809
			(					# wrap whole match in $1
810
			  \[
811
				(' . $this->nested_brackets_re . ')	# link text = $2
812
			  \]
813
814
			  [ ]?				# one optional space
815
			  (?:\n[ ]*)?		# one optional newline followed by spaces
816
817
			  \[
818
				(.*?)		# id = $3
819
			  \]
820
			)
821
			}xs', array( &$this, '_doAnchors_reference_callback' ), $text );
822
823
			//
824
			// Next, inline-style links: [link text](url "optional title")
825
			//
826
			$text = preg_replace_callback( '{
827
			(				# wrap whole match in $1
828
			  \[
829
				(' . $this->nested_brackets_re . ')	# link text = $2
830
			  \]
831
			  \(			# literal paren
832
				[ \n]*
833
				(?:
834
					<(.+?)>	# href = $3
835
				|
836
					(' . $this->nested_url_parenthesis_re . ')	# href = $4
837
				)
838
				[ \n]*
839
				(			# $5
840
				  ([\'"])	# quote char = $6
841
				  (.*?)		# Title = $7
842
				  \6		# matching quote
843
				  [ \n]*	# ignore any spaces/tabs between closing quote and )
844
				)?			# title is optional
845
			  \)
846
			)
847
			}xs', array( &$this, '_doAnchors_inline_callback' ), $text );
848
849
			//
850
			// Last, handle reference-style shortcuts: [link text]
851
			// These must come last in case you've also got [link text][1]
852
			// or [link text](/foo)
0 ignored issues
show
Unused Code Comprehensibility introduced by
42% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
853
			//
854
			$text = preg_replace_callback( '{
855
			(					# wrap whole match in $1
856
			  \[
857
				([^\[\]]+)		# link text = $2; can\'t contain [ or ]
858
			  \]
859
			)
860
			}xs', array( &$this, '_doAnchors_reference_callback' ), $text );
861
862
			$this->in_anchor = false;
863
864
			return $text;
865
		}
866
867
		/**
868
		 * @param $matches
869
		 *
870
		 * @return string
871
		 */
872
		public function _doAnchors_reference_callback( $matches ) {
0 ignored issues
show
The function name _doAnchors_reference_callback is in camel caps, but expected _do_anchors_reference_callback instead as per the coding standard.
Loading history...
873
874
			$whole_match = $matches[1];
875
			$link_text   = $matches[2];
876
			$link_id     =& $matches[3];
877
878
			if ( $link_id == '' ) {
879
				// for shortcut links like [this][] or [this].
0 ignored issues
show
Unused Code Comprehensibility introduced by
39% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
880
				$link_id = $link_text;
881
			}
882
883
			// lower-case and turn embedded newlines into spaces
884
			$link_id = strtolower( $link_id );
885
			$link_id = preg_replace( '{[ ]?\n}', ' ', $link_id );
886
887
			if ( isset( $this->urls[ $link_id ] ) ) {
888
				$url = $this->urls[ $link_id ];
889
				$url = $this->encodeAttribute( $url );
890
891
				$result = "<a href=\"$url\"";
892
				if ( isset( $this->titles[ $link_id ] ) ) {
893
					$title  = $this->titles[ $link_id ];
894
					$title  = $this->encodeAttribute( $title );
895
					$result .= " title=\"$title\"";
896
				}
897
898
				$link_text = $this->runSpanGamut( $link_text );
899
				$result    .= ">$link_text</a>";
900
				$result    = $this->hashPart( $result );
901
			} else {
902
				$result = $whole_match;
903
			}
904
905
			return $result;
906
		}
907
908
		/**
909
		 * @param $matches
910
		 *
911
		 * @return string
912
		 */
913
		public function _doAnchors_inline_callback( $matches ) {
0 ignored issues
show
The function name _doAnchors_inline_callback is in camel caps, but expected _do_anchors_inline_callback instead as per the coding standard.
Loading history...
914
915
			$whole_match = $matches[1];
916
			$link_text   = $this->runSpanGamut( $matches[2] );
917
			$url         = $matches[3] == '' ? $matches[4] : $matches[3];
918
			$title       =& $matches[7];
919
920
			$url = $this->encodeAttribute( $url );
921
922
			$result = "<a href=\"$url\"";
923
			if ( isset( $title ) ) {
924
				$title  = $this->encodeAttribute( $title );
925
				$result .= " title=\"$title\"";
926
			}
927
928
			$link_text = $this->runSpanGamut( $link_text );
929
			$result    .= ">$link_text</a>";
930
931
			return $this->hashPart( $result );
932
		}
933
934
		/**
935
		 * @param $text
936
		 *
937
		 * @return mixed
938
		 */
939
		public function doImages( $text ) {
0 ignored issues
show
The function name doImages is in camel caps, but expected do_images instead as per the coding standard.
Loading history...
940
941
			//
942
			// Turn Markdown image shortcuts into <img> tags.
943
			//
944
			//
945
			// First, handle reference-style labeled images: ![alt text][id]
946
			//
947
			$text = preg_replace_callback( '{
948
			(				# wrap whole match in $1
949
			  !\[
950
				(' . $this->nested_brackets_re . ')		# alt text = $2
951
			  \]
952
953
			  [ ]?				# one optional space
954
			  (?:\n[ ]*)?		# one optional newline followed by spaces
955
956
			  \[
957
				(.*?)		# id = $3
958
			  \]
959
960
			)
961
			}xs', array( &$this, '_doImages_reference_callback' ), $text );
962
963
			//
964
			// Next, handle inline images:  ![alt text](url "optional title")
965
			// Don't forget: encode * and _
966
			//
967
			$text = preg_replace_callback( '{
968
			(				# wrap whole match in $1
969
			  !\[
970
				(' . $this->nested_brackets_re . ')		# alt text = $2
971
			  \]
972
			  \s?			# One optional whitespace character
973
			  \(			# literal paren
974
				[ \n]*
975
				(?:
976
					<(\S*)>	# src url = $3
977
				|
978
					(' . $this->nested_url_parenthesis_re . ')	# src url = $4
979
				)
980
				[ \n]*
981
				(			# $5
982
				  ([\'"])	# quote char = $6
983
				  (.*?)		# title = $7
984
				  \6		# matching quote
985
				  [ \n]*
986
				)?			# title is optional
987
			  \)
988
			)
989
			}xs', array( &$this, '_doImages_inline_callback' ), $text );
990
991
			return $text;
992
		}
993
994
		/**
995
		 * @param $matches
996
		 *
997
		 * @return string
998
		 */
999
		public function _doImages_reference_callback( $matches ) {
0 ignored issues
show
The function name _doImages_reference_callback is in camel caps, but expected _do_images_reference_callback instead as per the coding standard.
Loading history...
1000
1001
			$whole_match = $matches[1];
1002
			$alt_text    = $matches[2];
1003
			$link_id     = strtolower( $matches[3] );
1004
1005
			if ( $link_id == '' ) {
1006
				$link_id = strtolower( $alt_text );
1007
				// for shortcut links like ![this][].
0 ignored issues
show
Unused Code Comprehensibility introduced by
38% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
1008
			}
1009
1010
			$alt_text = $this->encodeAttribute( $alt_text );
1011
			if ( isset( $this->urls[ $link_id ] ) ) {
1012
				$url    = $this->encodeAttribute( $this->urls[ $link_id ] );
1013
				$result = "<img src=\"$url\" alt=\"$alt_text\"";
1014
				if ( isset( $this->titles[ $link_id ] ) ) {
1015
					$title  = $this->titles[ $link_id ];
1016
					$title  = $this->encodeAttribute( $title );
1017
					$result .= " title=\"$title\"";
1018
				}
1019
				$result .= $this->empty_element_suffix;
1020
				$result = $this->hashPart( $result );
1021
			} else {
1022
				// If there's no such link ID, leave intact:
1023
				$result = $whole_match;
1024
			}
1025
1026
			return $result;
1027
		}
1028
1029
		/**
1030
		 * @param $matches
1031
		 *
1032
		 * @return string
1033
		 */
1034
		public function _doImages_inline_callback( $matches ) {
0 ignored issues
show
The function name _doImages_inline_callback is in camel caps, but expected _do_images_inline_callback instead as per the coding standard.
Loading history...
1035
1036
			$whole_match = $matches[1];
1037
			$alt_text    = $matches[2];
1038
			$url         = $matches[3] == '' ? $matches[4] : $matches[3];
1039
			$title       =& $matches[7];
1040
1041
			$alt_text = $this->encodeAttribute( $alt_text );
1042
			$url      = $this->encodeAttribute( $url );
1043
			$result   = "<img src=\"$url\" alt=\"$alt_text\"";
1044
			if ( isset( $title ) ) {
1045
				$title  = $this->encodeAttribute( $title );
1046
				$result .= " title=\"$title\"";
1047
				// $title already quoted
1048
			}
1049
			$result .= $this->empty_element_suffix;
1050
1051
			return $this->hashPart( $result );
1052
		}
1053
1054
		/**
1055
		 * @param $text
1056
		 *
1057
		 * @return mixed
1058
		 */
1059
		public function doHeaders( $text ) {
0 ignored issues
show
The function name doHeaders is in camel caps, but expected do_headers instead as per the coding standard.
Loading history...
1060
1061
			// Setext-style headers:
1062
			// Header 1
1063
			// ========
1064
			//
1065
			// Header 2
1066
			// --------
1067
			//
1068
			$text = preg_replace_callback( '{ ^(.+?)[ ]*\n(=+|-+)[ ]*\n+ }mx', array(
1069
				&$this,
1070
				'_doHeaders_callback_setext',
1071
			), $text );
1072
1073
			// atx-style headers:
1074
			// Header 1
1075
			// Header 2
1076
			// Header 2 with closing hashes ##
1077
			// ...
1078
			// Header 6
1079
			//
1080
			$text = preg_replace_callback( '{
1081
				^(\#{1,6})	# $1 = string of #\'s
1082
				[ ]*
1083
				(.+?)		# $2 = Header text
1084
				[ ]*
1085
				\#*			# optional closing #\'s (not counted)
1086
				\n+
1087
			}xm', array( &$this, '_doHeaders_callback_atx' ), $text );
1088
1089
			return $text;
1090
		}
1091
1092
		/**
1093
		 * @param $matches
1094
		 *
1095
		 * @return string
1096
		 */
1097
		public function _doHeaders_callback_setext( $matches ) {
0 ignored issues
show
The function name _doHeaders_callback_setext is in camel caps, but expected _do_headers_callback_setext instead as per the coding standard.
Loading history...
1098
1099
			// Terrible hack to check we haven't found an empty list item.
1100
			if ( $matches[2] == '-' && preg_match( '{^-(?: |$)}', $matches[1] ) ) {
1101
				return $matches[0];
1102
			}
1103
1104
			$level = $matches[2]{0} == '=' ? 1 : 2;
1105
			$block = "<h$level>" . $this->runSpanGamut( $matches[1] ) . "</h$level>";
1106
1107
			return "\n" . $this->hashBlock( $block ) . "\n\n";
1108
		}
1109
1110
		/**
1111
		 * @param $matches
1112
		 *
1113
		 * @return string
1114
		 */
1115
		public function _doHeaders_callback_atx( $matches ) {
0 ignored issues
show
The function name _doHeaders_callback_atx is in camel caps, but expected _do_headers_callback_atx instead as per the coding standard.
Loading history...
1116
1117
			$level = strlen( $matches[1] );
1118
			$block = "<h$level>" . $this->runSpanGamut( $matches[2] ) . "</h$level>";
1119
1120
			return "\n" . $this->hashBlock( $block ) . "\n\n";
1121
		}
1122
1123
		/**
1124
		 * @param $text
1125
		 *
1126
		 * @return mixed
1127
		 */
1128
		public function doLists( $text ) {
0 ignored issues
show
The function name doLists is in camel caps, but expected do_lists instead as per the coding standard.
Loading history...
1129
1130
			//
1131
			// Form HTML ordered (numbered) and unordered (bulleted) lists.
1132
			//
1133
			$less_than_tab = $this->tab_width - 1;
1134
1135
			// Re-usable patterns to match list item bullets and number markers:
1136
			$marker_ul_re  = '[*+-]';
1137
			$marker_ol_re  = '\d+[\.]';
1138
			$marker_any_re = "(?:$marker_ul_re|$marker_ol_re)";
1139
1140
			$markers_relist = array(
1141
				$marker_ul_re => $marker_ol_re,
1142
				$marker_ol_re => $marker_ul_re,
1143
			);
1144
1145
			foreach ( $markers_relist as $marker_re => $other_marker_re ) {
1146
				// Re-usable pattern to match any entirel ul or ol list:
1147
				$whole_list_re = '
1148
				(								# $1 = whole list
1149
				  (								# $2
1150
					([ ]{0,' . $less_than_tab . '})	# $3 = number of spaces
1151
					(' . $marker_re . ')			# $4 = first list item marker
1152
					[ ]+
1153
				  )
1154
				  (?s:.+?)
1155
				  (								# $5
1156
					  \z
1157
					|
1158
					  \n{2,}
1159
					  (?=\S)
1160
					  (?!						# Negative lookahead for another list item marker
1161
						[ ]*
1162
						' . $marker_re . '[ ]+
1163
					  )
1164
					|
1165
					  (?=						# Lookahead for another kind of list
1166
					    \n
1167
						\3						# Must have the same indentation
1168
						' . $other_marker_re . '[ ]+
1169
					  )
1170
				  )
1171
				)
1172
			';
1173
				// mx
1174
				// We use a different prefix before nested lists than top-level lists.
1175
				// See extended comment in _ProcessListItems().
1176
				if ( $this->list_level ) {
1177
					$text = preg_replace_callback( '{
1178
						^
1179
						' . $whole_list_re . '
1180
					}mx', array( &$this, '_doLists_callback' ), $text );
1181
				} else {
1182
					$text = preg_replace_callback( '{
1183
						(?:(?<=\n)\n|\A\n?) # Must eat the newline
1184
						' . $whole_list_re . '
1185
					}mx', array( &$this, '_doLists_callback' ), $text );
1186
				}
1187
			}//end foreach
1188
1189
			return $text;
1190
		}
1191
1192
		/**
1193
		 * @param $matches
1194
		 *
1195
		 * @return string
1196
		 */
1197
		public function _doLists_callback( $matches ) {
0 ignored issues
show
The function name _doLists_callback is in camel caps, but expected _do_lists_callback instead as per the coding standard.
Loading history...
1198
1199
			// Re-usable patterns to match list item bullets and number markers:
1200
			$marker_ul_re  = '[*+-]';
1201
			$marker_ol_re  = '\d+[\.]';
1202
			$marker_any_re = "(?:$marker_ul_re|$marker_ol_re)";
1203
1204
			$list      = $matches[1];
1205
			$list_type = preg_match( "/$marker_ul_re/", $matches[4] ) ? 'ul' : 'ol';
1206
1207
			$marker_any_re = ( $list_type == 'ul' ? $marker_ul_re : $marker_ol_re );
1208
1209
			$list   .= "\n";
1210
			$result = $this->processListItems( $list, $marker_any_re );
1211
1212
			$result = $this->hashBlock( "<$list_type>\n" . $result . "</$list_type>" );
1213
1214
			return "\n" . $result . "\n\n";
1215
		}
1216
1217
		public $list_level = 0;
1218
1219
		/**
1220
		 * @param $list_str
1221
		 * @param $marker_any_re
1222
		 *
1223
		 * @return mixed
1224
		 */
1225
		public function processListItems( $list_str, $marker_any_re ) {
0 ignored issues
show
The function name processListItems is in camel caps, but expected process_list_items instead as per the coding standard.
Loading history...
1226
1227
			//
1228
			// Process the contents of a single ordered or unordered list, splitting it
1229
			// into individual list items.
1230
			//
1231
			// The $this->list_level global keeps track of when we're inside a list.
1232
			// Each time we enter a list, we increment it; when we leave a list,
1233
			// we decrement. If it's zero, we're not in a list anymore.
1234
			//
1235
			// We do this because when we're not inside a list, we want to treat
1236
			// something like this:
1237
			//
1238
			// I recommend upgrading to version
1239
			// 8. Oops, now this line is treated
1240
			// as a sub-list.
1241
			//
1242
			// As a single paragraph, despite the fact that the second line starts
1243
			// with a digit-period-space sequence.
1244
			//
1245
			// Whereas when we're inside a list (or sub-list), that line will be
1246
			// treated as the start of a sub-list. What a kludge, huh? This is
1247
			// an aspect of Markdown's syntax that's hard to parse perfectly
1248
			// without resorting to mind-reading. Perhaps the solution is to
1249
			// change the syntax rules such that sub-lists must start with a
1250
			// starting cardinal number; e.g. "1." or "a.".
1251
			$this->list_level ++;
1252
1253
			// trim trailing blank lines:
1254
			$list_str = preg_replace( "/\n{2,}\\z/", "\n", $list_str );
1255
1256
			$list_str = preg_replace_callback( '{
1257
			(\n)?							# leading line = $1
1258
			(^[ ]*)							# leading whitespace = $2
1259
			(' . $marker_any_re . '				# list marker and space = $3
1260
				(?:[ ]+|(?=\n))	# space only required if item is not empty
1261
			)
1262
			((?s:.*?))						# list item text   = $4
1263
			(?:(\n+(?=\n))|\n)				# tailing blank line = $5
1264
			(?= \n* (\z | \2 (' . $marker_any_re . ') (?:[ ]+|(?=\n))))
1265
			}xm', array( &$this, '_processListItems_callback' ), $list_str );
1266
1267
			$this->list_level --;
1268
1269
			return $list_str;
1270
		}
1271
1272
		/**
1273
		 * @param $matches
1274
		 *
1275
		 * @return string
1276
		 */
1277
		public function _processListItems_callback( $matches ) {
0 ignored issues
show
The function name _processListItems_callback is in camel caps, but expected _process_list_items_callback instead as per the coding standard.
Loading history...
1278
1279
			$item               = $matches[4];
1280
			$leading_line       =& $matches[1];
1281
			$leading_space      =& $matches[2];
1282
			$marker_space       = $matches[3];
1283
			$tailing_blank_line =& $matches[5];
1284
1285
			if ( $leading_line || $tailing_blank_line || preg_match( '/\n{2,}/', $item ) ) {
1286
				// Replace marker with the appropriate whitespace indentation
1287
				$item = $leading_space . str_repeat( ' ', strlen( $marker_space ) ) . $item;
1288
				$item = $this->runBlockGamut( $this->outdent( $item ) . "\n" );
1289
			} else {
1290
				// Recursion for sub-lists:
1291
				$item = $this->doLists( $this->outdent( $item ) );
1292
				$item = preg_replace( '/\n+$/', '', $item );
1293
				$item = $this->runSpanGamut( $item );
1294
			}
1295
1296
			return '<li>' . $item . "</li>\n";
1297
		}
1298
1299
		/**
1300
		 * @param $text
1301
		 *
1302
		 * @return mixed
1303
		 */
1304
		public function doCodeBlocks( $text ) {
0 ignored issues
show
The function name doCodeBlocks is in camel caps, but expected do_code_blocks instead as per the coding standard.
Loading history...
1305
1306
			//
1307
			// Process Markdown `<pre><code>` blocks.
1308
			//
1309
			$text = preg_replace_callback( '{
1310
				(?:\n\n|\A\n?)
1311
				(	            # $1 = the code block -- one or more lines, starting with a space/tab
1312
				  (?>
1313
					[ ]{' . $this->tab_width . '}  # Lines must start with a tab or a tab-width of spaces
1314
					.*\n+
1315
				  )+
1316
				)
1317
				((?=^[ ]{0,' . $this->tab_width . '}\S)|\Z)	# Lookahead for non-space at line-start, or end of doc
1318
			}xm', array( &$this, '_doCodeBlocks_callback' ), $text );
1319
1320
			return $text;
1321
		}
1322
1323
		/**
1324
		 * @param $matches
1325
		 *
1326
		 * @return string
1327
		 */
1328
		public function _doCodeBlocks_callback( $matches ) {
0 ignored issues
show
The function name _doCodeBlocks_callback is in camel caps, but expected _do_code_blocks_callback instead as per the coding standard.
Loading history...
1329
1330
			$codeblock = $matches[1];
1331
1332
			$codeblock = $this->outdent( $codeblock );
1333
			$codeblock = htmlspecialchars( $codeblock, ENT_NOQUOTES );
1334
1335
			// trim leading newlines and trailing newlines
1336
			$codeblock = preg_replace( '/\A\n+|\n+\z/', '', $codeblock );
1337
1338
			$codeblock = "<pre><code>$codeblock\n</code></pre>";
1339
1340
			return "\n\n" . $this->hashBlock( $codeblock ) . "\n\n";
1341
		}
1342
1343
		/**
1344
		 * @param $code
1345
		 *
1346
		 * @return string
1347
		 */
1348
		public function makeCodeSpan( $code ) {
0 ignored issues
show
The function name makeCodeSpan is in camel caps, but expected make_code_span instead as per the coding standard.
Loading history...
1349
1350
			//
1351
			// Create a code span markup for $code. Called from handleSpanToken.
1352
			//
1353
			$code = htmlspecialchars( trim( $code ), ENT_NOQUOTES );
1354
1355
			return $this->hashPart( "<code>$code</code>" );
1356
		}
1357
1358
		public $em_relist = array(
1359
			''  => '(?:(?<!\*)\*(?!\*)|(?<!_)_(?!_))(?=\S|$)(?![\.,:;]\s)',
1360
			'*' => '(?<=\S|^)(?<!\*)\*(?!\*)',
1361
			'_' => '(?<=\S|^)(?<!_)_(?!_)',
1362
		);
1363
		public $strong_relist = array(
1364
			''   => '(?:(?<!\*)\*\*(?!\*)|(?<!_)__(?!_))(?=\S|$)(?![\.,:;]\s)',
1365
			'**' => '(?<=\S|^)(?<!\*)\*\*(?!\*)',
1366
			'__' => '(?<=\S|^)(?<!_)__(?!_)',
1367
		);
1368
		public $em_strong_relist = array(
1369
			''    => '(?:(?<!\*)\*\*\*(?!\*)|(?<!_)___(?!_))(?=\S|$)(?![\.,:;]\s)',
1370
			'***' => '(?<=\S|^)(?<!\*)\*\*\*(?!\*)',
1371
			'___' => '(?<=\S|^)(?<!_)___(?!_)',
1372
		);
1373
		public $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...
1374
1375
		public function prepareItalicsAndBold() {
0 ignored issues
show
The function name prepareItalicsAndBold is in camel caps, but expected prepare_italics_and_bold instead as per the coding standard.
Loading history...
1376
1377
			//
1378
			// Prepare regular expressions for searching emphasis tokens in any
1379
			// context.
1380
			//
1381
			foreach ( $this->em_relist as $em => $em_re ) {
1382
				foreach ( $this->strong_relist as $strong => $strong_re ) {
1383
					// Construct list of allowed token expressions.
1384
					$token_relist = array();
1385
					if ( isset( $this->em_strong_relist["$em$strong"] ) ) {
1386
						$token_relist[] = $this->em_strong_relist["$em$strong"];
1387
					}
1388
					$token_relist[] = $em_re;
1389
					$token_relist[] = $strong_re;
1390
1391
					// Construct master expression from list.
1392
					$token_re                                      = '{(' . implode( '|', $token_relist ) . ')}';
1393
					$this->em_strong_prepared_relist["$em$strong"] = $token_re;
1394
				}
1395
			}
1396
		}
1397
1398
		/**
1399
		 * @param $text
1400
		 *
1401
		 * @return string
1402
		 */
1403
		public function doItalicsAndBold( $text ) {
0 ignored issues
show
The function name doItalicsAndBold is in camel caps, but expected do_italics_and_bold instead as per the coding standard.
Loading history...
1404
1405
			$token_stack  = array( '' );
1406
			$text_stack   = array( '' );
1407
			$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...
1408
			$strong       = '';
1409
			$tree_char_em = false;
1410
1411
			while ( 1 ) {
1412
				//
1413
				// Get prepared regular expression for seraching emphasis tokens
1414
				// in current context.
1415
				//
1416
				$token_re = $this->em_strong_prepared_relist["$em$strong"];
1417
1418
				//
1419
				// Each loop iteration search for the next emphasis token.
1420
				// Each token is then passed to handleSpanToken.
1421
				//
1422
				$parts         = preg_split( $token_re, $text, 2, PREG_SPLIT_DELIM_CAPTURE );
1423
				$text_stack[0] .= $parts[0];
1424
				$token         =& $parts[1];
1425
				$text          =& $parts[2];
1426
1427
				if ( empty( $token ) ) {
1428
					// Reached end of text span: empty stack without emitting.
1429
					// any more emphasis.
1430
					while ( $token_stack[0] ) {
1431
						$text_stack[1] .= array_shift( $token_stack );
1432
						$text_stack[0] .= array_shift( $text_stack );
1433
					}
1434
					break;
1435
				}
1436
1437
				$token_len = strlen( $token );
1438
				if ( $tree_char_em ) {
1439
					// Reached closing marker while inside a three-char emphasis.
1440
					if ( $token_len == 3 ) {
0 ignored issues
show
Found "== 3". Use Yoda Condition checks, you must
Loading history...
1441
						// Three-char closing marker, close em and strong.
1442
						array_shift( $token_stack );
1443
						$span          = array_shift( $text_stack );
1444
						$span          = $this->runSpanGamut( $span );
1445
						$span          = "<strong><em>$span</em></strong>";
1446
						$text_stack[0] .= $this->hashPart( $span );
1447
						$em            = '';
1448
						$strong        = '';
1449
					} else {
1450
						// Other closing marker: close one em or strong and
1451
						// change current token state to match the other
1452
						$token_stack[0] = str_repeat( $token{0}, 3 - $token_len );
1453
						$tag            = $token_len == 2 ? 'strong' : 'em';
1454
						$span           = $text_stack[0];
1455
						$span           = $this->runSpanGamut( $span );
1456
						$span           = "<$tag>$span</$tag>";
1457
						$text_stack[0]  = $this->hashPart( $span );
1458
						$$tag           = '';
1459
						// $$tag stands for $em or $strong
0 ignored issues
show
Unused Code Comprehensibility introduced by
47% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
1460
					}//end if
1461
					$tree_char_em = false;
1462
				} elseif ( $token_len == 3 ) {
0 ignored issues
show
Found "== 3". Use Yoda Condition checks, you must
Loading history...
1463
					if ( $em ) {
1464
						// Reached closing marker for both em and strong.
1465
						// Closing strong marker:
1466
						for ( $i = 0; $i < 2; ++ $i ) {
1467
							$shifted_token = array_shift( $token_stack );
1468
							$tag           = strlen( $shifted_token ) == 2 ? 'strong' : 'em';
1469
							$span          = array_shift( $text_stack );
1470
							$span          = $this->runSpanGamut( $span );
1471
							$span          = "<$tag>$span</$tag>";
1472
							$text_stack[0] .= $this->hashPart( $span );
1473
							$$tag          = '';
1474
							// $$tag stands for $em or $strong
0 ignored issues
show
Unused Code Comprehensibility introduced by
47% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
1475
						}
1476
					} else {
1477
						// Reached opening three-char emphasis marker. Push on token
1478
						// stack; will be handled by the special condition above.
1479
						$em     = $token{0};
1480
						$strong = "$em$em";
1481
						array_unshift( $token_stack, $token );
1482
						array_unshift( $text_stack, '' );
1483
						$tree_char_em = true;
1484
					}//end if
1485
				} elseif ( $token_len == 2 ) {
0 ignored issues
show
Found "== 2". Use Yoda Condition checks, you must
Loading history...
1486
					if ( $strong ) {
1487
						// Unwind any dangling emphasis marker:
1488
						if ( strlen( $token_stack[0] ) == 1 ) {
0 ignored issues
show
Found "== 1". Use Yoda Condition checks, you must
Loading history...
1489
							$text_stack[1] .= array_shift( $token_stack );
1490
							$text_stack[0] .= array_shift( $text_stack );
1491
						}
1492
						// Closing strong marker:
1493
						array_shift( $token_stack );
1494
						$span          = array_shift( $text_stack );
1495
						$span          = $this->runSpanGamut( $span );
1496
						$span          = "<strong>$span</strong>";
1497
						$text_stack[0] .= $this->hashPart( $span );
1498
						$strong        = '';
1499
					} else {
1500
						array_unshift( $token_stack, $token );
1501
						array_unshift( $text_stack, '' );
1502
						$strong = $token;
1503
					}
1504
				} else {
1505
					// Here $token_len == 1
1506
					if ( $em ) {
1507
						if ( strlen( $token_stack[0] ) == 1 ) {
0 ignored issues
show
Found "== 1". Use Yoda Condition checks, you must
Loading history...
1508
							// Closing emphasis marker:
1509
							array_shift( $token_stack );
1510
							$span          = array_shift( $text_stack );
1511
							$span          = $this->runSpanGamut( $span );
1512
							$span          = "<em>$span</em>";
1513
							$text_stack[0] .= $this->hashPart( $span );
1514
							$em            = '';
1515
						} else {
1516
							$text_stack[0] .= $token;
1517
						}
1518
					} else {
1519
						array_unshift( $token_stack, $token );
1520
						array_unshift( $text_stack, '' );
1521
						$em = $token;
1522
					}
1523
				}//end if
1524
			}//end while
1525
1526
			return $text_stack[0];
1527
		}
1528
1529
		/**
1530
		 * @param $text
1531
		 *
1532
		 * @return mixed
1533
		 */
1534
		public function doBlockQuotes( $text ) {
0 ignored issues
show
The function name doBlockQuotes is in camel caps, but expected do_block_quotes instead as per the coding standard.
Loading history...
1535
1536
			$text = preg_replace_callback( '/
1537
			  (								# Wrap whole match in $1
1538
				(?>
1539
				  ^[ ]*>[ ]?			# ">" at the start of a line
1540
					.+\n					# rest of the first line
1541
				  (.+\n)*					# subsequent consecutive lines
1542
				  \n*						# blanks
1543
				)+
1544
			  )
1545
			/xm', array( &$this, '_doBlockQuotes_callback' ), $text );
1546
1547
			return $text;
1548
		}
1549
1550
		/**
1551
		 * @param $matches
1552
		 *
1553
		 * @return string
1554
		 */
1555
		public function _doBlockQuotes_callback( $matches ) {
0 ignored issues
show
The function name _doBlockQuotes_callback is in camel caps, but expected _do_block_quotes_callback instead as per the coding standard.
Loading history...
1556
1557
			$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...
1558
			// trim one level of quoting - trim whitespace-only lines
1559
			$bq = preg_replace( '/^[ ]*>[ ]?|^[ ]+$/m', '', $bq );
1560
			$bq = $this->runBlockGamut( $bq );
1561
			// recurse
1562
			$bq = preg_replace( '/^/m', '  ', $bq );
1563
			// These leading spaces cause problem with <pre> content,
1564
			// so we need to fix that:
1565
			$bq = preg_replace_callback( '{(\s*<pre>.+?</pre>)}sx', array( &$this, '_doBlockQuotes_callback2' ), $bq );
1566
1567
			return "\n" . $this->hashBlock( "<blockquote>\n$bq\n</blockquote>" ) . "\n\n";
1568
		}
1569
1570
		/**
1571
		 * @param $matches
1572
		 *
1573
		 * @return mixed
1574
		 */
1575
		public function _doBlockQuotes_callback2( $matches ) {
0 ignored issues
show
The function name _doBlockQuotes_callback2 is in camel caps, but expected _do_block_quotes_callback2 instead as per the coding standard.
Loading history...
1576
1577
			$pre = $matches[1];
1578
			$pre = preg_replace( '/^  /m', '', $pre );
1579
1580
			return $pre;
1581
		}
1582
1583
		/**
1584
		 * @param $text
1585
		 *
1586
		 * @return string
1587
		 */
1588
		public function formParagraphs( $text ) {
0 ignored issues
show
The function name formParagraphs is in camel caps, but expected form_paragraphs instead as per the coding standard.
Loading history...
1589
1590
			//
1591
			// Params:
1592
			// $text - string to process with html <p> tags
1593
			//
1594
			// Strip leading and trailing lines:
1595
			$text = preg_replace( '/\A\n+|\n+\z/', '', $text );
1596
1597
			$grafs = preg_split( '/\n{2,}/', $text, - 1, PREG_SPLIT_NO_EMPTY );
1598
1599
			//
1600
			// Wrap <p> tags and unhashify HTML blocks
1601
			//
1602
			foreach ( $grafs as $key => $value ) {
1603
				if ( ! preg_match( '/^B\x1A[0-9]+B$/', $value ) ) {
1604
					// Is a paragraph.
1605
					$value         = $this->runSpanGamut( $value );
1606
					$value         = preg_replace( '/^([ ]*)/', '<p>', $value );
1607
					$value         .= '</p>';
1608
					$grafs[ $key ] = $this->unhash( $value );
1609
				} else {
1610
					// Is a block.
1611
					// Modify elements of @grafs in-place...
1612
					$graf  = $value;
1613
					$block = $this->html_hashes[ $graf ];
1614
					$graf  = $block;
1615
					// if (preg_match('{
1616
					// \A
1617
					// (                           # $1 = <div> tag
1618
					// <div  \s+
1619
					// [^>]*
0 ignored issues
show
Unused Code Comprehensibility introduced by
50% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
1620
					// \b
1621
					// markdown\s*=\s*  ([\'"])  #   $2 = attr quote char
1622
					// 1
1623
					// \2
1624
					// [^>]*
0 ignored issues
show
Unused Code Comprehensibility introduced by
50% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
1625
					// >
1626
					// )
1627
					// (                           # $3 = contents
1628
					// .*
1629
					// )
1630
					// (</div>)                    # $4 = closing tag
1631
					// \z
1632
					// }xs', $block, $matches))
1633
					// {
1634
					// list(, $div_open, , $div_content, $div_close) = $matches;
0 ignored issues
show
Unused Code Comprehensibility introduced by
60% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
1635
					//
1636
					// # We can't call Markdown(), because that resets the hash;
1637
					// # that initialization code should be pulled into its own sub, though.
1638
					// $div_content = $this->hashHTMLBlocks($div_content);
0 ignored issues
show
Unused Code Comprehensibility introduced by
59% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
1639
					//
1640
					// # Run document gamut methods on the content.
1641
					// foreach ($this->document_gamut as $method => $priority) {
0 ignored issues
show
Unused Code Comprehensibility introduced by
56% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
1642
					// $div_content = $this->$method($div_content);
0 ignored issues
show
Unused Code Comprehensibility introduced by
67% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
1643
					// }
1644
					//
1645
					// $div_open = preg_replace(
1646
					// '{\smarkdown\s*=\s*([\'"]).+?\1}', '', $div_open);
1647
					//
1648
					// $graf = $div_open . "\n" . $div_content . "\n" . $div_close;
1649
					// }
1650
					$grafs[ $key ] = $graf;
1651
				}//end if
1652
			}//end foreach
1653
1654
			return implode( "\n\n", $grafs );
1655
		}
1656
1657
		/**
1658
		 * @param $text
1659
		 *
1660
		 * @return mixed
1661
		 */
1662
		public function encodeAttribute( $text ) {
0 ignored issues
show
The function name encodeAttribute is in camel caps, but expected encode_attribute instead as per the coding standard.
Loading history...
1663
1664
			//
1665
			// Encode text for a double-quoted HTML attribute. This function
1666
			// is *not* suitable for attributes enclosed in single quotes.
1667
			//
1668
			$text = $this->encodeAmpsAndAngles( $text );
1669
			$text = str_replace( '"', '&quot;', $text );
1670
1671
			return $text;
1672
		}
1673
1674
		/**
1675
		 * @param $text
1676
		 *
1677
		 * @return mixed
1678
		 */
1679
		public function encodeAmpsAndAngles( $text ) {
0 ignored issues
show
The function name encodeAmpsAndAngles is in camel caps, but expected encode_amps_and_angles instead as per the coding standard.
Loading history...
1680
1681
			//
1682
			// Smart processing for ampersands and angle brackets that need to
1683
			// be encoded. Valid character entities are left alone unless the
1684
			// no-entities mode is set.
1685
			//
1686
			if ( $this->no_entities ) {
1687
				$text = str_replace( '&', '&amp;', $text );
1688
			} else {
1689
				// Ampersand-encoding based entirely on Nat Irons's Amputator
1690
				// MT plugin: <http://bumppo.net/projects/amputator/>
1691
				$text = preg_replace( '/&(?!#?[xX]?(?:[0-9a-fA-F]+|\w+);)/', '&amp;', $text );
1692
			}
1693
			// Encode remaining <'s
1694
			$text = str_replace( '<', '&lt;', $text );
1695
1696
			return $text;
1697
		}
1698
1699
		/**
1700
		 * @param $text
1701
		 *
1702
		 * @return mixed
1703
		 */
1704
		public function doAutoLinks( $text ) {
0 ignored issues
show
The function name doAutoLinks is in camel caps, but expected do_auto_links instead as per the coding standard.
Loading history...
1705
1706
			$text = preg_replace_callback( '{<((https?|ftp|dict):[^\'">\s]+)>}i', array(
1707
				&$this,
1708
				'_doAutoLinks_url_callback',
1709
			), $text );
1710
1711
			// Email addresses: <[email protected]>
1712
			$text = preg_replace_callback( '{
1713
			<
1714
			(?:mailto:)?
1715
			(
1716
				(?:
1717
					[-!#$%&\'*+/=?^_`.{|}~\w\x80-\xFF]+
1718
				|
1719
					".*?"
1720
				)
1721
				\@
1722
				(?:
1723
					[-a-z0-9\x80-\xFF]+(\.[-a-z0-9\x80-\xFF]+)*\.[a-z]+
1724
				|
1725
					\[[\d.a-fA-F:]+\]	# IPv4 & IPv6
1726
				)
1727
			)
1728
			>
1729
			}xi', array( &$this, '_doAutoLinks_email_callback' ), $text );
1730
			$text = preg_replace_callback( '{<(tel:([^\'">\s]+))>}i', array(
1731
				&$this,
1732
				'_doAutoLinks_tel_callback',
1733
			), $text );
1734
1735
			return $text;
1736
		}
1737
1738
		/**
1739
		 * @param $matches
1740
		 *
1741
		 * @return string
1742
		 */
1743
		public function _doAutoLinks_tel_callback( $matches ) {
0 ignored issues
show
The function name _doAutoLinks_tel_callback is in camel caps, but expected _do_auto_links_tel_callback instead as per the coding standard.
Loading history...
1744
1745
			$url  = $this->encodeAttribute( $matches[1] );
1746
			$tel  = $this->encodeAttribute( $matches[2] );
1747
			$link = "<a href=\"$url\">$tel</a>";
1748
1749
			return $this->hashPart( $link );
1750
		}
1751
1752
		/**
1753
		 * @param $matches
1754
		 *
1755
		 * @return string
1756
		 */
1757
		public function _doAutoLinks_url_callback( $matches ) {
0 ignored issues
show
The function name _doAutoLinks_url_callback is in camel caps, but expected _do_auto_links_url_callback instead as per the coding standard.
Loading history...
1758
1759
			$url  = $this->encodeAttribute( $matches[1] );
1760
			$link = "<a href=\"$url\">$url</a>";
1761
1762
			return $this->hashPart( $link );
1763
		}
1764
1765
		/**
1766
		 * @param $matches
1767
		 *
1768
		 * @return string
1769
		 */
1770
		public function _doAutoLinks_email_callback( $matches ) {
0 ignored issues
show
The function name _doAutoLinks_email_callback is in camel caps, but expected _do_auto_links_email_callback instead as per the coding standard.
Loading history...
1771
1772
			$address = $matches[1];
1773
			$link    = $this->encodeEmailAddress( $address );
1774
1775
			return $this->hashPart( $link );
1776
		}
1777
1778
		/**
1779
		 * @param $addr
1780
		 *
1781
		 * @return string
1782
		 */
1783
		public function encodeEmailAddress( $addr ) {
0 ignored issues
show
The function name encodeEmailAddress is in camel caps, but expected encode_email_address instead as per the coding standard.
Loading history...
1784
1785
			//
1786
			// Input: an email address, e.g. "[email protected]"
1787
			//
1788
			// Output: the email address as a mailto link, with each character
1789
			// of the address encoded as either a decimal or hex entity, in
1790
			// the hopes of foiling most address harvesting spam bots. E.g.:
1791
			//
1792
			// <p><a href="&#109;&#x61;&#105;&#x6c;&#116;&#x6f;&#58;&#x66;o&#111;
1793
			// &#x40;&#101;&#x78;&#97;&#x6d;&#112;&#x6c;&#101;&#46;&#x63;&#111;
1794
			// &#x6d;">&#x66;o&#111;&#x40;&#101;&#x78;&#97;&#x6d;&#112;&#x6c;
1795
			// &#101;&#46;&#x63;&#111;&#x6d;</a></p>
1796
			//
1797
			// Based by a filter by Matthew Wickline, posted to BBEdit-Talk.
1798
			// With some optimizations by Milian Wolff.
1799
			//
1800
			$addr  = 'mailto:' . $addr;
1801
			$chars = preg_split( '/(?<!^)(?!$)/', $addr );
1802
			$seed  = (int) abs( crc32( $addr ) / strlen( $addr ) );
1803
			// Deterministic seed.
1804
			foreach ( $chars as $key => $char ) {
1805
				$ord = ord( $char );
1806
				// Ignore non-ascii chars.
1807
				if ( $ord < 128 ) {
1808
					$r = ( $seed * ( 1 + $key ) ) % 100;
1809
					// Pseudo-random function.
1810
					// roughly 10% raw, 45% hex, 45% dec
1811
					// '@' *must* be encoded. I insist.
1812
					if ( $r > 90 && $char != '@' ) { /* do nothing */
0 ignored issues
show
This if statement is empty and can be removed.

This check looks for the bodies of if statements that have no statements or where all statements have been commented out. This may be the result of changes for debugging or the code may simply be obsolete.

These if bodies can be removed. If you have an empty if but statements in the else branch, consider inverting the condition.

if (rand(1, 6) > 3) {
//print "Check failed";
} else {
    print "Check succeeded";
}

could be turned into

if (rand(1, 6) <= 3) {
    print "Check succeeded";
}

This is much more concise to read.

Loading history...
1813
					} elseif ( $r < 45 ) {
1814
						$chars[ $key ] = '&#x' . dechex( $ord ) . ';';
1815
					} else {
1816
						$chars[ $key ] = '&#' . $ord . ';';
1817
					}
1818
				}
1819
			}
1820
1821
			$addr = implode( '', $chars );
1822
			$text = implode( '', array_slice( $chars, 7 ) );
1823
			// text without `mailto:`
1824
			$addr = "<a href=\"$addr\">$text</a>";
1825
1826
			return $addr;
1827
		}
1828
1829
		/**
1830
		 * @param $str
1831
		 *
1832
		 * @return string
1833
		 */
1834
		public function parseSpan( $str ) {
0 ignored issues
show
The function name parseSpan is in camel caps, but expected parse_span instead as per the coding standard.
Loading history...
1835
1836
			//
1837
			// Take the string $str and parse it into tokens, hashing embeded HTML,
1838
			// escaped characters and handling code spans.
1839
			//
1840
			$output = '';
1841
1842
			$span_re = '{
1843
				(
1844
					\\\\' . $this->escape_chars_re . '
1845
				|
1846
					(?<![`\\\\])
1847
					`+						# code span marker
1848
			' . ( $this->no_markup ? '' : '
1849
				|
1850
					<!--    .*?     -->		# comment
1851
				|
1852
					<\?.*?\?> | <%.*?%>		# processing instruction
1853
				|
1854
					<[!$]?[-a-zA-Z0-9:_]+	# regular tags
1855
					(?>
1856
						\s
1857
						(?>[^"\'>]+|"[^"]*"|\'[^\']*\')*
1858
					)?
1859
					>
1860
				|
1861
					<[-a-zA-Z0-9:_]+\s*/> # xml-style empty tag
1862
				|
1863
					</[-a-zA-Z0-9:_]+\s*> # closing tag
1864
			' ) . '
1865
				)
1866
				}xs';
1867
1868
			while ( 1 ) {
1869
				//
1870
				// Each loop iteration seach for either the next tag, the next
1871
				// openning code span marker, or the next escaped character.
1872
				// Each token is then passed to handleSpanToken.
1873
				//
1874
				$parts = preg_split( $span_re, $str, 2, PREG_SPLIT_DELIM_CAPTURE );
1875
1876
				// Create token from text preceding tag.
1877
				if ( $parts[0] != '' ) {
1878
					$output .= $parts[0];
1879
				}
1880
1881
				// Check if we reach the end.
1882
				if ( isset( $parts[1] ) ) {
1883
					$output .= $this->handleSpanToken( $parts[1], $parts[2] );
1884
					$str    = $parts[2];
1885
				} else {
1886
					break;
1887
				}
1888
			}//end while
1889
1890
			return $output;
1891
		}
1892
1893
		/**
1894
		 * @param $token
1895
		 * @param $str
1896
		 *
1897
		 * @return string
1898
		 */
1899
		public function handleSpanToken( $token, &$str ) {
0 ignored issues
show
The function name handleSpanToken is in camel caps, but expected handle_span_token instead as per the coding standard.
Loading history...
1900
1901
			//
1902
			// Handle $token provided by parseSpan by determining its nature and
1903
			// returning the corresponding value that should replace it.
1904
			//
1905
			switch ( $token{0} ) {
1906
				case '\\':
1907
					return $this->hashPart( '&#' . ord( $token{1} ) . ';' );
1908
				case '`':
1909
					// Search for end marker in remaining text.
1910
					if ( preg_match( '/^(.*?[^`])' . preg_quote( $token ) . '(?!`)(.*)$/sm', $str, $matches ) ) {
1911
						$str      = $matches[2];
1912
						$codespan = $this->makeCodeSpan( $matches[1] );
1913
1914
						return $this->hashPart( $codespan );
1915
					}
1916
1917
					return $token;
1918
				// return as text since no ending marker found.
1919
				default:
1920
					return $this->hashPart( $token );
1921
			}
1922
		}
1923
1924
		/**
1925
		 * @param $text
1926
		 *
1927
		 * @return mixed
1928
		 */
1929
		public function outdent( $text ) {
1930
1931
			//
1932
			// Remove one level of line-leading tabs or spaces
1933
			//
1934
			return preg_replace( '/^(\t|[ ]{1,' . $this->tab_width . '})/m', '', $text );
1935
		}
1936
1937
1938
		// String length function for detab. `_initDetab` will create a function to
1939
		// hanlde UTF-8 if the default function does not exist.
1940
		public $utf8_strlen = 'mb_strlen';
1941
1942
		/**
1943
		 * @param $text
1944
		 *
1945
		 * @return mixed
1946
		 */
1947
		public function detab( $text ) {
1948
1949
			//
1950
			// Replace tabs with the appropriate amount of space.
1951
			//
1952
			// For each line we separate the line in blocks delemited by
1953
			// tab characters. Then we reconstruct every line by adding the
1954
			// appropriate number of space between each blocks.
1955
			$text = preg_replace_callback( '/^.*\t.*$/m', array( &$this, '_detab_callback' ), $text );
1956
1957
			return $text;
1958
		}
1959
1960
		/**
1961
		 * @param $matches
1962
		 *
1963
		 * @return string
1964
		 */
1965
		public function _detab_callback( $matches ) {
1966
1967
			$line   = $matches[0];
1968
			$strlen = $this->utf8_strlen;
1969
			// strlen function for UTF-8.
1970
			// Split in blocks.
1971
			$blocks = explode( "\t", $line );
1972
			// Add each blocks to the line.
1973
			$line = $blocks[0];
1974
			unset( $blocks[0] );
1975
			// Do not add first block twice.
1976
			foreach ( $blocks as $block ) {
1977
				// Calculate amount of space, insert spaces, insert block.
1978
				$amount = $this->tab_width - $strlen( $line, 'UTF-8' ) % $this->tab_width;
1979
				$line   .= str_repeat( ' ', $amount ) . $block;
1980
			}
1981
1982
			return $line;
1983
		}
1984
1985
		public function _initDetab() {
0 ignored issues
show
The function name _initDetab is in camel caps, but expected _init_detab instead as per the coding standard.
Loading history...
1986
1987
			//
1988
			// Check for the availability of the function in the `utf8_strlen` property
1989
			// (initially `mb_strlen`). If the function is not available, create a
1990
			// function that will loosely count the number of UTF-8 characters with a
1991
			// regular expression.
1992
			//
1993
			if ( function_exists( $this->utf8_strlen ) ) {
1994
				return;
1995
			}
1996
			$this->utf8_strlen = create_function( '$text', 'return preg_match_all(
0 ignored issues
show
create_function is discouraged, please use Anonymous functions instead.
Loading history...
Security Best Practice introduced by
The use of create_function is highly discouraged, better use a closure.

create_function can pose a great security vulnerability as it is similar to eval, and could be used for arbitrary code execution. We highly recommend to use a closure instead.

// Instead of
$function = create_function('$a, $b', 'return $a + $b');

// Better use
$function = function($a, $b) { return $a + $b; }
Loading history...
1997
			"/[\\\\x00-\\\\xBF]|[\\\\xC0-\\\\xFF][\\\\x80-\\\\xBF]*/",
1998
			$text, $m);' );
1999
		}
2000
2001
		/**
2002
		 * @param $text
2003
		 *
2004
		 * @return mixed
2005
		 */
2006
		public function unhash( $text ) {
2007
2008
			//
2009
			// Swap back in all the tags hashed by _HashHTMLBlocks.
2010
			//
2011
			return preg_replace_callback( '/(.)\x1A[0-9]+\1/', array( &$this, '_unhash_callback' ), $text );
2012
		}
2013
2014
		/**
2015
		 * @param $matches
2016
		 *
2017
		 * @return mixed
2018
		 */
2019
		public function _unhash_callback( $matches ) {
2020
2021
			return $this->html_hashes[ $matches[0] ];
2022
		}
2023
2024
	}
2025
2026
	/*
2027
	PHP Markdown
2028
	============
2029
2030
	Description
2031
	-----------
2032
2033
	This is a PHP translation of the original Markdown formatter written in
2034
	Perl by John Gruber.
2035
2036
	Markdown is a text-to-HTML filter; it translates an easy-to-read /
2037
	easy-to-write structured text format into HTML. Markdown's text format
2038
	is mostly similar to that of plain text email, and supports features such
2039
	as headers, *emphasis*, code blocks, blockquotes, and links.
2040
2041
	Markdown's syntax is designed not as a generic markup language, but
2042
	specifically to serve as a front-end to (X)HTML. You can use span-level
2043
	HTML tags anywhere in a Markdown document, and you can use block level
2044
	HTML tags (like <div> and <table> as well).
2045
2046
	For more information about Markdown's syntax, see:
2047
2048
	<http://daringfireball.net/projects/markdown/>
2049
2050
2051
	Bugs
2052
	----
2053
2054
	To file bug reports please send email to:
2055
2056
	<[email protected]>
2057
2058
	Please include with your report: (1) the example input; (2) the output you
2059
	expected; (3) the output Markdown actually produced.
2060
2061
2062
	Version History
2063
	---------------
2064
2065
	See the readme file for detailed release notes for this version.
2066
2067
2068
	Copyright and License
2069
	---------------------
2070
2071
	PHP Markdown
2072
	Copyright (c) 2004-2013 Michel Fortin
2073
	<http://michelf.ca/>
2074
	All rights reserved.
2075
2076
	Based on Markdown
2077
	Copyright (c) 2003-2006 John Gruber
2078
	<http://daringfireball.net/>
2079
	All rights reserved.
2080
2081
	Redistribution and use in source and binary forms, with or without
2082
	modification, are permitted provided that the following conditions are
2083
	met:
2084
2085
	*	Redistributions of source code must retain the above copyright notice,
2086
		this list of conditions and the following disclaimer.
2087
2088
	*	Redistributions in binary form must reproduce the above copyright
2089
		notice, this list of conditions and the following disclaimer in the
2090
		documentation and/or other materials provided with the distribution.
2091
2092
	*	Neither the name "Markdown" nor the names of its contributors may
2093
		be used to endorse or promote products derived from this software
2094
		without specific prior written permission.
2095
2096
	This software is provided by the copyright holders and contributors "as
2097
	is" and any express or implied warranties, including, but not limited
2098
	to, the implied warranties of merchantability and fitness for a
2099
	particular purpose are disclaimed. In no event shall the copyright owner
2100
	or contributors be liable for any direct, indirect, incidental, special,
2101
	exemplary, or consequential damages (including, but not limited to,
2102
	procurement of substitute goods or services; loss of use, data, or
2103
	profits; or business interruption) however caused and on any theory of
2104
	liability, whether in contract, strict liability, or tort (including
2105
	negligence or otherwise) arising in any way out of the use of this
2106
	software, even if advised of the possibility of such damage.
2107
2108
	*/
2109
endif;
2110