1<?php 2 3namespace dokuwiki\Parsing\ParserMode; 4 5use dokuwiki\Parsing\Handler; 6use dokuwiki\Parsing\Helpers\Media as MediaHelper; 7 8class Media extends AbstractMode 9{ 10 /** @inheritdoc */ 11 public function getSort() 12 { 13 return 320; 14 } 15 16 /** @inheritdoc */ 17 public function connectTo($mode) 18 { 19 // Body is possessive: it can only match up to the first `}}` (neither 20 // alternative accepts `}}`), so it never needs to backtrack to let the 21 // closing `}}` match. Without the possessive quantifier an unclosed 22 // `{{` followed by a large body drives the non-JIT PCRE engine to 23 // retain one backtracking frame per byte — an unbounded memory spike. 24 $this->Lexer->addSpecialPattern("\{\{(?:[^\}]|(?:\}[^\}]))++\}\}", $mode, 'media'); 25 } 26 27 /** @inheritdoc */ 28 public function handle($match, $state, $pos, Handler $handler) 29 { 30 $p = self::parseMedia($match); 31 32 $handler->addCall( 33 $p['type'], 34 [$p['src'], $p['title'], $p['align'], $p['width'], $p['height'], $p['cache'], $p['linking']], 35 $pos 36 ); 37 return true; 38 } 39 40 /** 41 * Parse media syntax into its components 42 * 43 * @param string $match The full media syntax (e.g. {{image.png?200|title}}) 44 * @return array Parsed media parameters (type, src, title, align, width, height, cache, linking) 45 */ 46 public static function parseMedia($match) 47 { 48 // Strip the opening and closing markup 49 $link = preg_replace(['/^\{\{/', '/\}\}$/u'], '', $match); 50 51 // Split title from URL 52 $link = sexplode('|', $link, 2); 53 54 // Check alignment 55 $ralign = (bool)preg_match('/^ /', $link[0]); 56 $lalign = (bool)preg_match('/ $/', $link[0]); 57 58 // Logic = what's that ;)... 59 if ($lalign & $ralign) { 60 $align = 'center'; 61 } elseif ($ralign) { 62 $align = 'right'; 63 } elseif ($lalign) { 64 $align = 'left'; 65 } else { 66 $align = null; 67 } 68 69 // The title... 70 if (!isset($link[1])) { 71 $link[1] = null; 72 } 73 74 //remove aligning spaces 75 $link[0] = trim($link[0]); 76 77 $p = MediaHelper::parseParameters($link[0]); 78 79 // Explicit param-derived alignment (?left/?right/?center) beats 80 // the whitespace-derived one — it's unambiguous and visible, and 81 // is the only form GfmMedia can express. 82 if ($p['align'] !== null) { 83 $align = $p['align']; 84 } 85 86 if (media_isexternal($p['src']) || link_isinterwiki($p['src'])) { 87 $call = 'externalmedia'; 88 } else { 89 $call = 'internalmedia'; 90 } 91 92 return [ 93 'type' => $call, 94 'src' => $p['src'], 95 'title' => $link[1], 96 'align' => $align, 97 'width' => $p['width'], 98 'height' => $p['height'], 99 'cache' => $p['cache'], 100 'linking' => $p['linking'] 101 ]; 102 } 103} 104