Sanitize filenames for usage in urls, fixes #86
This commit is contained in:
parent
667935e927
commit
5d2d19141c
@ -109,18 +109,38 @@ class LinkRenderer extends \League\CommonMark\Inline\Renderer\LinkRenderer
|
|||||||
$urlAndHash = explode('#', $url);
|
$urlAndHash = explode('#', $url);
|
||||||
$url = $urlAndHash[0];
|
$url = $urlAndHash[0];
|
||||||
|
|
||||||
|
$foundWithHash = false;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
$file = $this->resolveInternalFile($url);
|
$file = $this->resolveInternalFile($url);
|
||||||
$url = DauxHelper::getRelativePath($this->daux->getCurrentPage()->getUrl(), $file->getUrl());
|
$url = DauxHelper::getRelativePath($this->daux->getCurrentPage()->getUrl(), $file->getUrl());
|
||||||
} catch (LinkNotFoundException $e) {
|
} catch (LinkNotFoundException $e) {
|
||||||
if ($this->daux->isStatic()) {
|
|
||||||
throw $e;
|
|
||||||
|
|
||||||
|
// For some reason, the filename could contain a # and thus the link needs to resolve to that.
|
||||||
|
try {
|
||||||
|
if (strlen($urlAndHash[1]) > 0) {
|
||||||
|
$file = $this->resolveInternalFile($url . '#' . $urlAndHash[1]);
|
||||||
|
$url = DauxHelper::getRelativePath($this->daux->getCurrentPage()->getUrl(), $file->getUrl());
|
||||||
|
$foundWithHash = true;
|
||||||
|
}
|
||||||
|
} catch (LinkNotFoundException $e2) {
|
||||||
|
// If it's still not found here, we'll only
|
||||||
|
// report on the first error as the second
|
||||||
|
// one will tell the same.
|
||||||
}
|
}
|
||||||
|
|
||||||
$element->setAttribute('class', 'Link--broken');
|
if (!$foundWithHash) {
|
||||||
|
if ($this->daux->isStatic()) {
|
||||||
|
throw $e;
|
||||||
|
}
|
||||||
|
|
||||||
|
$element->setAttribute('class', 'Link--broken');
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (isset($urlAndHash[1])) {
|
if (!$foundWithHash && isset($urlAndHash[1])) {
|
||||||
$url .= '#' . $urlAndHash[1];
|
$url .= '#' . $urlAndHash[1];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -189,7 +189,7 @@ class DauxHelper
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
$node = urldecode($node);
|
$node = DauxHelper::slug(urldecode($node));
|
||||||
|
|
||||||
// if the node exists in the current request tree,
|
// if the node exists in the current request tree,
|
||||||
// change the $tree variable to reference the new
|
// change the $tree variable to reference the new
|
||||||
@ -241,18 +241,21 @@ class DauxHelper
|
|||||||
*/
|
*/
|
||||||
public static function slug($title)
|
public static function slug($title)
|
||||||
{
|
{
|
||||||
|
// Convert to ASCII
|
||||||
foreach (static::charsArray() as $key => $value) {
|
foreach (static::charsArray() as $key => $value) {
|
||||||
$title = str_replace($value, $key, $title);
|
$title = str_replace($value, $key, $title);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Remove unsupported characters
|
||||||
$title = preg_replace('/[^\x20-\x7E]/u', '', $title);
|
$title = preg_replace('/[^\x20-\x7E]/u', '', $title);
|
||||||
|
|
||||||
$separator = '_';
|
$separator = '_';
|
||||||
// Convert all dashes into underscores
|
// Convert all dashes into underscores
|
||||||
$title = preg_replace('![' . preg_quote('-') . ']+!u', $separator, $title);
|
$title = preg_replace('![' . preg_quote('-') . ']+!u', $separator, $title);
|
||||||
|
|
||||||
// Remove all characters that are not the separator, letters, numbers, or whitespace.
|
// Remove all characters that are not valid in a URL:
|
||||||
$title = preg_replace('![^' . preg_quote($separator) . '\pL\pN\s]+!u', '', $title);
|
// $-_.+!*'(), separator, letters, numbers, or whitespace.
|
||||||
|
$title = preg_replace('![^-' . preg_quote($separator) . '\!\'\(\),\.\+\*\$\pL\pN\s]+!u', '', $title);
|
||||||
|
|
||||||
// Replace all separator characters and whitespace by a single separator
|
// Replace all separator characters and whitespace by a single separator
|
||||||
$title = preg_replace('![' . preg_quote($separator) . '\s]+!u', $separator, $title);
|
$title = preg_replace('![' . preg_quote($separator) . '\s]+!u', $separator, $title);
|
||||||
|
@ -115,6 +115,7 @@ class Builder
|
|||||||
}
|
}
|
||||||
|
|
||||||
$uri = static::removeSortingInformations($name);
|
$uri = static::removeSortingInformations($name);
|
||||||
|
$uri = DauxHelper::slug($uri);
|
||||||
if ($config->isStatic()) {
|
if ($config->isStatic()) {
|
||||||
$uri .= '.html';
|
$uri .= '.html';
|
||||||
}
|
}
|
||||||
|
@ -20,6 +20,7 @@ class LinkRendererTest extends TestCase
|
|||||||
'Widgets' => [
|
'Widgets' => [
|
||||||
'Page.md' => 'another page',
|
'Page.md' => 'another page',
|
||||||
'Button.md' => 'another page',
|
'Button.md' => 'another page',
|
||||||
|
'Page_with_#_hash.md' => 'page with hash',
|
||||||
],
|
],
|
||||||
];
|
];
|
||||||
$root = vfsStream::setup('root', null, $structure);
|
$root = vfsStream::setup('root', null, $structure);
|
||||||
@ -38,6 +39,11 @@ class LinkRendererTest extends TestCase
|
|||||||
public function providerRenderLink()
|
public function providerRenderLink()
|
||||||
{
|
{
|
||||||
return [
|
return [
|
||||||
|
// /Widgets/Page_with_#_hash
|
||||||
|
['<a href="../Widgets/Page_with_hash.html">Link</a>', '[Link](../Widgets/Page_with_#_hash.md)', 'Content/Page.html'],
|
||||||
|
['<a href="../Widgets/Page_with_hash.html">Link</a>', '[Link](!Widgets/Page_with_#_hash)', 'Content/Page.html'],
|
||||||
|
['<a href="Page_with_hash.html">Link</a>', '[Link](Page_with_#_hash.md)', 'Widgets/Page.html'],
|
||||||
|
|
||||||
// /Widgets/Page
|
// /Widgets/Page
|
||||||
['<a href="http://google.ch" class="Link--external">Link</a>', '[Link](http://google.ch)', 'Widgets/Page.html'],
|
['<a href="http://google.ch" class="Link--external">Link</a>', '[Link](http://google.ch)', 'Widgets/Page.html'],
|
||||||
['<a href="#features">Link</a>', '[Link](#features)', 'Widgets/Page.html'],
|
['<a href="#features">Link</a>', '[Link](#features)', 'Widgets/Page.html'],
|
||||||
|
@ -82,16 +82,27 @@ class BuilderTest extends TestCase
|
|||||||
return new Root($config);
|
return new Root($config);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function testGetOrCreatePage()
|
public function providerCreatePage()
|
||||||
|
{
|
||||||
|
return [
|
||||||
|
['A Page.md', 'dir/A_Page.html', 'A_Page.html', 'A Page'],
|
||||||
|
['Page#1.md', 'dir/Page1.html', 'Page1.html', 'Page#1']
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @dataProvider providerCreatePage
|
||||||
|
*/
|
||||||
|
public function testGetOrCreatePage($file, $url, $uri, $title)
|
||||||
{
|
{
|
||||||
$directory = new Directory($this->getStaticRoot(), 'dir');
|
$directory = new Directory($this->getStaticRoot(), 'dir');
|
||||||
|
|
||||||
$entry = Builder::getOrCreatePage($directory, 'A Page.md');
|
$entry = Builder::getOrCreatePage($directory, $file);
|
||||||
|
|
||||||
$this->assertSame($directory, $entry->getParent());
|
$this->assertSame($directory, $entry->getParent());
|
||||||
$this->assertEquals('dir/A_Page.html', $entry->getUrl());
|
$this->assertEquals($url, $entry->getUrl());
|
||||||
$this->assertEquals('A_Page.html', $entry->getUri());
|
$this->assertEquals($uri, $entry->getUri());
|
||||||
$this->assertEquals('A Page', $entry->getTitle());
|
$this->assertEquals($title, $entry->getTitle());
|
||||||
$this->assertInstanceOf('Todaymade\Daux\Tree\Content', $entry);
|
$this->assertInstanceOf('Todaymade\Daux\Tree\Content', $entry);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user