TShortcode::shortCodeBook()   A
last analyzed

Complexity

Conditions 2
Paths 2

Size

Total Lines 27

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 6

Importance

Changes 0
Metric Value
dl 0
loc 27
ccs 0
cts 0
cp 0
rs 9.488
c 0
b 0
f 0
cc 2
nc 2
nop 1
crap 6
1
<?php
2
3
namespace Mos\TextFilter;
4
5
/**
6
 * Shortcode to format when working with text.
7
 *
8
 */
9
trait TShortcode
10
{
11
    /**
12
     * Shortcode to quicker format text as HTML.
13
     *
14
     * @param string $text text to be converted.
15
     *
16
     * @return string the formatted text.
17
     */
18 1
    public function shortCode($text)
19
    {
20
        /* Needs PHP 7
21
        $patternsAndCallbacks = [
22
            "/\[(FIGURE)[\s+](.+)\]/" => function ($match) {
23
                return self::ShortCodeFigure($matches[2]);
24
            },
25
            "/(```([\w]*))\n([^`]*)```[\n]{1}/s" => function ($match) {
26
                return $this->syntaxHighlightGeSHi($matches[3], $matches[2]);
27
            },
28
        ];
29
30
        return preg_replace_callback_array($patternsAndCallbacks, $text);
31
        */
32
33
        $patterns = [
34 1
            "/\[(FIGURE)[\s+](.+)\]/",
35
            //'/\[(YOUTUBE) src=(.+) width=(.+) caption=(.+)\]/',
36 1
            "/\[(YOUTUBE)[\s+](.+)\]/",
37 1
            "/\[(CODEPEN)[\s+](.+)\]/",
38 1
            "/\[(ASCIINEMA)[\s+](.+)\]/",
39 1
            "/\[(BOOK)[\s+](.+)\]/",
40 1
            //"/(```)([\w]*)\n([.]*)```[\n]{1}/s",
41 1
            "/(```)([\w]*)\n(.*?)```\n/s",
42
            '/\[(INFO)\]/',
43 1
            '/\[(\/INFO)\]/',
44 1
            '/\[(WARNING)\]/',
45 1
            '/\[(\/WARNING)\]/',
46 1
        ];
47 1
48 1
        return preg_replace_callback(
49
            $patterns,
50
            function ($matches) {
51
                switch ($matches[1]) {
52
                    case "FIGURE":
53
                        return self::shortCodeFigure($matches[2]);
54
                    break;
0 ignored issues
show
Unused Code introduced by
break is not strictly necessary here and could be removed.

The break statement is not necessary if it is preceded for example by a return statement:

switch ($x) {
    case 1:
        return 'foo';
        break; // This break is not necessary and can be left off.
}

If you would like to keep this construct to be consistent with other case statements, you can safely mark this issue as a false-positive.

Loading history...
55
56
                    case "YOUTUBE":
57
                        return self::shortCodeYoutube($matches[2]);
58
                    break;
0 ignored issues
show
Unused Code introduced by
break is not strictly necessary here and could be removed.

The break statement is not necessary if it is preceded for example by a return statement:

switch ($x) {
    case 1:
        return 'foo';
        break; // This break is not necessary and can be left off.
}

If you would like to keep this construct to be consistent with other case statements, you can safely mark this issue as a false-positive.

Loading history...
59
60
                    case "CODEPEN":
61
                        return self::shortCodeCodepen($matches[2]);
62
                    break;
0 ignored issues
show
Unused Code introduced by
break is not strictly necessary here and could be removed.

The break statement is not necessary if it is preceded for example by a return statement:

switch ($x) {
    case 1:
        return 'foo';
        break; // This break is not necessary and can be left off.
}

If you would like to keep this construct to be consistent with other case statements, you can safely mark this issue as a false-positive.

Loading history...
63
64
                    case "ASCIINEMA":
65
                        return self::shortCodeAsciinema($matches[2]);
66
                    break;
0 ignored issues
show
Unused Code introduced by
break is not strictly necessary here and could be removed.

The break statement is not necessary if it is preceded for example by a return statement:

switch ($x) {
    case 1:
        return 'foo';
        break; // This break is not necessary and can be left off.
}

If you would like to keep this construct to be consistent with other case statements, you can safely mark this issue as a false-positive.

Loading history...
67
68
                    case "BOOK":
69
                        return self::shortCodeBook($matches[2]);
70
                    break;
0 ignored issues
show
Unused Code introduced by
break is not strictly necessary here and could be removed.

The break statement is not necessary if it is preceded for example by a return statement:

switch ($x) {
    case 1:
        return 'foo';
        break; // This break is not necessary and can be left off.
}

If you would like to keep this construct to be consistent with other case statements, you can safely mark this issue as a false-positive.

Loading history...
71
72
                    case "```":
73
                        //return $this->syntaxHighlightGeSHi($matches[3], $matches[2]);
74
                        return $this->syntaxHighlightJs($matches[3], $matches[2]);
0 ignored issues
show
Bug introduced by
It seems like syntaxHighlightJs() must be provided by classes using this trait. How about adding it as abstract method to this trait?

This check looks for methods that are used by a trait but not required by it.

To illustrate, let’s look at the following code example

trait Idable {
    public function equalIds(Idable $other) {
        return $this->getId() === $other->getId();
    }
}

The trait Idable provides a method equalsId that in turn relies on the method getId(). If this method does not exist on a class mixing in this trait, the method will fail.

Adding the getId() as an abstract method to the trait will make sure it is available.

Loading history...
75 1
                    break;
0 ignored issues
show
Unused Code introduced by
break is not strictly necessary here and could be removed.

The break statement is not necessary if it is preceded for example by a return statement:

switch ($x) {
    case 1:
        return 'foo';
        break; // This break is not necessary and can be left off.
}

If you would like to keep this construct to be consistent with other case statements, you can safely mark this issue as a false-positive.

Loading history...
76
77 1
                    case 'INFO':
78
                        return <<<EOD
79
<div class="info">
80
    <span class="icon fa-stack fa-lg">
81
        <i class="fa fa-circle fa-stack-2x"></i>
82
        <i class="fa fa-info fa-stack-1x fa-inverse" aria-hidden="true"></i>
83
    </span>
84
    <div markdown=1>
85
EOD;
86
                        break;
0 ignored issues
show
Unused Code introduced by
break is not strictly necessary here and could be removed.

The break statement is not necessary if it is preceded for example by a return statement:

switch ($x) {
    case 1:
        return 'foo';
        break; // This break is not necessary and can be left off.
}

If you would like to keep this construct to be consistent with other case statements, you can safely mark this issue as a false-positive.

Loading history...
87
88
                    case 'WARNING':
89
                        return <<<EOD
90 1
<div class="warning">
91
    <span class="icon fa-stack fa-lg">
92 1
        <i class="fa fa-circle fa-stack-2x"></i>
93
        <i class="fa fa-exclamation-triangle fa-stack-1x fa-inverse" aria-hidden="true"></i>
94 1
    </span>
95 1
    <div markdown=1>
96 1
EOD;
97 1
                        break;
0 ignored issues
show
Unused Code introduced by
break is not strictly necessary here and could be removed.

The break statement is not necessary if it is preceded for example by a return statement:

switch ($x) {
    case 1:
        return 'foo';
        break; // This break is not necessary and can be left off.
}

If you would like to keep this construct to be consistent with other case statements, you can safely mark this issue as a false-positive.

Loading history...
98
99
                    case '/INFO':
100 1
                    case '/WARNING':
101 1
                        return "</div></div>";
102 1
                        break;
0 ignored issues
show
Unused Code introduced by
break is not strictly necessary here and could be removed.

The break statement is not necessary if it is preceded for example by a return statement:

switch ($x) {
    case 1:
        return 'foo';
        break; // This break is not necessary and can be left off.
}

If you would like to keep this construct to be consistent with other case statements, you can safely mark this issue as a false-positive.

Loading history...
103
104 1
                    default:
105
                        return "{$matches[1]} is unknown shortcode.";
106 1
                }
107
            },
108
            $text
109
        );
110
    }
111
112
113
114
    /**
115
     * Init shortcode handling by preparing the option list to an array,
116
     * for those using arguments.
117
     *
118
     * @param string $options for the shortcode.
119
     *
120
     * @return array with all the options.
121
     */
122
    public static function shortCodeInit($options)
123
    {
124
        preg_match_all('/[a-zA-Z0-9]+="[^"]+"|\S+/', $options, $matches);
125
126
        $res = array();
127
        foreach ($matches[0] as $match) {
128
            $pos = strpos($match, '=');
129
            if ($pos === false) {
130
                $res[$match] = true;
131
            } else {
132
                $key = substr($match, 0, $pos);
133
                $val = trim(substr($match, $pos+1), '"');
134
                $res[$key] = $val;
135
            }
136
        }
137
138
        return $res;
139
    }
140
141
142
143
    /**
144
     * Shortcode for [YOUTUBE].
145
     *
146
     * Usage example: [YOUTUBE src=id-for-the-tube width=630 caption=""]
147
     *
148
     * @param string $options for the shortcode.
149
     *
150
     * @return array with all the options.
151
     */
152
    public static function shortCodeYoutube($options)
153
    {
154
        $options= array_merge(
155
            [
156
                "id"    => null,
157
                "class" => null,
158
                "src" => null,
159 1
                "list" => null,
160
                "time" => null,
161
                "width" => 600,
162 1
                "ratio" => 16/9,
163
                "caption" => null,
164 1
            ],
165 1
            self::ShortCodeInit($options)
166 1
        );
167 1
        extract($options, EXTR_SKIP);
168 1
169 1
        $id = $id ? " id=\"$id\"" : null;
170 1
        $class = $class ? " class=\"figure $class\"" : " class=\"figure\"";
171 1
        $list = $list ? "?listType=playlist&amp;list=$list" : null;
172 1
        $time = $time ? "#t=$time" : null;
173 1
        $height = ceil($width / $ratio);
174 1
175 1
        //$caption = t("Figure: !CAPTION", ["!CAPTION" => $caption]);
176
        if ($caption) {
177 1
            $caption = "<figcaption markdown=1>{$caption}</figcaption>";
178 1
        }
179 1
180
        // @codingStandardsIgnoreStart
181 1
        $html = <<<EOD
182 1
<figure{$id}{$class}>
183 1
<iframe width="$width" height="$height" src="https://www.youtube.com/embed/{$src}{$list}{$time}" frameborder="0" allowfullscreen></iframe>
184
{$caption}
185 1
</figure>
186 1
EOD;
187 1
        // @codingStandardsIgnoreEnd
188 1
189
        return $html;
190 1
    }
191 1
192 1
193 1
194 1
    /**
195 1
     * Shortcode for [CODEPEN].
196
     *
197
     * Usage example: [CODEPEN src=id-for-the-pen user="mosbth"
198 1
     * tab="js,result" caption="caption"]
199 1
     *
200 1
     * @param string $options for the shortcode.
201 1
     *
202 1
     * @return array with all the options.
203
     */
204 1
    public static function shortCodeCodepen($options)
205
    {
206
        $options= array_merge(
207
            [
208
                "id"    => null,
209
                "class" => null,
210
                "src" => null,
211
                "user" => null,
212
                "title" => null,
213
                "tab" => "result",
214
                "theme" => 0,
215
                "height" => 300,
216
                "width" => "100%",
217
                "caption" => null,
218
            ],
219
            self::ShortCodeInit($options)
220
        );
221
        extract($options, EXTR_SKIP);
222
223
        $id = $id ? " id=\"$id\"" : null;
224
        $class = $class ? " class=\"figure figure-codepen $class\"" : " class=\"figure figure-codepen\"";
225
226
        //$caption = t("Figure: !CAPTION", ["!CAPTION" => $caption]);
227
        if ($caption) {
228
            $caption = "<figcaption markdown=1>{$caption}</figcaption>";
229
        }
230
231
        // @codingStandardsIgnoreStart
232
        $html = <<<EOD
233
<figure{$id}{$class} width="$width">
234
<p data-height="$height" data-theme-id="$theme" data-slug-hash="$src" data-default-tab="$tab" data-user="$user" data-embed-version="2" data-pen-title="$title" class="codepen">See the <a href="https://codepen.io/$user/pen/$src/">Pen</a> on <a href="https://codepen.io">CodePen</a>.</p>
235
{$caption}
236
</figure>
237
<script async src="https://static.codepen.io/assets/embed/ei.js"></script>
238
EOD;
239
        // @codingStandardsIgnoreEnd
240
241
        return $html;
242
    }
243
244
245
246
    /**
247
     * Shortcode for <figure>.
248
     *
249
     * Usage example: [FIGURE src="img/home/me.jpg" caption="Me" alt="Bild på mig" nolink="nolink"]
250
     *
251
     * @param string $options for the shortcode.
252
     *
253
     * @return array with all the options.
254
     */
255
    public static function shortCodeFigure($options)
256
    {
257
        // Merge incoming options with default and expose as variables
258
        $options= array_merge(
259
            [
260
                "id"    => null,
261
                "class" => null,
262
                "src"   => null,
263
                "title" => null,
264
                "alt"   => null,
265
                "caption" => null,
266
                "href"  => null,
267
                "nolink" => false,
268
            ],
269
            self::ShortCodeInit($options)
270
        );
271
        extract($options, EXTR_SKIP);
272
273
        $id = $id ? " id=\"$id\"" : null;
274
        $class = $class ? " class=\"figure $class\"" : " class=\"figure\"";
275
        $title = $title ? " title=\"$title\"" : null;
276
277
        if (!$alt && $caption) {
278
            $alt = $caption;
279
        }
280
281
        if (!$href) {
282
            $pos = strpos($src, "?");
283
            $href = $pos ? substr($src, 0, $pos) : $src;
284
        }
285
286
        $start = null;
287
        $end = null;
288
        if (!$nolink) {
289
            $start = "<a href=\"{$href}\">";
290
            $end = "</a>";
291
        }
292
293
        if ($caption) {
294
            $caption = "<figcaption markdown=1>{$caption}</figcaption>";
295
        }
296
297
        $html = <<<EOD
298
<figure{$id}{$class}>
299
{$start}<img src="{$src}" alt="{$alt}"{$title}/>{$end}
300
{$caption}
301
</figure>
302
EOD;
303
304
        return $html;
305
    }
306
307
308
309
    /**
310
     * Shortcode for [asciinema].
311
     *
312
     * @param string $code the code to process.
0 ignored issues
show
Bug introduced by
There is no parameter named $code. Was it maybe removed?

This check looks for PHPDoc comments describing methods or function parameters that do not exist on the corresponding method or function.

Consider the following example. The parameter $italy is not defined by the method finale(...).

/**
 * @param array $germany
 * @param array $island
 * @param array $italy
 */
function finale($germany, $island) {
    return "2:1";
}

The most likely cause is that the parameter was removed, but the annotation was not.

Loading history...
313
     * @param string $options for the shortcode.
314
     * @return array with all the options.
315
     */
316
    public static function shortCodeAsciinema($options)
317
    {
318
        // Merge incoming options with default and expose as variables
319
        $options= array_merge(
320
            [
321
                "id" => null,
322
                "class" => null,
323
                "src" => null,
324
                "title" => null,
325
                "caption" => null,
326
            ],
327
            self::ShortCodeInit($options)
328
        );
329
        extract($options, EXTR_SKIP);
330
331
        $id = $id ? " id=\"$id\"" : null;
332
        $class = $class ? " class=\"figure asciinema $class\"" : " class=\"figure asciinema\"";
333
        $title = $title ? " title=\"$title\"" : null;
334
335
        $html = <<<EOD
336
<figure{$id}{$class}$title>
337
<script type="text/javascript" src="https://asciinema.org/a/{$src}.js" id="asciicast-{$src}" async></script>
338
<figcaption markdown=1>{$caption}</figcaption>
339
</figure>
340
EOD;
341
342
        return $html;
343
    }
344
345
346
347
    /**
348
     * Shortcode for [book].
349
     *
350
     * @param string $code the code to process.
0 ignored issues
show
Bug introduced by
There is no parameter named $code. Was it maybe removed?

This check looks for PHPDoc comments describing methods or function parameters that do not exist on the corresponding method or function.

Consider the following example. The parameter $italy is not defined by the method finale(...).

/**
 * @param array $germany
 * @param array $island
 * @param array $italy
 */
function finale($germany, $island) {
    return "2:1";
}

The most likely cause is that the parameter was removed, but the annotation was not.

Loading history...
351
     * @param string $options for the shortcode.
352
     * @return array with all the options.
353
     */
354
    public static function shortCodeBook($options)
355
    {
356
        // Merge incoming options with default and expose as variables
357
        $options= array_merge(
358
            [
359
                "isbn" => null,
360
            ],
361
            self::ShortCodeInit($options)
362
        );
363
        extract($options, EXTR_SKIP);
364
365
        $stores = [
366
            "BTH" => "http://bth.summon.serialssolutions.com/?#!/search?ho=t&amp;q={$isbn}",
367
            "Libris" => "http://libris.kb.se/hitlist?q={$isbn}",
368
            "Google Books" => "http://books.google.com/books?q={$isbn}",
369
            "Bokus" => "http://www.bokus.com/bok/{$isbn}",
370
            "Adlibris" => "http://www.adlibris.com/se/product.aspx?isbn={$isbn}",
371
            "Amazon" => "http://www.amazon.com/s/ref=nb_ss?url=field-keywords={$isbn}",
372
            "Barnes&Noble" => "http://search.barnesandnoble.com/booksearch/ISBNInquiry.asp?r=1&IF=N&EAN={$isbn}",
373
        ];
374
375
        $html = null;
376
        foreach ($stores as $key => $val) {
377
            $html .= "<a href='$val'>$key</a> &bull; ";
378
        }
379
        return substr($html, 0, -8);
380
    }
381
382
383
384
    /**
385
     * Shortcode for including a SVG-image inside a <figure>.
386
     *
387
     * @param string $code the code to process.
388
     * @param string $options for the shortcode.
389
     * @return array with all the options.
390
     */
391
/*    public static function ShortCodeSVGFigure($options) {
392
        // Merge incoming options with default and expose as variables
393
        $options= array_merge(
394
            [
395
                "id"    => null,
396
                "class" => null,
397
                "src"   => null,
398
                "title" => null,
399
                "alt"   => null,
400
                "caption" => null,
401
                "href"  => null,
402
                "nolink" => false,
403
                //'path' => null,
404
            ],
405
            self::ShortCodeInit($options)
406
        );
407
        extract($options, EXTR_SKIP);
408
409
        $id = $id ? " id=\"$id\"" : null;
410
        $class = $class ? " class=\"figure $class\"" : " class=\"figure\"";
411
        $title = $title ? " title=\"$title\"" : null;
412
413
        if (!$alt && $caption) {
414
            $alt = $caption;
415
        }
416
417
        if (!$href) {
418
            $pos = strpos($src, "?");
419
            $href = $pos ? substr($src, 0, $pos) : $src;
420
        }
421
422
        $start = null;
423
        $end = null;
424
        if (!$nolink) {
425
            $start = "<a href=\"{$href}\">";
426
            $end = "</a>";
427
        }
428
429
        // Import the file containing the svg-image
430
        /*
431
        $svg = null;
432
433
        if($path[0] != '/') {
434
        $path = self::$dir . '/' . $path;
435
        }
436
437
        if(is_file($path)) {
438
        $svg = file_get_contents($path);
439
        }
440
        else {
441
        $svg = "No such file: $path";
442
        }
443
        $html = <<<EOD
444
        <figure{$id}{$class}>
445
        {$svg}
446
        <figcaption markdown=1>{$caption}</figcaption>
447
        </figure>
448
        EOD;*/
449
/*
450
        $html = <<<EOD
451
<figure{$id}{$class}>
452
{$start}<img src="{$src}" alt="{$alt}"{$title}/>{$end}
453
<figcaption markdown=1>{$caption}</figcaption>
454
</figure>
455
EOD;
456
457
        return $html;*/
458
/*    }
459
*/
460
461
462
463
/**
464
 * Shorttags to to quicker format text as HTML.
465
 *
466
 * @param string text text to be converted.
467
 * @return string the formatted text.
468
 */
469
/*public static function ShortTags($text) {
470
  $callback = function($matches) {
471
    switch($matches[1]) {
472
      case 'IMG':
473
        $caption = t('Image: ');
474
        $pos = strpos($matches[2], '?');
475
        $href = $pos ? substr($matches[2], 0, $pos) : $matches[2];
476
        $src = htmlspecialchars($matches[2]);
477
        return <<<EOD
478
<figure>
479
<a href='{$href}'><img src='{$src}' alt='{$matches[3]}' /></a>
480
<figcaption markdown=1>{$caption}{$matches[3]}</figcaption>
481
</figure>
482
EOD;
483
484
      case 'IMG2':
485
        $caption = null; //t('Image: ');
486
        $pos = strpos($matches[2], '?');
487
        $href = $pos ? substr($matches[2], 0, $pos) : $matches[2];
488
        $src = htmlspecialchars($matches[2]);
489
        return <<<EOD
490
<figure class="{$matches[4]}">
491
<a href='{$href}'><img src='{$src}' alt='{$matches[3]}' /></a>
492
<figcaption markdown=1>{$caption}{$matches[3]}</figcaption>
493
</figure>
494
EOD;
495
      case 'BOOK':
496
        $isbn = $matches[2];
497
        $stores = array(
498
          'BTH' => "http://bth.summon.serialssolutions.com/?#!/search?ho=t&amp;q={$isbn}",
499
          'Libris' => "http://libris.kb.se/hitlist?q={$isbn}",
500
          'Google Books' => "http://books.google.com/books?q={$isbn}",
501
          'Bokus' => "http://www.bokus.com/bok/{$isbn}",
502
          'Adlibris' => "http://www.adlibris.com/se/product.aspx?isbn={$isbn}",
503
          'Amazon' => "http://www.amazon.com/s/ref=nb_ss?url=field-keywords={$isbn}",
504
          'Barnes&Noble' => "http://search.barnesandnoble.com/booksearch/ISBNInquiry.asp?r=1&IF=N&EAN={$isbn}",
505
        );
506
        $html = null;
507
        foreach($stores as $key => $val) {
508
          $html .= "<a href='$val'>$key</a> &bull; ";
509
        }
510
        return substr($html, 0, -8);
511
      break;
512
513
      case 'YOUTUBE':
514
        $caption = t('Figure: ');
515
        $height = ceil($matches[3] / (16/9));
516
        return <<<EOD
517
<figure>
518
<iframe width='{$matches[3]}' height='{$height}' src="http://www.youtube.com/embed/{$matches[2]}" frameborder="0"
519
allowfullscreen></iframe>
520
<figcaption>{$caption}{$matches[4]}</figcaption>
521
</figure>
522
EOD;
523
      break;
524
      
525
      case 'syntax=': return CTextFilter::SyntaxHighlightGeSHi($matches[3], $matches[2]); break;
526
      case '```': return CTextFilter::SyntaxHighlightGeSHi($matches[3], $matches[2]); break;
527
      //case 'syntax=': return "<pre>" . highlight_string($matches[3], true) . "</pre>"; break;
528
      //case 'INCL':  include($matches[2]); break;
529
      case 'INFO':  return "<div class='info' markdown=1>"; break;
530
      case '/INFO': return "</div>"; break;
531
      case 'BASEURL': return CLydia::Instance()->request->base_url; break;
532
      case 'FIGURE': return CTextFilter::ShortCodeFigure($matches[2]); break;
533
      case 'FIGURE-SVG': return CTextFilter::ShortCodeSVGFigure($matches[2]); break;
534
      case 'ASCIINEMA': return CTextFilter::ShortCodeAsciinema($matches[2]); break;
535
      default: return "{$matches[1]} IS UNKNOWN SHORTTAG."; break;
536
    }
537
  };
538
  $patterns = array(
539
    '#\[(BASEURL)\]#',
540
    //'/\[(AUTHOR) name=(.+) email=(.+) url=(.+)\]/',
541
    '/\[(FIGURE)[\s+](.+)\]/',
542
    '/\[(FIGURE-SVG)[\s+](.+)\]/',
543
    '/\[(ASCIINEMA)[\s+](.+)\]/',
544
    '/\[(IMG) src=(.+) alt=(.+)\]/',
545
    '/\[(IMG2) src=(.+) alt="(.+)" class="(.+)"\]/',
546
    '/\[(BOOK) isbn=(.+)\]/',
547
    '/\[(YOUTUBE) src=(.+) width=(.+) caption=(.+)\]/',
548
    '/~~~(syntax=)(php|html|html5|css|sql|javascript|bash)\n([^~]+)\n~~~/s',
549
    '/(```)(php|html|html5|css|sql|javascript|bash|text|txt|python)\n([^`]+)\n```/s',
550
    //'/\[(INCL)/s*([^\]+)/',
551
    '#\[(INFO)\]#', '#\[(/INFO)\]#',
552
  );
553
554
  $ret = preg_replace_callback($patterns, $callback, $text);
555
  return $ret;
556
}
557
*/
558
}
559