Completed
Push — master ( 72613d...069c91 )
by Michael
02:16
created

magnific_popup/classes/class.parsedown.inc.php (13 issues)

Upgrade to new PHP Analysis Engine

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

1
<?php
2
3
#
4
#
5
# Parsedown
6
# http://parsedown.org
7
#
8
# (c) Emanuil Rusev
9
# http://erusev.com
10
#
11
# For the full license information, please view the LICENSE file that was
12
# distributed with this source code.
13
#
14
#
15
16
/**
17
 * Class Parsedown
18
 */
19
class Parsedown
20
{
21
    #
22
    # Multiton (http://en.wikipedia.org/wiki/Multiton_pattern)
23
    #
24
25
    /**
26
     * @param string $name
27
     * @return mixed|Parsedown
28
     */
29
    public static function instance($name = 'default')
30
    {
31
        if (isset(self::$instances[$name])) {
32
            return self::$instances[$name];
33
        }
34
35
        $instance = new Parsedown();
36
37
        self::$instances[$name] = $instance;
38
39
        return $instance;
40
    }
41
42
    private static $instances = array();
43
44
    #
45
    # Setters
46
    #
47
48
    private $break_marker = "  \n";
49
50
    /**
51
     * @param $breaks_enabled
52
     * @return $this
53
     */
54
    public function set_breaks_enabled($breaks_enabled)
55
    {
56
        $this->break_marker = $breaks_enabled ? "\n" : "  \n";
57
58
        return $this;
59
    }
60
61
    #
62
    # Fields
63
    #
64
65
    private $reference_map       = array();
66
    private $escape_sequence_map = array();
67
68
    #
69
    # Public Methods
70
    #
71
72
    /**
73
     * @param $text
74
     * @return mixed|string
75
     */
76
    public function parse($text)
77
    {
78
        # removes \r characters
79
        $text = str_replace("\r\n", "\n", $text);
80
        $text = str_replace("\r", "\n", $text);
81
82
        # replaces tabs with spaces
83
        $text = str_replace("\t", '    ', $text);
84
85
        # encodes escape sequences
86
87
        if (false !== strpos($text, '\\')) {
88
            $escape_sequences = array('\\\\', '\`', '\*', '\_', '\{', '\}', '\[', '\]', '\(', '\)', '\>', '\#', '\+', '\-', '\.', '\!');
89
90
            foreach ($escape_sequences as $index => $escape_sequence) {
91
                if (false !== strpos($text, $escape_sequence)) {
92
                    $code = "\x1A" . '\\' . $index . ';';
93
94
                    $text = str_replace($escape_sequence, $code, $text);
95
96
                    $this->escape_sequence_map[$code] = $escape_sequence;
97
                }
98
            }
99
        }
100
101
        # ~
102
103
        $text = trim($text, "\n");
104
105
        $lines = explode("\n", $text);
106
107
        $text = $this->parse_block_elements($lines);
108
109
        # decodes escape sequences
110
111
        foreach ($this->escape_sequence_map as $code => $escape_sequence) {
112
            $text = str_replace($code, $escape_sequence[1], $text);
113
        }
114
115
        # ~
116
117
        $text = rtrim($text, "\n");
118
119
        return $text;
120
    }
121
122
    #
123
    # Private Methods
124
    #
125
126
    /**
127
     * @param array  $lines
128
     * @param string $context
129
     * @return string
130
     */
131
    private function parse_block_elements(array $lines, $context = '')
132
    {
133
        $elements = array();
134
135
        $element = array(
136
            'type' => ''
137
        );
138
139
        foreach ($lines as $line) {
140
            # fenced elements
141
142
            switch ($element['type']) {
143
                case 'fenced block':
144
145
                    if (!isset($element['closed'])) {
146
                        if (preg_match('/^[ ]*' . $element['fence'][0] . '{3,}[ ]*$/', $line)) {
147
                            $element['closed'] = true;
148
                        } else {
149
                            '' !== $element['text'] and $element['text'] .= "\n";
0 ignored issues
show
Comprehensibility Best Practice introduced by
Using logical operators such as and instead of && is generally not recommended.

PHP has two types of connecting operators (logical operators, and boolean operators):

  Logical Operators Boolean Operator
AND - meaning and &&
OR - meaning or ||

The difference between these is the order in which they are executed. In most cases, you would want to use a boolean operator like &&, or ||.

Let’s take a look at a few examples:

// Logical operators have lower precedence:
$f = false or true;

// is executed like this:
($f = false) or true;


// Boolean operators have higher precedence:
$f = false || true;

// is executed like this:
$f = (false || true);

Logical Operators are used for Control-Flow

One case where you explicitly want to use logical operators is for control-flow such as this:

$x === 5
    or die('$x must be 5.');

// Instead of
if ($x !== 5) {
    die('$x must be 5.');
}

Since die introduces problems of its own, f.e. it makes our code hardly testable, and prevents any kind of more sophisticated error handling; you probably do not want to use this in real-world code. Unfortunately, logical operators cannot be combined with throw at this point:

// The following is currently a parse error.
$x === 5
    or throw new RuntimeException('$x must be 5.');

These limitations lead to logical operators rarely being of use in current PHP code.

Loading history...
150
151
                            $element['text'] .= $line;
152
                        }
153
154
                        continue 2;
155
                    }
156
157
                    break;
158
159
                case 'block-level markup':
160
161
                    if (!isset($element['closed'])) {
162
                        if (false !== strpos($line, $element['start'])) { # opening tag
163
                            $element['depth']++;
164
                        }
165
166
                        if (false !== strpos($line, $element['end'])) { # closing tag
167
                            $element['depth'] > 0 ? $element['depth']-- : $element['closed'] = true;
168
                        }
169
170
                        $element['text'] .= "\n" . $line;
171
172
                        continue 2;
173
                    }
174
175
                    break;
176
            }
177
178
            # *
179
180
            $deindented_line = ltrim($line);
181
182
            if ('' === $deindented_line) {
183
                $element['interrupted'] = true;
184
185
                continue;
186
            }
187
188
            # composite elements
189
190
            switch ($element['type']) {
191
                case 'blockquote':
192
193
                    if (!isset($element['interrupted'])) {
194
                        $line = preg_replace('/^[ ]*>[ ]?/', '', $line);
195
196
                        $element['lines'] [] = $line;
197
198
                        continue 2;
199
                    }
200
201
                    break;
202
203
                case 'li':
204
205
                    if (preg_match('/^([ ]{0,3})(\d+[.]|[*+-])[ ](.*)/', $line, $matches)) {
206
                        if ($element['indentation'] !== $matches[1]) {
207
                            $element['lines'] [] = $line;
208
                        } else {
209
                            unset($element['last']);
210
211
                            $elements [] = $element;
212
213
                            $element = array(
214
                                'type'        => 'li',
215
                                'indentation' => $matches[1],
216
                                'last'        => true,
217
                                'lines'       => array(
218
                                    preg_replace('/^[ ]{0,4}/', '', $matches[3])
219
                                )
220
                            );
221
                        }
222
223
                        continue 2;
224
                    }
225
226
                    if (isset($element['interrupted'])) {
227
                        if (' ' === $line[0]) {
228
                            $element['lines'] [] = '';
229
230
                            $line = preg_replace('/^[ ]{0,4}/', '', $line);
231
232
                            $element['lines'] [] = $line;
233
234
                            unset($element['interrupted']);
235
236
                            continue 2;
237
                        }
238
                    } else {
239
                        $line = preg_replace('/^[ ]{0,4}/', '', $line);
240
241
                        $element['lines'] [] = $line;
242
243
                        continue 2;
244
                    }
245
246
                    break;
247
            }
248
249
            # indentation sensitive types
250
251
            switch ($line[0]) {
252
                case ' ':
253
254
                    # code block
255
256
                    if (isset($line[3]) and ' ' === $line[3] and ' ' === $line[2] and ' ' === $line[1]) {
0 ignored issues
show
Comprehensibility Best Practice introduced by
Using logical operators such as and instead of && is generally not recommended.

PHP has two types of connecting operators (logical operators, and boolean operators):

  Logical Operators Boolean Operator
AND - meaning and &&
OR - meaning or ||

The difference between these is the order in which they are executed. In most cases, you would want to use a boolean operator like &&, or ||.

Let’s take a look at a few examples:

// Logical operators have lower precedence:
$f = false or true;

// is executed like this:
($f = false) or true;


// Boolean operators have higher precedence:
$f = false || true;

// is executed like this:
$f = (false || true);

Logical Operators are used for Control-Flow

One case where you explicitly want to use logical operators is for control-flow such as this:

$x === 5
    or die('$x must be 5.');

// Instead of
if ($x !== 5) {
    die('$x must be 5.');
}

Since die introduces problems of its own, f.e. it makes our code hardly testable, and prevents any kind of more sophisticated error handling; you probably do not want to use this in real-world code. Unfortunately, logical operators cannot be combined with throw at this point:

// The following is currently a parse error.
$x === 5
    or throw new RuntimeException('$x must be 5.');

These limitations lead to logical operators rarely being of use in current PHP code.

Loading history...
257
                        $code_line = substr($line, 4);
258
259
                        if ('code block' === $element['type']) {
260
                            if (isset($element['interrupted'])) {
261
                                $element['text'] .= "\n";
262
263
                                unset($element['interrupted']);
264
                            }
265
266
                            $element['text'] .= "\n" . $code_line;
267
                        } else {
268
                            $elements [] = $element;
269
270
                            $element = array(
271
                                'type' => 'code block',
272
                                'text' => $code_line
273
                            );
274
                        }
275
276
                        continue 2;
277
                    }
278
279
                    break;
280
281
                case '#':
282
283
                    # atx heading (#)
284
285
                    if (isset($line[1])) {
286
                        $elements [] = $element;
287
288
                        $level = 1;
289
290
                        while (isset($line[$level]) and '#' === $line[$level]) {
0 ignored issues
show
Comprehensibility Best Practice introduced by
Using logical operators such as and instead of && is generally not recommended.

PHP has two types of connecting operators (logical operators, and boolean operators):

  Logical Operators Boolean Operator
AND - meaning and &&
OR - meaning or ||

The difference between these is the order in which they are executed. In most cases, you would want to use a boolean operator like &&, or ||.

Let’s take a look at a few examples:

// Logical operators have lower precedence:
$f = false or true;

// is executed like this:
($f = false) or true;


// Boolean operators have higher precedence:
$f = false || true;

// is executed like this:
$f = (false || true);

Logical Operators are used for Control-Flow

One case where you explicitly want to use logical operators is for control-flow such as this:

$x === 5
    or die('$x must be 5.');

// Instead of
if ($x !== 5) {
    die('$x must be 5.');
}

Since die introduces problems of its own, f.e. it makes our code hardly testable, and prevents any kind of more sophisticated error handling; you probably do not want to use this in real-world code. Unfortunately, logical operators cannot be combined with throw at this point:

// The following is currently a parse error.
$x === 5
    or throw new RuntimeException('$x must be 5.');

These limitations lead to logical operators rarely being of use in current PHP code.

Loading history...
291
                            ++$level;
292
                        }
293
294
                        $element = array(
295
                            'type'  => 'heading',
296
                            'text'  => trim($line, '# '),
297
                            'level' => $level
298
                        );
299
300
                        continue 2;
301
                    }
302
303
                    break;
304
305
                case '-':
306
                case '=':
307
308
                    # setext heading
309
310
                    if ('paragraph' === $element['type'] and false === isset($element['interrupted'])) {
0 ignored issues
show
Comprehensibility Best Practice introduced by
Using logical operators such as and instead of && is generally not recommended.

PHP has two types of connecting operators (logical operators, and boolean operators):

  Logical Operators Boolean Operator
AND - meaning and &&
OR - meaning or ||

The difference between these is the order in which they are executed. In most cases, you would want to use a boolean operator like &&, or ||.

Let’s take a look at a few examples:

// Logical operators have lower precedence:
$f = false or true;

// is executed like this:
($f = false) or true;


// Boolean operators have higher precedence:
$f = false || true;

// is executed like this:
$f = (false || true);

Logical Operators are used for Control-Flow

One case where you explicitly want to use logical operators is for control-flow such as this:

$x === 5
    or die('$x must be 5.');

// Instead of
if ($x !== 5) {
    die('$x must be 5.');
}

Since die introduces problems of its own, f.e. it makes our code hardly testable, and prevents any kind of more sophisticated error handling; you probably do not want to use this in real-world code. Unfortunately, logical operators cannot be combined with throw at this point:

// The following is currently a parse error.
$x === 5
    or throw new RuntimeException('$x must be 5.');

These limitations lead to logical operators rarely being of use in current PHP code.

Loading history...
311
                        $chopped_line = rtrim($line);
312
313
                        $i = 1;
314
315
                        while (isset($chopped_line[$i])) {
316
                            if ($chopped_line[$i] !== $line[0]) {
317
                                break 2;
318
                            }
319
320
                            ++$i;
321
                        }
322
323
                        $element['type']  = 'heading';
324
                        $element['level'] = '-' === $line[0] ? 2 : 1;
325
326
                        continue 2;
327
                    }
328
329
                    break;
330
            }
331
332
            # indentation insensitive types
333
334
            switch ($deindented_line[0]) {
335
                case '<':
336
337
                    $position = strpos($deindented_line, '>');
338
339
                    if ($position > 1) { # tag
340
                        $name = substr($deindented_line, 1, $position - 1);
341
                        $name = rtrim($name);
342
343
                        if ('/' === substr($name, -1)) {
344
                            $self_closing = true;
345
346
                            $name = substr($name, 0, -1);
347
                        }
348
349
                        $position = strpos($name, ' ');
350
351
                        if ($position) {
352
                            $name = substr($name, 0, $position);
353
                        }
354
355
                        if (!ctype_alpha($name)) {
356
                            break;
357
                        }
358
359
                        if (in_array($name, $this->inline_tags)) {
360
                            break;
361
                        }
362
363
                        $elements [] = $element;
364
365
                        if (isset($self_closing)) {
366
                            $element = array(
367
                                'type' => 'self-closing tag',
368
                                'text' => $deindented_line
369
                            );
370
371
                            unset($self_closing);
372
373
                            continue 2;
374
                        }
375
376
                        $element = array(
377
                            'type'  => 'block-level markup',
378
                            'text'  => $deindented_line,
379
                            'start' => '<' . $name . '>',
380
                            'end'   => '</' . $name . '>',
381
                            'depth' => 0
382
                        );
383
384
                        if (strpos($deindented_line, $element['end'])) {
385
                            $element['closed'] = true;
386
                        }
387
388
                        continue 2;
389
                    }
390
391
                    break;
392
393
                case '>':
394
395
                    # quote
396
397
                    if (preg_match('/^>[ ]?(.*)/', $deindented_line, $matches)) {
398
                        $elements [] = $element;
399
400
                        $element = array(
401
                            'type'  => 'blockquote',
402
                            'lines' => array(
403
                                $matches[1]
404
                            )
405
                        );
406
407
                        continue 2;
408
                    }
409
410
                    break;
411
412
                case '[':
413
414
                    # reference
415
416
                    if (preg_match('/^\[(.+?)\]:[ ]*(.+?)(?:[ ]+[\'"](.+?)[\'"])?[ ]*$/', $deindented_line, $matches)) {
417
                        $label = strtolower($matches[1]);
418
419
                        $this->reference_map[$label] = array(
420
                            '»' => trim($matches[2], '<>')
421
                        );
422
423
                        if (isset($matches[3])) {
424
                            $this->reference_map[$label]['#'] = $matches[3];
425
                        }
426
427
                        continue 2;
428
                    }
429
430
                    break;
431
432
                case '`':
433
                case '~':
434
435
                    # fenced code block
436
437
                    if (preg_match('/^([`]{3,}|[~]{3,})[ ]*(\S+)?[ ]*$/', $deindented_line, $matches)) {
438
                        $elements [] = $element;
439
440
                        $element = array(
441
                            'type'  => 'fenced block',
442
                            'text'  => '',
443
                            'fence' => $matches[1]
444
                        );
445
446
                        isset($matches[2]) and $element['language'] = $matches[2];
447
448
                        continue 2;
449
                    }
450
451
                    break;
452
453
                case '*':
454
                case '+':
455
                case '-':
456
                case '_':
457
458
                    # hr
459
460
                    if (preg_match('/^([-*_])([ ]{0,2}\1){2,}[ ]*$/', $deindented_line)) {
461
                        $elements [] = $element;
462
463
                        $element = array(
464
                            'type' => 'hr'
465
                        );
466
467
                        continue 2;
468
                    }
469
470
                    # li
471
472
                    if (preg_match('/^([ ]*)[*+-][ ](.*)/', $line, $matches)) {
473
                        $elements [] = $element;
474
475
                        $element = array(
476
                            'type'        => 'li',
477
                            'ordered'     => false,
478
                            'indentation' => $matches[1],
479
                            'last'        => true,
480
                            'lines'       => array(
481
                                preg_replace('/^[ ]{0,4}/', '', $matches[2])
482
                            )
483
                        );
484
485
                        continue 2;
486
                    }
487
            }
488
489
            # li
490
491
            if ($deindented_line[0] <= '9' and $deindented_line[0] >= '0' and preg_match('/^([ ]*)\d+[.][ ](.*)/', $line, $matches)) {
492
                $elements [] = $element;
493
494
                $element = array(
495
                    'type'        => 'li',
496
                    'ordered'     => true,
497
                    'indentation' => $matches[1],
498
                    'last'        => true,
499
                    'lines'       => array(
500
                        preg_replace('/^[ ]{0,4}/', '', $matches[2])
501
                    )
502
                );
503
504
                continue;
505
            }
506
507
            # paragraph
508
509
            if ('paragraph' === $element['type']) {
510
                if (isset($element['interrupted'])) {
511
                    $elements [] = $element;
512
513
                    $element['text'] = $line;
514
515
                    unset($element['interrupted']);
516
                } else {
517
                    $element['text'] .= "\n" . $line;
518
                }
519
            } else {
520
                $elements [] = $element;
521
522
                $element = array(
523
                    'type' => 'paragraph',
524
                    'text' => $line
525
                );
526
            }
527
        }
528
529
        $elements [] = $element;
530
531
        unset($elements[0]);
532
533
        #
534
        # ~
535
        #
536
537
        $markup = '';
538
539
        foreach ($elements as $element) {
540
            switch ($element['type']) {
541
                case 'paragraph':
542
543
                    $text = $this->parse_span_elements($element['text']);
544
545
                    if ('li' === $context and '' === $markup) {
0 ignored issues
show
Comprehensibility Best Practice introduced by
Using logical operators such as and instead of && is generally not recommended.

PHP has two types of connecting operators (logical operators, and boolean operators):

  Logical Operators Boolean Operator
AND - meaning and &&
OR - meaning or ||

The difference between these is the order in which they are executed. In most cases, you would want to use a boolean operator like &&, or ||.

Let’s take a look at a few examples:

// Logical operators have lower precedence:
$f = false or true;

// is executed like this:
($f = false) or true;


// Boolean operators have higher precedence:
$f = false || true;

// is executed like this:
$f = (false || true);

Logical Operators are used for Control-Flow

One case where you explicitly want to use logical operators is for control-flow such as this:

$x === 5
    or die('$x must be 5.');

// Instead of
if ($x !== 5) {
    die('$x must be 5.');
}

Since die introduces problems of its own, f.e. it makes our code hardly testable, and prevents any kind of more sophisticated error handling; you probably do not want to use this in real-world code. Unfortunately, logical operators cannot be combined with throw at this point:

// The following is currently a parse error.
$x === 5
    or throw new RuntimeException('$x must be 5.');

These limitations lead to logical operators rarely being of use in current PHP code.

Loading history...
546
                        if (isset($element['interrupted'])) {
547
                            $markup .= "\n" . '<p>' . $text . '</p>' . "\n";
548
                        } else {
549
                            $markup .= $text;
550
                        }
551
                    } else {
552
                        $markup .= '<p>' . $text . '</p>' . "\n";
553
                    }
554
555
                    break;
556
557
                case 'blockquote':
558
559
                    $text = $this->parse_block_elements($element['lines']);
560
561
                    $markup .= '<blockquote>' . "\n" . $text . '</blockquote>' . "\n";
562
563
                    break;
564
565
                case 'code block':
566
567
                    $text = htmlspecialchars($element['text'], ENT_NOQUOTES, 'UTF-8');
568
569
                    false !== strpos($text, "\x1A\\") and $text = strtr($text, $this->escape_sequence_map);
0 ignored issues
show
Comprehensibility Best Practice introduced by
Using logical operators such as and instead of && is generally not recommended.

PHP has two types of connecting operators (logical operators, and boolean operators):

  Logical Operators Boolean Operator
AND - meaning and &&
OR - meaning or ||

The difference between these is the order in which they are executed. In most cases, you would want to use a boolean operator like &&, or ||.

Let’s take a look at a few examples:

// Logical operators have lower precedence:
$f = false or true;

// is executed like this:
($f = false) or true;


// Boolean operators have higher precedence:
$f = false || true;

// is executed like this:
$f = (false || true);

Logical Operators are used for Control-Flow

One case where you explicitly want to use logical operators is for control-flow such as this:

$x === 5
    or die('$x must be 5.');

// Instead of
if ($x !== 5) {
    die('$x must be 5.');
}

Since die introduces problems of its own, f.e. it makes our code hardly testable, and prevents any kind of more sophisticated error handling; you probably do not want to use this in real-world code. Unfortunately, logical operators cannot be combined with throw at this point:

// The following is currently a parse error.
$x === 5
    or throw new RuntimeException('$x must be 5.');

These limitations lead to logical operators rarely being of use in current PHP code.

Loading history...
570
571
                    $markup .= isset($element['language']) ? '<pre><code class="language-' . $element['language'] . '">' . $text . '</code></pre>' : '<pre><code>' . $text . '</code></pre>';
572
573
                    $markup .= "\n";
574
575
                    break;
576
577
                case 'fenced block':
578
579
                    $text = $element['text'];
580
581
                    false !== strpos($text, "\x1A\\") and $text = strtr($text, $this->escape_sequence_map);
0 ignored issues
show
Comprehensibility Best Practice introduced by
Using logical operators such as and instead of && is generally not recommended.

PHP has two types of connecting operators (logical operators, and boolean operators):

  Logical Operators Boolean Operator
AND - meaning and &&
OR - meaning or ||

The difference between these is the order in which they are executed. In most cases, you would want to use a boolean operator like &&, or ||.

Let’s take a look at a few examples:

// Logical operators have lower precedence:
$f = false or true;

// is executed like this:
($f = false) or true;


// Boolean operators have higher precedence:
$f = false || true;

// is executed like this:
$f = (false || true);

Logical Operators are used for Control-Flow

One case where you explicitly want to use logical operators is for control-flow such as this:

$x === 5
    or die('$x must be 5.');

// Instead of
if ($x !== 5) {
    die('$x must be 5.');
}

Since die introduces problems of its own, f.e. it makes our code hardly testable, and prevents any kind of more sophisticated error handling; you probably do not want to use this in real-world code. Unfortunately, logical operators cannot be combined with throw at this point:

// The following is currently a parse error.
$x === 5
    or throw new RuntimeException('$x must be 5.');

These limitations lead to logical operators rarely being of use in current PHP code.

Loading history...
582
583
                    $markup .= rex_highlight_string($text, true) . "\n";
584
585
                    $markup .= "\n";
586
587
                    break;
588
589
                case 'heading':
590
591
                    $text = $this->parse_span_elements($element['text']);
592
593
                    $markup .= '<h' . $element['level'] . '>' . $text . '</h' . $element['level'] . '>' . "\n";
594
595
                    break;
596
597
                case 'hr':
598
599
                    $markup .= '<hr >' . "\n";
600
601
                    break;
602
603
                case 'li':
604
605
                    if (isset($element['ordered'])) { # first
606
                        $list_type = $element['ordered'] ? 'ol' : 'ul';
607
608
                        $markup .= '<' . $list_type . '>' . "\n";
609
                    }
610
611
                    if (isset($element['interrupted']) and !isset($element['last'])) {
612
                        $element['lines'] [] = '';
613
                    }
614
615
                    $text = $this->parse_block_elements($element['lines'], 'li');
616
617
                    $markup .= '<li>' . $text . '</li>' . "\n";
618
619
                    isset($element['last']) and $markup .= '</' . $list_type . '>' . "\n";
620
621
                    break;
622
623
                case 'block-level markup':
624
625
                    $markup .= $element['text'] . "\n";
626
627
                    break;
628
629
                default:
630
631
                    $markup .= $element['text'] . "\n";
632
            }
633
        }
634
635
        return $markup;
636
    }
637
638
    /**
639
     * @param       $text
640
     * @param array $markers
641
     * @return string
642
     */
643
    private function parse_span_elements($text, $markers = array('![', '&', '*', '<', '[', '_', '`', 'http', '~~'))
644
    {
645
        if (false === isset($text[2]) or $markers === array()) {
0 ignored issues
show
Comprehensibility Best Practice introduced by
Using logical operators such as or instead of || is generally not recommended.

PHP has two types of connecting operators (logical operators, and boolean operators):

  Logical Operators Boolean Operator
AND - meaning and &&
OR - meaning or ||

The difference between these is the order in which they are executed. In most cases, you would want to use a boolean operator like &&, or ||.

Let’s take a look at a few examples:

// Logical operators have lower precedence:
$f = false or true;

// is executed like this:
($f = false) or true;


// Boolean operators have higher precedence:
$f = false || true;

// is executed like this:
$f = (false || true);

Logical Operators are used for Control-Flow

One case where you explicitly want to use logical operators is for control-flow such as this:

$x === 5
    or die('$x must be 5.');

// Instead of
if ($x !== 5) {
    die('$x must be 5.');
}

Since die introduces problems of its own, f.e. it makes our code hardly testable, and prevents any kind of more sophisticated error handling; you probably do not want to use this in real-world code. Unfortunately, logical operators cannot be combined with throw at this point:

// The following is currently a parse error.
$x === 5
    or throw new RuntimeException('$x must be 5.');

These limitations lead to logical operators rarely being of use in current PHP code.

Loading history...
646
            return $text;
647
        }
648
649
        # ~
650
651
        $markup = '';
652
653
        while ($markers) {
654
            $closest_marker          = null;
655
            $closest_marker_index    = 0;
656
            $closest_marker_position = null;
657
658
            foreach ($markers as $index => $marker) {
659
                $marker_position = strpos($text, $marker);
660
661
                if (false === $marker_position) {
662
                    unset($markers[$index]);
663
664
                    continue;
665
                }
666
667
                if (null === $closest_marker or $marker_position < $closest_marker_position) {
0 ignored issues
show
Comprehensibility Best Practice introduced by
Using logical operators such as or instead of || is generally not recommended.

PHP has two types of connecting operators (logical operators, and boolean operators):

  Logical Operators Boolean Operator
AND - meaning and &&
OR - meaning or ||

The difference between these is the order in which they are executed. In most cases, you would want to use a boolean operator like &&, or ||.

Let’s take a look at a few examples:

// Logical operators have lower precedence:
$f = false or true;

// is executed like this:
($f = false) or true;


// Boolean operators have higher precedence:
$f = false || true;

// is executed like this:
$f = (false || true);

Logical Operators are used for Control-Flow

One case where you explicitly want to use logical operators is for control-flow such as this:

$x === 5
    or die('$x must be 5.');

// Instead of
if ($x !== 5) {
    die('$x must be 5.');
}

Since die introduces problems of its own, f.e. it makes our code hardly testable, and prevents any kind of more sophisticated error handling; you probably do not want to use this in real-world code. Unfortunately, logical operators cannot be combined with throw at this point:

// The following is currently a parse error.
$x === 5
    or throw new RuntimeException('$x must be 5.');

These limitations lead to logical operators rarely being of use in current PHP code.

Loading history...
668
                    $closest_marker          = $marker;
669
                    $closest_marker_index    = $index;
670
                    $closest_marker_position = $marker_position;
671
                }
672
            }
673
674
            # ~
675
676
            if (null === $closest_marker or false === isset($text[$closest_marker_position + 2])) {
0 ignored issues
show
Comprehensibility Best Practice introduced by
Using logical operators such as or instead of || is generally not recommended.

PHP has two types of connecting operators (logical operators, and boolean operators):

  Logical Operators Boolean Operator
AND - meaning and &&
OR - meaning or ||

The difference between these is the order in which they are executed. In most cases, you would want to use a boolean operator like &&, or ||.

Let’s take a look at a few examples:

// Logical operators have lower precedence:
$f = false or true;

// is executed like this:
($f = false) or true;


// Boolean operators have higher precedence:
$f = false || true;

// is executed like this:
$f = (false || true);

Logical Operators are used for Control-Flow

One case where you explicitly want to use logical operators is for control-flow such as this:

$x === 5
    or die('$x must be 5.');

// Instead of
if ($x !== 5) {
    die('$x must be 5.');
}

Since die introduces problems of its own, f.e. it makes our code hardly testable, and prevents any kind of more sophisticated error handling; you probably do not want to use this in real-world code. Unfortunately, logical operators cannot be combined with throw at this point:

// The following is currently a parse error.
$x === 5
    or throw new RuntimeException('$x must be 5.');

These limitations lead to logical operators rarely being of use in current PHP code.

Loading history...
677
                $markup .= $text;
678
679
                break;
680
            } else {
681
                $markup .= substr($text, 0, $closest_marker_position);
682
            }
683
684
            $text = substr($text, $closest_marker_position);
685
686
            # ~
687
688
            unset($markers[$closest_marker_index]);
689
690
            # ~
691
692
            switch ($closest_marker) {
693
                case '![':
694
                case '[':
695
696
                    if (strpos($text, ']') and preg_match('/\[((?:[^][]|(?R))*)\]/', $text, $matches)) {
697
                        $element = array(
698
                            '!' => '!' === $text[0],
699
                            'a' => $matches[1]
700
                        );
701
702
                        $offset = strlen($matches[0]);
703
704
                        $element['!'] and ++$offset;
705
706
                        $remaining_text = substr($text, $offset);
707
708
                        if ('(' === $remaining_text[0] and preg_match('/\([ ]*(.*?)(?:[ ]+[\'"](.+?)[\'"])?[ ]*\)/', $remaining_text, $matches)) {
709
                            $element['»'] = $matches[1];
710
711
                            if (isset($matches[2])) {
712
                                $element['#'] = $matches[2];
713
                            }
714
715
                            $offset += strlen($matches[0]);
716
                        } elseif ($this->reference_map) {
717
                            $reference = $element['a'];
718
719
                            if (preg_match('/^\s*\[(.*?)\]/', $remaining_text, $matches)) {
720
                                $reference = $matches[1] ?: $element['a'];
721
722
                                $offset += strlen($matches[0]);
723
                            }
724
725
                            $reference = strtolower($reference);
726
727
                            if (isset($this->reference_map[$reference])) {
728
                                $element['»'] = $this->reference_map[$reference]['»'];
729
730
                                if (isset($this->reference_map[$reference]['#'])) {
731
                                    $element['#'] = $this->reference_map[$reference]['#'];
732
                                }
733
                            } else {
734
                                unset($element);
735
                            }
736
                        } else {
737
                            unset($element);
738
                        }
739
                    }
740
741
                    if (isset($element)) {
742
                        $element['»'] = str_replace('&', '&amp;', $element['»']);
743
                        $element['»'] = str_replace('<', '&lt;', $element['»']);
744
745
                        if ($element['!']) {
746
                            $markup .= '<img alt="' . $element['a'] . '" src="' . $element['»'] . '" >';
747
                        } else {
748
                            $element['a'] = $this->parse_span_elements($element['a'], $markers);
749
750
                            $markup .= isset($element['#']) ? '<a href="' . $element['»'] . '" title="' . $element['#'] . '">' . $element['a'] . '</a>' : '<a href="' . $element['»'] . '">' . $element['a'] . '</a>';
751
                        }
752
753
                        unset($element);
754
                    } else {
755
                        $markup .= $closest_marker;
756
757
                        $offset = '![' === $closest_marker ? 2 : 1;
758
                    }
759
760
                    break;
761
762
                case '&':
763
764
                    if (preg_match('/^&#?\w+;/', $text, $matches)) {
765
                        $markup .= $matches[0];
766
767
                        $offset = strlen($matches[0]);
768
                    } else {
769
                        $markup .= '&amp;';
770
771
                        $offset = 1;
772
                    }
773
774
                    break;
775
776
                case '*':
777
                case '_':
778
779
                    if ($text[1] === $closest_marker and preg_match($this->strong_regex[$closest_marker], $text, $matches)) {
780
                        $matches[1] = $this->parse_span_elements($matches[1], $markers);
781
782
                        $markup .= '<strong>' . $matches[1] . '</strong>';
783
                    } elseif (preg_match($this->em_regex[$closest_marker], $text, $matches)) {
784
                        $matches[1] = $this->parse_span_elements($matches[1], $markers);
785
786
                        $markup .= '<em>' . $matches[1] . '</em>';
787
                    } elseif ($text[1] === $closest_marker and preg_match($this->strong_em_regex[$closest_marker], $text, $matches)) {
788
                        $matches[2] = $this->parse_span_elements($matches[2], $markers);
789
790
                        $matches[1] and $matches[1] = $this->parse_span_elements($matches[1], $markers);
791
                        $matches[3] and $matches[3] = $this->parse_span_elements($matches[3], $markers);
792
793
                        $markup .= '<strong>' . $matches[1] . '<em>' . $matches[2] . '</em>' . $matches[3] . '</strong>';
794
                    } elseif (preg_match($this->em_strong_regex[$closest_marker], $text, $matches)) {
795
                        $matches[2] = $this->parse_span_elements($matches[2], $markers);
796
797
                        $matches[1] and $matches[1] = $this->parse_span_elements($matches[1], $markers);
798
                        $matches[3] and $matches[3] = $this->parse_span_elements($matches[3], $markers);
799
800
                        $markup .= '<em>' . $matches[1] . '<strong>' . $matches[2] . '</strong>' . $matches[3] . '</em>';
801
                    }
802
803
                    if (isset($matches) and $matches) {
804
                        $offset = strlen($matches[0]);
805
                    } else {
806
                        $markup .= $closest_marker;
807
808
                        $offset = 1;
809
                    }
810
811
                    break;
812
813
                case '<':
0 ignored issues
show
The case body in a switch statement must start on the line following the statement.

According to the PSR-2, the body of a case statement must start on the line immediately following the case statement.

switch ($expr) {
case "A":
    doSomething(); //right
    break;
case "B":

    doSomethingElse(); //wrong
    break;

}

To learn more about the PSR-2 coding standard, please refer to the PHP-Fig.

Loading history...
814
815
                    if (false !== strpos($text, '>')) {
816
                        if ('h' === $text[1] and preg_match('/^<(https?:[\/]{2}[^\s]+?)>/i', $text, $matches)) {
0 ignored issues
show
Comprehensibility Best Practice introduced by
Using logical operators such as and instead of && is generally not recommended.

PHP has two types of connecting operators (logical operators, and boolean operators):

  Logical Operators Boolean Operator
AND - meaning and &&
OR - meaning or ||

The difference between these is the order in which they are executed. In most cases, you would want to use a boolean operator like &&, or ||.

Let’s take a look at a few examples:

// Logical operators have lower precedence:
$f = false or true;

// is executed like this:
($f = false) or true;


// Boolean operators have higher precedence:
$f = false || true;

// is executed like this:
$f = (false || true);

Logical Operators are used for Control-Flow

One case where you explicitly want to use logical operators is for control-flow such as this:

$x === 5
    or die('$x must be 5.');

// Instead of
if ($x !== 5) {
    die('$x must be 5.');
}

Since die introduces problems of its own, f.e. it makes our code hardly testable, and prevents any kind of more sophisticated error handling; you probably do not want to use this in real-world code. Unfortunately, logical operators cannot be combined with throw at this point:

// The following is currently a parse error.
$x === 5
    or throw new RuntimeException('$x must be 5.');

These limitations lead to logical operators rarely being of use in current PHP code.

Loading history...
817
                            $element_url = $matches[1];
818
                            $element_url = str_replace('&', '&amp;', $element_url);
819
                            $element_url = str_replace('<', '&lt;', $element_url);
820
821
                            $markup .= '<a href="' . $element_url . '">' . $element_url . '</a>';
822
823
                            $offset = strlen($matches[0]);
824
                        } elseif (preg_match('/^<\/?\w.*?>/', $text, $matches)) {
825
                            $markup .= $matches[0];
826
827
                            $offset = strlen($matches[0]);
828
                        } else {
829
                            $markup .= '&lt;';
830
831
                            $offset = 1;
832
                        }
833
                    } else {
834
                        $markup .= '&lt;';
835
836
                        $offset = 1;
837
                    }
838
839
                    break;
840
841
                case '`':
842
843
                    if (preg_match('/^`(.+?)`/', $text, $matches)) {
844
                        $element_text = $matches[1];
845
                        $element_text = htmlspecialchars($element_text, ENT_NOQUOTES, 'UTF-8');
846
847
                        if ($this->escape_sequence_map and false !== strpos($element_text, "\x1A")) {
0 ignored issues
show
Comprehensibility Best Practice introduced by
Using logical operators such as and instead of && is generally not recommended.

PHP has two types of connecting operators (logical operators, and boolean operators):

  Logical Operators Boolean Operator
AND - meaning and &&
OR - meaning or ||

The difference between these is the order in which they are executed. In most cases, you would want to use a boolean operator like &&, or ||.

Let’s take a look at a few examples:

// Logical operators have lower precedence:
$f = false or true;

// is executed like this:
($f = false) or true;


// Boolean operators have higher precedence:
$f = false || true;

// is executed like this:
$f = (false || true);

Logical Operators are used for Control-Flow

One case where you explicitly want to use logical operators is for control-flow such as this:

$x === 5
    or die('$x must be 5.');

// Instead of
if ($x !== 5) {
    die('$x must be 5.');
}

Since die introduces problems of its own, f.e. it makes our code hardly testable, and prevents any kind of more sophisticated error handling; you probably do not want to use this in real-world code. Unfortunately, logical operators cannot be combined with throw at this point:

// The following is currently a parse error.
$x === 5
    or throw new RuntimeException('$x must be 5.');

These limitations lead to logical operators rarely being of use in current PHP code.

Loading history...
848
                            $element_text = strtr($element_text, $this->escape_sequence_map);
849
                        }
850
851
                        $markup .= '<code>' . $element_text . '</code>';
852
853
                        $offset = strlen($matches[0]);
854
                    } else {
855
                        $markup .= '`';
856
857
                        $offset = 1;
858
                    }
859
860
                    break;
861
862
                case 'http':
863
864
                    if (preg_match('/^https?:[\/]{2}[^\s]+\b/i', $text, $matches)) {
865
                        $element_url = $matches[0];
866
                        $element_url = str_replace('&', '&amp;', $element_url);
867
                        $element_url = str_replace('<', '&lt;', $element_url);
868
869
                        $markup .= '<a href="' . $element_url . '">' . $element_url . '</a>';
870
871
                        $offset = strlen($matches[0]);
872
                    } else {
873
                        $markup .= 'http';
874
875
                        $offset = 4;
876
                    }
877
878
                    break;
879
880
                case '~~':
881
882
                    if (preg_match('/^~~(?=\S)(.+?)(?<=\S)~~/', $text, $matches)) {
883
                        $matches[1] = $this->parse_span_elements($matches[1], $markers);
884
885
                        $markup .= '<del>' . $matches[1] . '</del>';
886
887
                        $offset = strlen($matches[0]);
888
                    } else {
889
                        $markup .= '~~';
890
891
                        $offset = 2;
892
                    }
893
894
                    break;
895
            }
896
897
            if (isset($offset)) {
898
                $text = substr($text, $offset);
899
            }
900
901
            $markers[$closest_marker_index] = $closest_marker;
902
        }
903
904
        $markup = str_replace($this->break_marker, '<br >' . "\n", $markup);
905
906
        return $markup;
907
    }
908
909
    #
910
    # Read-only
911
    #
912
913
    private $inline_tags = array(
914
        'a',
915
        'abbr',
916
        'acronym',
917
        'b',
918
        'bdo',
919
        'big',
920
        'br',
921
        'button',
922
        'cite',
923
        'code',
924
        'dfn',
925
        'em',
926
        'i',
927
        'img',
928
        'input',
929
        'kbd',
930
        'label',
931
        'map',
932
        'object',
933
        'q',
934
        'samp',
935
        'script',
936
        'select',
937
        'small',
938
        'span',
939
        'strong',
940
        'sub',
941
        'sup',
942
        'textarea',
943
        'tt',
944
        'var'
945
    );
946
947
    # ~
948
949
    private $strong_regex = array(
950
        '*' => '/^[*]{2}([^*]+?)[*]{2}(?![*])/s',
951
        '_' => '/^__([^_]+?)__(?!_)/s'
952
    );
953
954
    private $em_regex = array(
955
        '*' => '/^[*]([^*]+?)[*](?![*])/s',
956
        '_' => '/^_([^_]+?)[_](?![_])\b/s'
957
    );
958
959
    private $strong_em_regex = array(
960
        '*' => '/^[*]{2}(.*?)[*](.+?)[*](.*?)[*]{2}/s',
961
        '_' => '/^__(.*?)_(.+?)_(.*?)__/s'
962
    );
963
964
    private $em_strong_regex = array(
965
        '*' => '/^[*](.*?)[*]{2}(.+?)[*]{2}(.*?)[*]/s',
966
        '_' => '/^_(.*?)__(.+?)__(.*?)_/s'
967
    );
968
}
969