private function parseLine($text, $markers = array(" \n", '![', '&', '*', '<', '[', '\\', '_', '`', 'http', '~~'))
{
if (isset($text[1]) === false or $markers === array()) {
return $text;
}
# ~
$markup = '';
while ($markers) {
$closestMarker = null;
$closestMarkerIndex = 0;
$closestMarkerPosition = null;
foreach ($markers as $index => $marker) {
$markerPosition = strpos($text, $marker);
if ($markerPosition === false) {
unset($markers[$index]);
continue;
}
if ($closestMarker === null or $markerPosition < $closestMarkerPosition) {
$closestMarker = $marker;
$closestMarkerIndex = $index;
$closestMarkerPosition = $markerPosition;
}
}
# ~
if ($closestMarker === null or isset($text[$closestMarkerPosition + 1]) === false) {
$markup .= $text;
break;
} else {
$markup .= substr($text, 0, $closestMarkerPosition);
}
$text = substr($text, $closestMarkerPosition);
# ~
unset($markers[$closestMarkerIndex]);
# ~
switch ($closestMarker) {
case " \n":
$markup .= '<br />' . "\n";
$offset = 3;
break;
case '![':
case '[':
if (strpos($text, ']') and preg_match('/\\[((?:[^][]|(?R))*)\\]/', $text, $matches)) {
$element = array('!' => $text[0] === '!', 'text' => $matches[1]);
$offset = strlen($matches[0]);
if ($element['!']) {
$offset++;
}
$remainingText = substr($text, $offset);
if ($remainingText[0] === '(' and preg_match('/\\([ ]*(.*?)(?:[ ]+[\'"](.+?)[\'"])?[ ]*\\)/', $remainingText, $matches)) {
$element['link'] = $matches[1];
if (isset($matches[2])) {
$element['title'] = $matches[2];
}
$offset += strlen($matches[0]);
} elseif ($this->referenceMap) {
$reference = $element['text'];
if (preg_match('/^\\s*\\[(.*?)\\]/', $remainingText, $matches)) {
$reference = $matches[1] === '' ? $element['text'] : $matches[1];
$offset += strlen($matches[0]);
}
$reference = strtolower($reference);
if (isset($this->referenceMap[$reference])) {
$element['link'] = $this->referenceMap[$reference]['link'];
if (isset($this->referenceMap[$reference]['title'])) {
$element['title'] = $this->referenceMap[$reference]['title'];
}
} else {
unset($element);
}
} else {
unset($element);
}
}
if (isset($element)) {
$element['link'] = str_replace('&', '&', $element['link']);
$element['link'] = str_replace('<', '<', $element['link']);
if ($element['!']) {
$markup .= '<img alt="' . $element['text'] . '" src="' . $element['link'] . '"';
if (isset($element['title'])) {
$markup .= ' title="' . $element['title'] . '"';
}
$markup .= ' />';
} else {
$element['text'] = $this->parseLine($element['text'], $markers);
$markup .= '<a href="' . $element['link'] . '"';
if (isset($element['title'])) {
$markup .= ' title="' . $element['title'] . '"';
}
$markup .= '>' . $element['text'] . '</a>';
}
unset($element);
} else {
$markup .= $closestMarker;
$offset = $closestMarker === '![' ? 2 : 1;
}
break;
case '&':
if (preg_match('/^&#?\\w+;/', $text, $matches)) {
$markup .= $matches[0];
$offset = strlen($matches[0]);
} else {
$markup .= '&';
$offset = 1;
}
break;
case '*':
case '_':
if ($text[1] === $closestMarker and preg_match(self::$strongRegex[$closestMarker], $text, $matches)) {
$markers[$closestMarkerIndex] = $closestMarker;
$matches[1] = $this->parseLine($matches[1], $markers);
$markup .= '<strong>' . $matches[1] . '</strong>';
} elseif (preg_match(self::$emRegex[$closestMarker], $text, $matches)) {
$markers[$closestMarkerIndex] = $closestMarker;
$matches[1] = $this->parseLine($matches[1], $markers);
$markup .= '<em>' . $matches[1] . '</em>';
}
if (isset($matches) and $matches) {
$offset = strlen($matches[0]);
} else {
$markup .= $closestMarker;
$offset = 1;
}
break;
case '<':
if (strpos($text, '>') !== false) {
if ($text[1] === 'h' and preg_match('/^<(https?:[\\/]{2}[^\\s]+?)>/i', $text, $matches)) {
$elementUrl = $matches[1];
$elementUrl = str_replace('&', '&', $elementUrl);
$elementUrl = str_replace('<', '<', $elementUrl);
$markup .= '<a href="' . $elementUrl . '">' . $elementUrl . '</a>';
$offset = strlen($matches[0]);
} elseif (strpos($text, '@') > 1 and preg_match('/<(\\S+?@\\S+?)>/', $text, $matches)) {
$markup .= '<a href="mailto:' . $matches[1] . '">' . $matches[1] . '</a>';
$offset = strlen($matches[0]);
} elseif (preg_match('/^<\\/?\\w.*?>/', $text, $matches)) {
$markup .= $matches[0];
$offset = strlen($matches[0]);
} else {
$markup .= '<';
$offset = 1;
}
} else {
$markup .= '<';
$offset = 1;
}
break;
case '\\':
if (in_array($text[1], self::$specialCharacters)) {
$markup .= $text[1];
$offset = 2;
} else {
$markup .= '\\';
$offset = 1;
}
break;
case '`':
if (preg_match('/^(`+)[ ]*(.+?)[ ]*(?<!`)\\1(?!`)/', $text, $matches)) {
$elementText = $matches[2];
$elementText = htmlspecialchars($elementText, ENT_NOQUOTES, 'UTF-8');
$markup .= '<code>' . $elementText . '</code>';
$offset = strlen($matches[0]);
} else {
$markup .= '`';
$offset = 1;
}
break;
case 'http':
if (preg_match('/^https?:[\\/]{2}[^\\s]+\\b\\/*/ui', $text, $matches)) {
$elementUrl = $matches[0];
$elementUrl = str_replace('&', '&', $elementUrl);
$elementUrl = str_replace('<', '<', $elementUrl);
$markup .= '<a href="' . $elementUrl . '">' . $elementUrl . '</a>';
$offset = strlen($matches[0]);
} else {
$markup .= 'http';
$offset = 4;
}
break;
case '~~':
if (preg_match('/^~~(?=\\S)(.+?)(?<=\\S)~~/', $text, $matches)) {
$matches[1] = $this->parseLine($matches[1], $markers);
$markup .= '<del>' . $matches[1] . '</del>';
$offset = strlen($matches[0]);
} else {
$markup .= '~~';
$offset = 2;
}
break;
}
if (isset($offset)) {
$text = substr($text, $offset);
}
$markers[$closestMarkerIndex] = $closestMarker;
}
return $markup;
}