-
Notifications
You must be signed in to change notification settings - Fork 91
Expand file tree
/
Copy pathIncludeFilePostprocessor.php
More file actions
103 lines (84 loc) · 2.98 KB
/
IncludeFilePostprocessor.php
File metadata and controls
103 lines (84 loc) · 2.98 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
<?php
namespace helpers\Markdown;
use helpers\Log;
/**
* Addition to Markdown to allow including remote files.
*
* Usage:
*
* {@include http://example.com/file.html}
* {@include escape http://example.com/file.html}
*
* Use the `escape` option to escape the included HTML content.
*
* This is a postprocessor, which means included content will not be parsed
* as Markdown. It will be inserted as-is in the final HTML content.
*/
class IncludeFilePostprocessor implements MarkdownParserInterface
{
/**
* Anything matching:
* - {@include <url>}
* - {@include escape <url>}
*/
const TAG_REGEX = '/\{@include( escape)? ([^\}]+)\}/';
/**
* @var MarkdownParserInterface
*/
private $wrapped;
public function __construct(MarkdownParserInterface $wrapped)
{
$this->wrapped = $wrapped;
}
public function parse($markdown)
{
$replacements = [];
// We need to replace "{@include <url>}" tags with random unique IDs
// else URLs are turned into <a> tags by the Markdown parser
$markdown = $this->replaceTagsWithUniqueIds($markdown, $replacements);
$document = $this->wrapped->parse($markdown);
$document->htmlContent = $this->replaceUniqueIdsWithFileContent($document->htmlContent, $replacements);
return $document;
}
private function replaceTagsWithUniqueIds($markdown, array &$replacements)
{
return preg_replace_callback(self::TAG_REGEX, function (array $matches) use (&$replacements) {
$uniqueId = uniqid();
$escape = ($matches[1] != null) ? true : false;
$replacements[$uniqueId] = $this->getFileContent($matches[2], $escape);
return $uniqueId;
}, $markdown);
}
private function getFileContent($url, $escape)
{
if (DISABLE_INCLUDE) {
return 'remote file inclusion disabled';
}
// Replace the placeholder with the actual domain
if (str_contains($url, '[DOCS_DOMAIN]')) {
$url = str_replace('[DOCS_DOMAIN]', DOCS_DOMAIN, $url);
}
// When necessary, convert to http for local development environments
if (str_contains($url, '[HTTPS]')) {
$protocol = DISABLE_INCLUDE_HTTPS ? 'http://' : 'https://';
$url = str_replace('[HTTPS]', $protocol, $url);
}
try {
$content = @file_get_contents($url);
if ($content) {
$content = htmlspecialchars_decode(htmlentities($content));
}
} catch (\Exception $e) {
Log::error(sprintf("Error while retrieving %s\n%s", $url, $e->getMessage()));
return 'Error while retrieving ' . htmlentities($url);
}
if ($escape) {
$content = htmlspecialchars($content);
}
return $content;
}
private function replaceUniqueIdsWithFileContent($html, array $replacements)
{
return str_replace(array_keys($replacements), array_values($replacements), $html);
}
}