mirror of
https://github.com/Dolibarr/dolibarr.git
synced 2025-02-20 13:46:52 +01:00
NEW Update lib parsedownto 1.7.4
This commit is contained in:
parent
3999f87fd2
commit
bf89d61686
|
|
@ -29,7 +29,7 @@ GeoIP2 0.2.0 Apache License 2.0 Yes
|
|||
Mobiledetect 2.8.41 MIT License Yes Detect mobile devices browsers
|
||||
NuSoap 0.9.5 LGPL 2.1+ Yes Library to develop SOAP Web services (not into rpm and deb package)
|
||||
PEAR Mail_MIME 1.8.9 BSD Yes NuSoap dependency
|
||||
ParseDown 1.6 MIT License Yes Markdown parser
|
||||
ParseDown 1.7.4 MIT License Yes Markdown parser
|
||||
PCLZip 2.8.4 LGPL-3+ Yes Library to zip/unzip files
|
||||
PHPDebugBar 1.18.2 MIT License Yes Used only by the module "debugbar" for developers
|
||||
PHP-Imap 2.7.2 MIT License Yes Library to use IMAP with OAuth
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
<?php
|
||||
/* Copyright (C) 2008-2013 Laurent Destailleur <eldy@users.sourceforge.net>
|
||||
/* Copyright (C) 2008-2023 Laurent Destailleur <eldy@users.sourceforge.net>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
|
|
@ -18,7 +18,7 @@
|
|||
|
||||
/**
|
||||
* \file htdocs/core/lib/parsemd.lib.php
|
||||
* \brief This file contains functions dedicated to MD parsind.
|
||||
* \brief This file contains functions dedicated to MD parsing.
|
||||
*/
|
||||
|
||||
/**
|
||||
|
|
@ -40,8 +40,9 @@ function dolMd2Html($content, $parser = 'parsedown', $replaceimagepath = null)
|
|||
}
|
||||
if ($parser == 'parsedown') {
|
||||
include_once DOL_DOCUMENT_ROOT.'/includes/parsedown/Parsedown.php';
|
||||
$Parsedown = new Parsedown();
|
||||
$content = $Parsedown->text($content);
|
||||
$parsedown = new Parsedown();
|
||||
$parsedown->setSafeMode(true); // This will escape HTML link <a href=""> into html entities but markdown links are ok
|
||||
$content = $parsedown->text($content);
|
||||
} else {
|
||||
$content = nl2br($content);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -683,6 +683,11 @@ class DolibarrModules // Can not be abstract, because we need to instantiate it
|
|||
if ((float) DOL_VERSION >= 6.0) {
|
||||
@include_once DOL_DOCUMENT_ROOT.'/core/lib/parsemd.lib.php';
|
||||
|
||||
// Replace a HTML string with a Markdown syntax
|
||||
$content = preg_replace('/<a href="([^"]+)">([^<]+)<\/a>/', '[\2](\1)', $content);
|
||||
//$content = preg_replace('/<a href="([^"]+)" target="([^"]+)">([^<]+)<\/a>/', '[\3](\1){:target="\2"}', $content);
|
||||
$content = preg_replace('/<a href="([^"]+)" target="([^"]+)">([^<]+)<\/a>/', '[\3](\1)', $content);
|
||||
|
||||
$content = dolMd2Html(
|
||||
$content,
|
||||
'parsedown',
|
||||
|
|
@ -692,6 +697,8 @@ class DolibarrModules // Can not be abstract, because we need to instantiate it
|
|||
'images/' => dol_buildpath(strtolower($this->name).'/images/', 1),
|
||||
)
|
||||
);
|
||||
|
||||
$content = preg_replace('/<a href="/', '<a target="_blank" rel="noopener noreferrer" href="', $content);
|
||||
} else {
|
||||
$content = nl2br($content);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,16 +0,0 @@
|
|||
language: php
|
||||
|
||||
php:
|
||||
- 7.1
|
||||
- 7.0
|
||||
- 5.6
|
||||
- 5.5
|
||||
- 5.4
|
||||
- 5.3
|
||||
- hhvm
|
||||
- hhvm-nightly
|
||||
|
||||
matrix:
|
||||
fast_finish: true
|
||||
allow_failures:
|
||||
- php: hhvm-nightly
|
||||
|
|
@ -1,6 +1,6 @@
|
|||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2013 Emanuil Rusev, erusev.com
|
||||
Copyright (c) 2013-2018 Emanuil Rusev, erusev.com
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||
this software and associated documentation files (the "Software"), to deal in
|
||||
|
|
@ -17,4 +17,4 @@ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
|||
FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
||||
COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
||||
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
|
|
|
|||
|
|
@ -17,7 +17,7 @@ class Parsedown
|
|||
{
|
||||
# ~
|
||||
|
||||
const version = '1.6.0';
|
||||
const version = '1.7.4';
|
||||
|
||||
# ~
|
||||
|
||||
|
|
@ -75,6 +75,32 @@ class Parsedown
|
|||
|
||||
protected $urlsLinked = true;
|
||||
|
||||
function setSafeMode($safeMode)
|
||||
{
|
||||
$this->safeMode = (bool) $safeMode;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
protected $safeMode;
|
||||
|
||||
protected $safeLinksWhitelist = array(
|
||||
'http://',
|
||||
'https://',
|
||||
'ftp://',
|
||||
'ftps://',
|
||||
'mailto:',
|
||||
'data:image/png;base64,',
|
||||
'data:image/gif;base64,',
|
||||
'data:image/jpeg;base64,',
|
||||
'irc:',
|
||||
'ircs:',
|
||||
'git:',
|
||||
'ssh:',
|
||||
'news:',
|
||||
'steam:',
|
||||
);
|
||||
|
||||
#
|
||||
# Lines
|
||||
#
|
||||
|
|
@ -141,11 +167,7 @@ class Parsedown
|
|||
|
||||
foreach ($parts as $part)
|
||||
{
|
||||
// @CHANGE LDR Fix when mb_strlen is not available
|
||||
//$shortage = 4 - mb_strlen($line, 'utf-8') % 4;
|
||||
if (function_exists('mb_strlen')) $len = mb_strlen($line, 'utf-8');
|
||||
else $len = strlen($line);
|
||||
$shortage = 4 - $len % 4;
|
||||
$shortage = 4 - mb_strlen($line, 'utf-8') % 4;
|
||||
|
||||
$line .= str_repeat(' ', $shortage);
|
||||
$line .= $part;
|
||||
|
|
@ -346,8 +368,6 @@ class Parsedown
|
|||
{
|
||||
$text = $Block['element']['text']['text'];
|
||||
|
||||
$text = htmlspecialchars($text, ENT_NOQUOTES, 'UTF-8');
|
||||
|
||||
$Block['element']['text']['text'] = $text;
|
||||
|
||||
return $Block;
|
||||
|
|
@ -358,7 +378,7 @@ class Parsedown
|
|||
|
||||
protected function blockComment($Line)
|
||||
{
|
||||
if ($this->markupEscaped)
|
||||
if ($this->markupEscaped or $this->safeMode)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
|
@ -400,7 +420,7 @@ class Parsedown
|
|||
|
||||
protected function blockFencedCode($Line)
|
||||
{
|
||||
if (preg_match('/^['.$Line['text'][0].']{3,}[ ]*([\w-]+)?[ ]*$/', $Line['text'], $matches))
|
||||
if (preg_match('/^['.$Line['text'][0].']{3,}[ ]*([^`]+)?[ ]*$/', $Line['text'], $matches))
|
||||
{
|
||||
$Element = array(
|
||||
'name' => 'code',
|
||||
|
|
@ -409,7 +429,21 @@ class Parsedown
|
|||
|
||||
if (isset($matches[1]))
|
||||
{
|
||||
$class = 'language-'.$matches[1];
|
||||
/**
|
||||
* https://www.w3.org/TR/2011/WD-html5-20110525/elements.html#classes
|
||||
* Every HTML element may have a class attribute specified.
|
||||
* The attribute, if specified, must have a value that is a set
|
||||
* of space-separated tokens representing the various classes
|
||||
* that the element belongs to.
|
||||
* [...]
|
||||
* The space characters, for the purposes of this specification,
|
||||
* are U+0020 SPACE, U+0009 CHARACTER TABULATION (tab),
|
||||
* U+000A LINE FEED (LF), U+000C FORM FEED (FF), and
|
||||
* U+000D CARRIAGE RETURN (CR).
|
||||
*/
|
||||
$language = substr($matches[1], 0, strcspn($matches[1], " \t\n\f\r"));
|
||||
|
||||
$class = 'language-'.$language;
|
||||
|
||||
$Element['attributes'] = array(
|
||||
'class' => $class,
|
||||
|
|
@ -461,8 +495,6 @@ class Parsedown
|
|||
{
|
||||
$text = $Block['element']['text']['text'];
|
||||
|
||||
$text = htmlspecialchars($text, ENT_NOQUOTES, 'UTF-8');
|
||||
|
||||
$Block['element']['text']['text'] = $text;
|
||||
|
||||
return $Block;
|
||||
|
|
@ -551,6 +583,8 @@ class Parsedown
|
|||
{
|
||||
$Block['li']['text'] []= '';
|
||||
|
||||
$Block['loose'] = true;
|
||||
|
||||
unset($Block['interrupted']);
|
||||
}
|
||||
|
||||
|
|
@ -599,6 +633,22 @@ class Parsedown
|
|||
}
|
||||
}
|
||||
|
||||
protected function blockListComplete(array $Block)
|
||||
{
|
||||
if (isset($Block['loose']))
|
||||
{
|
||||
foreach ($Block['element']['text'] as &$li)
|
||||
{
|
||||
if (end($li['text']) !== '')
|
||||
{
|
||||
$li['text'] []= '';
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $Block;
|
||||
}
|
||||
|
||||
#
|
||||
# Quote
|
||||
|
||||
|
|
@ -682,12 +732,12 @@ class Parsedown
|
|||
|
||||
protected function blockMarkup($Line)
|
||||
{
|
||||
if ($this->markupEscaped)
|
||||
if ($this->markupEscaped or $this->safeMode)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (preg_match('/^<(\w*)(?:[ ]*'.$this->regexHtmlAttribute.')*[ ]*(\/)?>/', $Line['text'], $matches))
|
||||
if (preg_match('/^<(\w[\w-]*)(?:[ ]*'.$this->regexHtmlAttribute.')*[ ]*(\/)?>/', $Line['text'], $matches))
|
||||
{
|
||||
$element = strtolower($matches[1]);
|
||||
|
||||
|
|
@ -1001,7 +1051,7 @@ class Parsedown
|
|||
# ~
|
||||
#
|
||||
|
||||
public function line($text)
|
||||
public function line($text, $nonNestables=array())
|
||||
{
|
||||
$markup = '';
|
||||
|
||||
|
|
@ -1017,6 +1067,13 @@ class Parsedown
|
|||
|
||||
foreach ($this->InlineTypes[$marker] as $inlineType)
|
||||
{
|
||||
# check to see if the current inline type is nestable in the current context
|
||||
|
||||
if ( ! empty($nonNestables) and in_array($inlineType, $nonNestables))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
$Inline = $this->{'inline'.$inlineType}($Excerpt);
|
||||
|
||||
if ( ! isset($Inline))
|
||||
|
|
@ -1038,6 +1095,13 @@ class Parsedown
|
|||
$Inline['position'] = $markerPosition;
|
||||
}
|
||||
|
||||
# cause the new element to 'inherit' our non nestables
|
||||
|
||||
foreach ($nonNestables as $non_nestable)
|
||||
{
|
||||
$Inline['element']['nonNestables'][] = $non_nestable;
|
||||
}
|
||||
|
||||
# the text that comes before the inline
|
||||
$unmarkedText = substr($text, 0, $Inline['position']);
|
||||
|
||||
|
|
@ -1078,7 +1142,6 @@ class Parsedown
|
|||
if (preg_match('/^('.$marker.'+)[ ]*(.+?)[ ]*(?<!'.$marker.')\1(?!'.$marker.')/s', $Excerpt['text'], $matches))
|
||||
{
|
||||
$text = $matches[2];
|
||||
$text = htmlspecialchars($text, ENT_NOQUOTES, 'UTF-8');
|
||||
$text = preg_replace("/[ ]*\n/", ' ', $text);
|
||||
|
||||
return array(
|
||||
|
|
@ -1180,9 +1243,7 @@ class Parsedown
|
|||
'name' => 'img',
|
||||
'attributes' => array(
|
||||
'src' => $Link['element']['attributes']['href'],
|
||||
'alt' => $Link['element']['text'],
|
||||
// @CHANGE LDR
|
||||
'class' => (!empty($Link['element']['attributes']['class']) ? $Link['element']['attributes']['class'] : '')
|
||||
'alt' => $Link['element']['text'],
|
||||
),
|
||||
),
|
||||
);
|
||||
|
|
@ -1199,6 +1260,7 @@ class Parsedown
|
|||
$Element = array(
|
||||
'name' => 'a',
|
||||
'handler' => 'line',
|
||||
'nonNestables' => array('Url', 'Link'),
|
||||
'text' => null,
|
||||
'attributes' => array(
|
||||
'href' => null,
|
||||
|
|
@ -1233,13 +1295,6 @@ class Parsedown
|
|||
}
|
||||
|
||||
$extent += strlen($matches[0]);
|
||||
|
||||
// @CHANGE LDR
|
||||
if (preg_match('/{([^}]+)}/', $remainder, $matches2))
|
||||
{
|
||||
$Element['attributes']['class'] = $matches2[1];
|
||||
$remainder = preg_replace('/{'.preg_quote($matches2[1],'/').'}/', '', $remainder);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
|
|
@ -1266,8 +1321,6 @@ class Parsedown
|
|||
$Element['attributes']['title'] = $Definition['title'];
|
||||
}
|
||||
|
||||
$Element['attributes']['href'] = str_replace(array('&', '<'), array('&', '<'), $Element['attributes']['href']);
|
||||
|
||||
return array(
|
||||
'extent' => $extent,
|
||||
'element' => $Element,
|
||||
|
|
@ -1276,12 +1329,12 @@ class Parsedown
|
|||
|
||||
protected function inlineMarkup($Excerpt)
|
||||
{
|
||||
if ($this->markupEscaped or strpos($Excerpt['text'], '>') === false)
|
||||
if ($this->markupEscaped or $this->safeMode or strpos($Excerpt['text'], '>') === false)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if ($Excerpt['text'][1] === '/' and preg_match('/^<\/\w*[ ]*>/s', $Excerpt['text'], $matches))
|
||||
if ($Excerpt['text'][1] === '/' and preg_match('/^<\/\w[\w-]*[ ]*>/s', $Excerpt['text'], $matches))
|
||||
{
|
||||
return array(
|
||||
'markup' => $matches[0],
|
||||
|
|
@ -1297,7 +1350,7 @@ class Parsedown
|
|||
);
|
||||
}
|
||||
|
||||
if ($Excerpt['text'][1] !== ' ' and preg_match('/^<\w*(?:[ ]*'.$this->regexHtmlAttribute.')*[ ]*\/?>/s', $Excerpt['text'], $matches))
|
||||
if ($Excerpt['text'][1] !== ' ' and preg_match('/^<\w[\w-]*(?:[ ]*'.$this->regexHtmlAttribute.')*[ ]*\/?>/s', $Excerpt['text'], $matches))
|
||||
{
|
||||
return array(
|
||||
'markup' => $matches[0],
|
||||
|
|
@ -1356,14 +1409,16 @@ class Parsedown
|
|||
|
||||
if (preg_match('/\bhttps?:[\/]{2}[^\s<]+\b\/*/ui', $Excerpt['context'], $matches, PREG_OFFSET_CAPTURE))
|
||||
{
|
||||
$url = $matches[0][0];
|
||||
|
||||
$Inline = array(
|
||||
'extent' => strlen($matches[0][0]),
|
||||
'position' => $matches[0][1],
|
||||
'element' => array(
|
||||
'name' => 'a',
|
||||
'text' => $matches[0][0],
|
||||
'text' => $url,
|
||||
'attributes' => array(
|
||||
'href' => $matches[0][0],
|
||||
'href' => $url,
|
||||
),
|
||||
),
|
||||
);
|
||||
|
|
@ -1376,7 +1431,7 @@ class Parsedown
|
|||
{
|
||||
if (strpos($Excerpt['text'], '>') !== false and preg_match('/^<(\w+:\/{2}[^ >]+)>/i', $Excerpt['text'], $matches))
|
||||
{
|
||||
$url = str_replace(array('&', '<'), array('&', '<'), $matches[1]);
|
||||
$url = $matches[1];
|
||||
|
||||
return array(
|
||||
'extent' => strlen($matches[0]),
|
||||
|
|
@ -1414,6 +1469,11 @@ class Parsedown
|
|||
|
||||
protected function element(array $Element)
|
||||
{
|
||||
if ($this->safeMode)
|
||||
{
|
||||
$Element = $this->sanitiseElement($Element);
|
||||
}
|
||||
|
||||
$markup = '<'.$Element['name'];
|
||||
|
||||
if (isset($Element['attributes']))
|
||||
|
|
@ -1425,23 +1485,45 @@ class Parsedown
|
|||
continue;
|
||||
}
|
||||
|
||||
$markup .= ' '.$name.'="'.$value.'"';
|
||||
$markup .= ' '.$name.'="'.self::escape($value).'"';
|
||||
}
|
||||
}
|
||||
|
||||
$permitRawHtml = false;
|
||||
|
||||
if (isset($Element['text']))
|
||||
{
|
||||
$text = $Element['text'];
|
||||
}
|
||||
// very strongly consider an alternative if you're writing an
|
||||
// extension
|
||||
elseif (isset($Element['rawHtml']))
|
||||
{
|
||||
$text = $Element['rawHtml'];
|
||||
$allowRawHtmlInSafeMode = isset($Element['allowRawHtmlInSafeMode']) && $Element['allowRawHtmlInSafeMode'];
|
||||
$permitRawHtml = !$this->safeMode || $allowRawHtmlInSafeMode;
|
||||
}
|
||||
|
||||
if (isset($text))
|
||||
{
|
||||
$markup .= '>';
|
||||
|
||||
if (!isset($Element['nonNestables']))
|
||||
{
|
||||
$Element['nonNestables'] = array();
|
||||
}
|
||||
|
||||
if (isset($Element['handler']))
|
||||
{
|
||||
// @CHANGE LDR
|
||||
//$markup .= $this->{$Element['handler']}($Element['text']);
|
||||
$markup .= preg_replace('/>{[^}]+}/', '>', $this->{$Element['handler']}($Element['text']));
|
||||
$markup .= $this->{$Element['handler']}($text, $Element['nonNestables']);
|
||||
}
|
||||
elseif (!$permitRawHtml)
|
||||
{
|
||||
$markup .= self::escape($text, true);
|
||||
}
|
||||
else
|
||||
{
|
||||
$markup .= $Element['text'];
|
||||
$markup .= $text;
|
||||
}
|
||||
|
||||
$markup .= '</'.$Element['name'].'>';
|
||||
|
|
@ -1500,10 +1582,77 @@ class Parsedown
|
|||
return $markup;
|
||||
}
|
||||
|
||||
protected function sanitiseElement(array $Element)
|
||||
{
|
||||
static $goodAttribute = '/^[a-zA-Z0-9][a-zA-Z0-9-_]*+$/';
|
||||
static $safeUrlNameToAtt = array(
|
||||
'a' => 'href',
|
||||
'img' => 'src',
|
||||
);
|
||||
|
||||
if (isset($safeUrlNameToAtt[$Element['name']]))
|
||||
{
|
||||
$Element = $this->filterUnsafeUrlInAttribute($Element, $safeUrlNameToAtt[$Element['name']]);
|
||||
}
|
||||
|
||||
if ( ! empty($Element['attributes']))
|
||||
{
|
||||
foreach ($Element['attributes'] as $att => $val)
|
||||
{
|
||||
# filter out badly parsed attribute
|
||||
if ( ! preg_match($goodAttribute, $att))
|
||||
{
|
||||
unset($Element['attributes'][$att]);
|
||||
}
|
||||
# dump onevent attribute
|
||||
elseif (self::striAtStart($att, 'on'))
|
||||
{
|
||||
unset($Element['attributes'][$att]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $Element;
|
||||
}
|
||||
|
||||
protected function filterUnsafeUrlInAttribute(array $Element, $attribute)
|
||||
{
|
||||
foreach ($this->safeLinksWhitelist as $scheme)
|
||||
{
|
||||
if (self::striAtStart($Element['attributes'][$attribute], $scheme))
|
||||
{
|
||||
return $Element;
|
||||
}
|
||||
}
|
||||
|
||||
$Element['attributes'][$attribute] = str_replace(':', '%3A', $Element['attributes'][$attribute]);
|
||||
|
||||
return $Element;
|
||||
}
|
||||
|
||||
#
|
||||
# Static Methods
|
||||
#
|
||||
|
||||
protected static function escape($text, $allowQuotes = false)
|
||||
{
|
||||
return htmlspecialchars($text, $allowQuotes ? ENT_NOQUOTES : ENT_QUOTES, 'UTF-8');
|
||||
}
|
||||
|
||||
protected static function striAtStart($string, $needle)
|
||||
{
|
||||
$len = strlen($needle);
|
||||
|
||||
if ($len > strlen($string))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
return strtolower(substr($string, 0, $len)) === strtolower($needle);
|
||||
}
|
||||
}
|
||||
|
||||
static function instance($name = 'default')
|
||||
{
|
||||
if (isset(self::$instances[$name]))
|
||||
|
|
@ -1554,10 +1703,10 @@ class Parsedown
|
|||
'b', 'em', 'big', 'cite', 'small', 'spacer', 'listing',
|
||||
'i', 'rp', 'del', 'code', 'strike', 'marquee',
|
||||
'q', 'rt', 'ins', 'font', 'strong',
|
||||
's', 'tt', 'sub', 'mark',
|
||||
'u', 'xm', 'sup', 'nobr',
|
||||
'var', 'ruby',
|
||||
'wbr', 'span',
|
||||
'time',
|
||||
's', 'tt', 'kbd', 'mark',
|
||||
'u', 'xm', 'sub', 'nobr',
|
||||
'sup', 'ruby',
|
||||
'var', 'span',
|
||||
'wbr', 'time',
|
||||
);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
> You might also like [Caret](http://caret.io?ref=parsedown) - our Markdown editor for Mac / Windows / Linux.
|
||||
> I also make [Caret](https://caret.io?ref=parsedown) - a Markdown editor for Mac and PC.
|
||||
|
||||
## Parsedown
|
||||
|
||||
|
|
@ -15,6 +15,7 @@ Better Markdown Parser in PHP
|
|||
### Features
|
||||
|
||||
* One File
|
||||
* No Dependencies
|
||||
* Super Fast
|
||||
* Extensible
|
||||
* [GitHub flavored](https://help.github.com/articles/github-flavored-markdown)
|
||||
|
|
@ -35,6 +36,35 @@ echo $Parsedown->text('Hello _Parsedown_!'); # prints: <p>Hello <em>Parsedown</e
|
|||
|
||||
More examples in [the wiki](https://github.com/erusev/parsedown/wiki/) and in [this video tutorial](http://youtu.be/wYZBY8DEikI).
|
||||
|
||||
### Security
|
||||
|
||||
Parsedown is capable of escaping user-input within the HTML that it generates. Additionally Parsedown will apply sanitisation to additional scripting vectors (such as scripting link destinations) that are introduced by the markdown syntax itself.
|
||||
|
||||
To tell Parsedown that it is processing untrusted user-input, use the following:
|
||||
```php
|
||||
$parsedown = new Parsedown;
|
||||
$parsedown->setSafeMode(true);
|
||||
```
|
||||
|
||||
If instead, you wish to allow HTML within untrusted user-input, but still want output to be free from XSS it is recommended that you make use of a HTML sanitiser that allows HTML tags to be whitelisted, like [HTML Purifier](http://htmlpurifier.org/).
|
||||
|
||||
In both cases you should strongly consider employing defence-in-depth measures, like [deploying a Content-Security-Policy](https://scotthelme.co.uk/content-security-policy-an-introduction/) (a browser security feature) so that your page is likely to be safe even if an attacker finds a vulnerability in one of the first lines of defence above.
|
||||
|
||||
#### Security of Parsedown Extensions
|
||||
|
||||
Safe mode does not necessarily yield safe results when using extensions to Parsedown. Extensions should be evaluated on their own to determine their specific safety against XSS.
|
||||
|
||||
### Escaping HTML
|
||||
> ⚠️ **WARNING:** This method isn't safe from XSS!
|
||||
|
||||
If you wish to escape HTML **in trusted input**, you can use the following:
|
||||
```php
|
||||
$parsedown = new Parsedown;
|
||||
$parsedown->setMarkupEscaped(true);
|
||||
```
|
||||
|
||||
Beware that this still allows users to insert unsafe scripting vectors, such as links like `[xss](javascript:alert%281%29)`.
|
||||
|
||||
### Questions
|
||||
|
||||
**How does Parsedown work?**
|
||||
|
|
@ -49,7 +79,7 @@ It passes most of the CommonMark tests. Most of the tests that don't pass deal w
|
|||
|
||||
**Who uses it?**
|
||||
|
||||
[phpDocumentor](http://www.phpdoc.org/), [October CMS](http://octobercms.com/), [Bolt CMS](http://bolt.cm/), [Kirby CMS](http://getkirby.com/), [Grav CMS](http://getgrav.org/), [Statamic CMS](http://www.statamic.com/), [Herbie CMS](http://www.getherbie.org/), [RaspberryPi.org](http://www.raspberrypi.org/), [Symfony demo](https://github.com/symfony/symfony-demo) and [more](https://packagist.org/packages/erusev/parsedown/dependents).
|
||||
[Laravel Framework](https://laravel.com/), [Bolt CMS](http://bolt.cm/), [Grav CMS](http://getgrav.org/), [Herbie CMS](http://www.getherbie.org/), [Kirby CMS](http://getkirby.com/), [October CMS](http://octobercms.com/), [Pico CMS](http://picocms.org), [Statamic CMS](http://www.statamic.com/), [phpDocumentor](http://www.phpdoc.org/), [RaspberryPi.org](http://www.raspberrypi.org/), [Symfony demo](https://github.com/symfony/symfony-demo) and [more](https://packagist.org/packages/erusev/parsedown/dependents).
|
||||
|
||||
**How can I help?**
|
||||
|
||||
|
|
|
|||
|
|
@ -13,9 +13,21 @@
|
|||
}
|
||||
],
|
||||
"require": {
|
||||
"php": ">=5.3.0"
|
||||
"php": ">=5.3.0",
|
||||
"ext-mbstring": "*"
|
||||
},
|
||||
"require-dev": {
|
||||
"phpunit/phpunit": "^4.8.35"
|
||||
},
|
||||
"autoload": {
|
||||
"psr-0": {"Parsedown": ""}
|
||||
},
|
||||
"autoload-dev": {
|
||||
"psr-0": {
|
||||
"TestParsedown": "test/",
|
||||
"ParsedownTest": "test/",
|
||||
"CommonMarkTest": "test/",
|
||||
"CommonMarkTestWeak": "test/"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,8 +0,0 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<phpunit bootstrap="test/bootstrap.php" colors="true">
|
||||
<testsuites>
|
||||
<testsuite>
|
||||
<file>test/ParsedownTest.php</file>
|
||||
</testsuite>
|
||||
</testsuites>
|
||||
</phpunit>
|
||||
Loading…
Reference in New Issue
Block a user