mirror of
https://tildegit.org/sbgodin/HtmGem.git
synced 2023-08-25 13:53:12 +02:00
Compare commits
No commits in common. "76ed024bbd7fa6304471cc81f91bed61bee3858a" and "a9fb49802a69ddc030c74da265118284fd2946ec" have entirely different histories.
76ed024bbd
...
a9fb49802a
@ -4,42 +4,24 @@ All notable changes to this project will be documented in this file.
|
|||||||
=> https://keepachangelog.com/en/1.0.0/ The format is based on keep a Changelog.
|
=> https://keepachangelog.com/en/1.0.0/ The format is based on keep a Changelog.
|
||||||
=> https://semver.org/spec/v2.0.0.html And this project adheres to Semantic Versioning.
|
=> https://semver.org/spec/v2.0.0.html And this project adheres to Semantic Versioning.
|
||||||
|
|
||||||
## [Unreleased] v2
|
## [Unreleased] v3
|
||||||
* cgi-bin? Handle user input
|
* cgi-bin? Handle user input
|
||||||
* Page caching: don’t generate twice an unmodified file.
|
* Page caching: don’t generate twice an unmodified file.
|
||||||
|
* Be able to move /htmgem anywhere and (for the Php part) outside the webbrowser scope.
|
||||||
|
|
||||||
## [Unreleased] v1
|
## [Unreleased] v2
|
||||||
|
|
||||||
### Security
|
### Security
|
||||||
∅
|
* Check unicode capability, UTF16 input, RTL/LTR, etc…
|
||||||
|
* Manage different type of carriage return: CR CR/LF LF.
|
||||||
|
|
||||||
### Development
|
### Development
|
||||||
* Proxy: https://thewebsite.tld/htmgem/proxy/[gemini://]capsule.tld/path/file.gmi
|
∅
|
||||||
|
|
||||||
### User interface
|
### User interface
|
||||||
* Images: click to load and display.
|
* Page menu on upper and lower sides: [parent dir] [root dir] [raw text].
|
||||||
* Be able to change the page style on the top bar.
|
* Images: click to display
|
||||||
* Be able to change the font size.
|
* Proxy: https://thewebsite.tld/htmgem/proxy/[gemini://]capsule.tld/path/file.gmi
|
||||||
|
|
||||||
## [1.4.0] - 2021-04-11
|
|
||||||
* Adds the breadcrumbs at the top and the bottom of the page.
|
|
||||||
* Adds the text icon H͜͡m.
|
|
||||||
* Opens the external addresses in a new window/tab.
|
|
||||||
* Changes details in the 404 page.
|
|
||||||
* Manages UTF-8, UTF-16 and UTF-32 entry format.
|
|
||||||
* FIX: adds alt text of preformated texts.
|
|
||||||
* Enables to move and rename /htmgem.
|
|
||||||
* Allows to always run without the URL rewriting.
|
|
||||||
* Many code refactorings.
|
|
||||||
|
|
||||||
## [1.3.0] - 2021-03-29
|
|
||||||
* Enables browsing without URL Rewriting
|
|
||||||
* Unit testing
|
|
||||||
* Adds the BNF definition
|
|
||||||
* Rewriting of the French documentation
|
|
||||||
* Translation to English
|
|
||||||
* Adds debug.css
|
|
||||||
* Adds index.htm in case of Php not activated
|
|
||||||
|
|
||||||
## [1.2.0] - 2021-03-19
|
## [1.2.0] - 2021-03-19
|
||||||
* Removes "^" to disable text decoration line-wise.
|
* Removes "^" to disable text decoration line-wise.
|
||||||
|
27
css/base.css
27
css/base.css
@ -2,7 +2,7 @@ html {
|
|||||||
font-family: sans-serif;
|
font-family: sans-serif;
|
||||||
}
|
}
|
||||||
|
|
||||||
#gmi {
|
body {
|
||||||
max-width: 1024px;
|
max-width: 1024px;
|
||||||
margin: auto;
|
margin: auto;
|
||||||
margin-top: 0.5em;
|
margin-top: 0.5em;
|
||||||
@ -33,26 +33,13 @@ a {
|
|||||||
text-decoration: none;
|
text-decoration: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
.menu:nth-of-type(1) .menu-line {
|
a {
|
||||||
text-align: left;
|
text-decoration: none;
|
||||||
}
|
|
||||||
.menu:nth-of-type(3) .menu-line {
|
|
||||||
text-align: right;
|
|
||||||
}
|
|
||||||
|
|
||||||
.menu a, .menu a:visited {
|
|
||||||
#color: #888;
|
|
||||||
}
|
|
||||||
.menu a:hover {
|
|
||||||
#color: #000;
|
|
||||||
}
|
|
||||||
.menu hr {
|
|
||||||
border: 1px solid lightgrey;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@media only screen and (max-width: 1024px) {
|
@media only screen and (max-width: 1024px) {
|
||||||
body {
|
body {
|
||||||
margin: 0.5rem 3rem;
|
margin: 3rem;
|
||||||
}
|
}
|
||||||
h1 {
|
h1 {
|
||||||
font-size: 4rem;
|
font-size: 4rem;
|
||||||
@ -66,10 +53,4 @@ a {
|
|||||||
p, pre, ul, blockquote {
|
p, pre, ul, blockquote {
|
||||||
font-size: 2.6rem;
|
font-size: 2.6rem;
|
||||||
}
|
}
|
||||||
.menu {
|
|
||||||
font-size: 2rem;
|
|
||||||
}
|
|
||||||
.menu hr {
|
|
||||||
border: 1px solid gray;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -17,66 +17,47 @@ blockquote {
|
|||||||
padding: 1rem;
|
padding: 1rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
.menu a, .menu a:visited {
|
a {
|
||||||
color: #888;
|
margin: -1.35rem;
|
||||||
}
|
|
||||||
|
|
||||||
.menu a:hover {
|
|
||||||
color: #000;
|
|
||||||
}
|
|
||||||
|
|
||||||
.menu hr {
|
|
||||||
color: white;
|
|
||||||
}
|
|
||||||
|
|
||||||
#gmi a {
|
|
||||||
margin: -0.7rem;
|
|
||||||
color:#820;
|
color:#820;
|
||||||
}
|
}
|
||||||
|
|
||||||
#gmi a:before {
|
a:before {
|
||||||
content: "🔗 ";
|
content: "🔗 ";
|
||||||
}
|
}
|
||||||
|
|
||||||
#gmi a:visited {
|
a:visited {
|
||||||
color: #868;
|
color: #868;
|
||||||
}
|
}
|
||||||
|
|
||||||
#gmi a.local:before {
|
a.local:before {
|
||||||
content: "🛩️ ";
|
content: "🛩️ ";
|
||||||
font-weight: bold;
|
font-weight: bold;
|
||||||
}
|
}
|
||||||
|
|
||||||
#gmi a.gemini:before {
|
a.gemini:before {
|
||||||
content: "🚀 ";
|
content: "🚀 ";
|
||||||
}
|
}
|
||||||
|
|
||||||
#gmi a.gopher:before {
|
a.gopher:before {
|
||||||
content: "📜 ";
|
content: "📜 ";
|
||||||
}
|
}
|
||||||
|
|
||||||
#gmi a.https:before {
|
a.https:before {
|
||||||
content: "🕸️ ";
|
content: "🕸️ ";
|
||||||
font-weight: bolder;
|
font-weight: bolder;
|
||||||
}
|
}
|
||||||
|
|
||||||
#gmi a.http:before {
|
a.http:before {
|
||||||
content: "🕸️ ";
|
content: "🕸️ ";
|
||||||
font-weight: lighter;
|
font-weight: lighter;
|
||||||
}
|
}
|
||||||
|
|
||||||
#gmi a.mumble:before {
|
a.mumble:before {
|
||||||
content: "🎤 ";
|
content: "🎤 ";
|
||||||
}
|
}
|
||||||
|
|
||||||
#gmi a.mailto:before {
|
a.mailto:before {
|
||||||
content: "✉️ ";
|
content: "✉️ ";
|
||||||
}
|
}
|
||||||
|
|
||||||
@media only screen and (max-width: 1024px) {
|
|
||||||
|
|
||||||
#gmi a {
|
|
||||||
margin: -2.9rem;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
49
index.php
49
index.php
@ -4,11 +4,7 @@ require_once "lib-htmgem.inc.php";
|
|||||||
require_once "lib-html.inc.php";
|
require_once "lib-html.inc.php";
|
||||||
require_once "lib-io.inc.php";
|
require_once "lib-io.inc.php";
|
||||||
|
|
||||||
$documentRoot = $_SERVER['DOCUMENT_ROOT'];
|
# The url argument is always absolute compared to the document root.
|
||||||
$scheme = (@$_SERVER['REQUEST_SCHEME']??"http")."://";
|
|
||||||
$domain = $_SERVER['HTTP_HOST'];
|
|
||||||
$php_self = $_SERVER['PHP_SELF']; // by default: /htmgem/index.php
|
|
||||||
$php_self_dir = dirname($php_self);
|
|
||||||
$url = @$_REQUEST["url"];
|
$url = @$_REQUEST["url"];
|
||||||
$urlRewriting = @$_REQUEST["rw"]=="1";
|
$urlRewriting = @$_REQUEST["rw"]=="1";
|
||||||
|
|
||||||
@ -22,21 +18,18 @@ $urlRewriting = @$_REQUEST["rw"]=="1";
|
|||||||
if (empty($url)) {
|
if (empty($url)) {
|
||||||
if (!file_exists("index.gmi")) {
|
if (!file_exists("index.gmi")) {
|
||||||
http_response_code(403);
|
http_response_code(403);
|
||||||
} else {
|
die("<!-- index.gmi missing -->");
|
||||||
$gt_html = new \htmgem\GemTextTranslate_html(file_get_contents("index.gmi"), true, "$php_self?url=", $php_self_dir);
|
|
||||||
if (empty($gt_html->getCss)) $gt_html->addCss($php_self_dir."/css/htmgem.css");
|
|
||||||
|
|
||||||
// No URL Rewritting assumed
|
|
||||||
echo \htmgem\html\getHtmlWithMenu($gt_html, $scheme, $domain, $php_self, "$php_self?url=");
|
|
||||||
}
|
}
|
||||||
|
$gt_html = new \htmgem\GemTextTranslate_html(@file_get_contents("index.gmi"), true, "/htmgem");
|
||||||
|
echo \htmgem\html\getFullHtml($gt_html);
|
||||||
exit();
|
exit();
|
||||||
}
|
}
|
||||||
|
|
||||||
$url = \htmgem\resolve_path(
|
$documentRoot = $_SERVER['DOCUMENT_ROOT'];
|
||||||
// Some webservers (Apache) don't add the slash
|
|
||||||
// while others (Nginx) do…
|
/**
|
||||||
( $url[0] == "/" ? "" : "/" ) . $url
|
* Provides index.gmi if no page given
|
||||||
);
|
*/
|
||||||
if (!preg_match("/\.gmi$/", $url)) {
|
if (!preg_match("/\.gmi$/", $url)) {
|
||||||
if ($url[-1] == "/")
|
if ($url[-1] == "/")
|
||||||
$url = $url."index.gmi";
|
$url = $url."index.gmi";
|
||||||
@ -62,13 +55,9 @@ switch(true) {
|
|||||||
if ($go404) {
|
if ($go404) {
|
||||||
error_log("HtmGem: 404 $url $filePath");
|
error_log("HtmGem: 404 $url $filePath");
|
||||||
http_response_code(404);
|
http_response_code(404);
|
||||||
$page404 = \htmgem\html\get404GmiPage($url);
|
$page404 = \htmgem\html\get404GmiPage("Page not found", $url);
|
||||||
$gt_html = new \htmgem\GemTextTranslate_html($page404);
|
$gt_html = new \htmgem\GemTextTranslate_html($page404);
|
||||||
if (empty($gt_html->getCss)) $gt_html->addCss($php_self_dir."/css/htmgem.css");
|
echo \htmgem\html\getFullHtml($gt_html);
|
||||||
if ($urlRewriting)
|
|
||||||
echo \htmgem\html\getHtmlWithMenu($gt_html, $scheme, $domain, $url);
|
|
||||||
else
|
|
||||||
echo \htmgem\html\getHtmlWithMenu($gt_html, $scheme, $domain, $url, "$php_self?url=");
|
|
||||||
exit();
|
exit();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -112,12 +101,12 @@ EOL;
|
|||||||
}
|
}
|
||||||
|
|
||||||
if ($urlRewriting)
|
if ($urlRewriting)
|
||||||
$gt_html = new \htmgem\GemTextTranslate_html($fileContents, $gt_htmlextDecoration);
|
$baseUrl = null;
|
||||||
else
|
else
|
||||||
$gt_html = new \htmgem\GemTextTranslate_html($fileContents, $gt_htmlextDecoration, "$php_self?url=", dirname($url));
|
$baseUrl = dirname($url);
|
||||||
|
$gt_html = new \htmgem\GemTextTranslate_html($fileContents, $gt_htmlextDecoration, $baseUrl);
|
||||||
if ("none" == $style) {
|
if ("none" == $style) {
|
||||||
#$gt_html->addCss("");
|
$gt_html->addCss("");
|
||||||
} elseif ("/" == @$style[0]) {
|
} elseif ("/" == @$style[0]) {
|
||||||
$gt_html->addCss($style);
|
$gt_html->addCss($style);
|
||||||
} elseif (empty($style)) {
|
} elseif (empty($style)) {
|
||||||
@ -130,13 +119,9 @@ if ("none" == $style) {
|
|||||||
$gt_html->addCss($localCss);
|
$gt_html->addCss($localCss);
|
||||||
}
|
}
|
||||||
} else { #TODO: regex check for $style
|
} else { #TODO: regex check for $style
|
||||||
$gt_html->addCss("$php_self_dir/css/$style.css");
|
$gt_html->addCss("/htmgem/css/$style.css");
|
||||||
}
|
}
|
||||||
if (empty($gt_html->getCss)) $gt_html->addCss($php_self_dir."/css/htmgem.css");
|
|
||||||
|
|
||||||
if ($urlRewriting)
|
echo \htmgem\html\getFullHtml($gt_html);
|
||||||
echo \htmgem\html\getHtmlWithMenu($gt_html, $scheme, $domain, $url);
|
|
||||||
else
|
|
||||||
echo \htmgem\html\getHtmlWithMenu($gt_html, $scheme, $domain, $url, "$php_self?url=");
|
|
||||||
|
|
||||||
?>
|
?>
|
||||||
|
@ -5,55 +5,6 @@ namespace htmgem;
|
|||||||
mb_internal_encoding("UTF-8");
|
mb_internal_encoding("UTF-8");
|
||||||
mb_regex_encoding("UTF-8");
|
mb_regex_encoding("UTF-8");
|
||||||
|
|
||||||
/**
|
|
||||||
* Resolve $path interpretating / . and ..
|
|
||||||
* @param $path str
|
|
||||||
* @returns "/" if .. goes above the limit
|
|
||||||
*/
|
|
||||||
function resolve_path($path) {
|
|
||||||
if (empty($path)) return "";
|
|
||||||
$absolute = "/"==$path[0];
|
|
||||||
$parts = array_filter(explode("/", $path), 'strlen');
|
|
||||||
$chuncks = array();
|
|
||||||
foreach ($parts as $part) {
|
|
||||||
if ('.' == $part) continue;
|
|
||||||
if ('..' == $part) {
|
|
||||||
if (is_null(array_pop($chuncks))) return "/";
|
|
||||||
} else {
|
|
||||||
$chuncks[] = $part;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
$output = implode("/", $chuncks);
|
|
||||||
if ($absolute) $output = "/".$output;
|
|
||||||
return $output;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Splits link (without .. or .) into parts along with direct url access.
|
|
||||||
* @param url
|
|
||||||
*
|
|
||||||
* Ex. /dir1/dir2/page.gmi
|
|
||||||
* --> "dir1" --> "/dir1"
|
|
||||||
* --> "dir2" --> "/dir1/dir2"
|
|
||||||
* --> "page.gmi" --> "/dir2/page.gmi"
|
|
||||||
*/
|
|
||||||
function split_path_links($path, $prefix="") {
|
|
||||||
$parts = array_filter(explode("/", $path), 'strlen');
|
|
||||||
if (empty($parts)) return array();
|
|
||||||
if ("/"==$path[0])
|
|
||||||
$stack = "/";
|
|
||||||
else
|
|
||||||
$stack = "";
|
|
||||||
$output = array();
|
|
||||||
$slash = "";
|
|
||||||
foreach ($parts as $part) {
|
|
||||||
$stack .= $slash.$part;
|
|
||||||
$output[$part] = $prefix.$stack;
|
|
||||||
$slash = "/";
|
|
||||||
}
|
|
||||||
return $output;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Parses the gemtext and generates the internal format version
|
* Parses the gemtext and generates the internal format version
|
||||||
* @param str $fileContents the gemtext to parse
|
* @param str $fileContents the gemtext to parse
|
||||||
@ -61,7 +12,7 @@ function split_path_links($path, $prefix="") {
|
|||||||
function gemtextParser($fileContents) {
|
function gemtextParser($fileContents) {
|
||||||
if (empty($fileContents)) return array();
|
if (empty($fileContents)) return array();
|
||||||
$fileContents = rtrim($fileContents); // removes last empty line
|
$fileContents = rtrim($fileContents); // removes last empty line
|
||||||
$fileLines = mb_split("\n|\r\n?", $fileContents); // Unix, Mac, Windows line feeds
|
$fileLines = mb_split("\R", $fileContents); // Unix, Mac, Windows line feeds
|
||||||
$mode = null;
|
$mode = null;
|
||||||
$current = array();
|
$current = array();
|
||||||
foreach ($fileLines as $line) {
|
foreach ($fileLines as $line) {
|
||||||
@ -231,15 +182,8 @@ class GemtextTranslate_html {
|
|||||||
protected $pageTitle = "";
|
protected $pageTitle = "";
|
||||||
public $translatedGemtext;
|
public $translatedGemtext;
|
||||||
|
|
||||||
/**
|
function __construct($parsedGemtext, $textDecoration=true, $baseUrl=Null) {
|
||||||
* @param $parsedGemtext the gemtext internal format
|
$this->baseUrl = $baseUrl;
|
||||||
* @param $textDecoration bool to interpret or not the text decoration
|
|
||||||
* @param $urlPrefix the prefix to prepend if the URL rewriting is not on
|
|
||||||
* @param $currentPageDir the current directory, to be used without URL rewriting
|
|
||||||
*/
|
|
||||||
function __construct($parsedGemtext, $textDecoration=true, $urlPrefix=null, $currentPageDir=null) {
|
|
||||||
$this->urlPrefix = $urlPrefix;
|
|
||||||
$this->currentPageDir = $currentPageDir;
|
|
||||||
if (empty($parsedGemtext)) $parsedGemtext = "";
|
if (empty($parsedGemtext)) $parsedGemtext = "";
|
||||||
// to delete the last empty lines
|
// to delete the last empty lines
|
||||||
$parsedGemtext = rtrim($parsedGemtext);
|
$parsedGemtext = rtrim($parsedGemtext);
|
||||||
@ -322,6 +266,29 @@ class GemtextTranslate_html {
|
|||||||
$text = preg_replace("/ +/", " ", $text);
|
$text = preg_replace("/ +/", " ", $text);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Resolve $path interpretating / . and ..
|
||||||
|
* @param $path str
|
||||||
|
* @returns "/" if .. goes above the limit
|
||||||
|
*/
|
||||||
|
public static function resolve_path($path) {
|
||||||
|
if (empty($path)) return "";
|
||||||
|
$absolute = "/"==$path[0];
|
||||||
|
$parts = array_filter(explode("/", $path), 'strlen');
|
||||||
|
$chuncks = array();
|
||||||
|
foreach ($parts as $part) {
|
||||||
|
if ('.' == $part) continue;
|
||||||
|
if ('..' == $part) {
|
||||||
|
if (is_null(array_pop($chuncks))) return "/";
|
||||||
|
} else {
|
||||||
|
$chuncks[] = $part;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
$output = implode("/", $chuncks);
|
||||||
|
if ($absolute) $output = "/".$output;
|
||||||
|
return $output;
|
||||||
|
}
|
||||||
|
|
||||||
public function translate($textDecoration=true) {
|
public function translate($textDecoration=true) {
|
||||||
$output = "";
|
$output = "";
|
||||||
foreach ($this->parsedGemtext as $node) {
|
foreach ($this->parsedGemtext as $node) {
|
||||||
@ -377,10 +344,10 @@ class GemtextTranslate_html {
|
|||||||
preg_match("/^([^:]+):/", $link, $matches);
|
preg_match("/^([^:]+):/", $link, $matches);
|
||||||
$protocol = @$matches[1]??"local";
|
$protocol = @$matches[1]??"local";
|
||||||
if ("local"==$protocol) {
|
if ("local"==$protocol) {
|
||||||
if (!is_null($this->urlPrefix)) { // No URL rewriting
|
if (!is_null($this->baseUrl)) { // No URL rewriting
|
||||||
$link = $this->currentPageDir."/".$link;
|
if ($link[0]!="/") $link = "{$this->baseUrl}/$link";
|
||||||
$link = resolve_path($link);
|
$link = self::resolve_path($link);
|
||||||
$link = $this->urlPrefix.$link;
|
$link = "/htmgem/index.php?url=$link";
|
||||||
}
|
}
|
||||||
$newWindow = "";
|
$newWindow = "";
|
||||||
} else {
|
} else {
|
||||||
|
@ -5,10 +5,12 @@ namespace htmgem\html;
|
|||||||
mb_internal_encoding("UTF-8");
|
mb_internal_encoding("UTF-8");
|
||||||
mb_regex_encoding("UTF-8");
|
mb_regex_encoding("UTF-8");
|
||||||
|
|
||||||
$txt_icon = "H͜͡m ";
|
/**
|
||||||
|
* Returns a full HTML page base
|
||||||
function getHeader(\htmgem\GemtextTranslate_html $gt_html) {
|
*/
|
||||||
|
function getFullHtml(\htmgem\GemtextTranslate_html $gt_html) {
|
||||||
$css = $gt_html->getCss();
|
$css = $gt_html->getCss();
|
||||||
|
if (!$css) $css = array("/htmgem/css/htmgem.css");
|
||||||
$output = <<<EOL
|
$output = <<<EOL
|
||||||
<!DOCTYPE html>
|
<!DOCTYPE html>
|
||||||
<html lang="">
|
<html lang="">
|
||||||
@ -21,76 +23,21 @@ EOL;
|
|||||||
}
|
}
|
||||||
$output .= <<<EOL
|
$output .= <<<EOL
|
||||||
</head>
|
</head>
|
||||||
|
<body>\n
|
||||||
EOL;
|
EOL;
|
||||||
|
$output .= $gt_html->translatedGemtext;
|
||||||
|
$output .= "</body>\n</html>\n";
|
||||||
|
|
||||||
return $output;
|
return $output;
|
||||||
}
|
}
|
||||||
|
|
||||||
function array_key_last_slice($array) {
|
function get404Gmipage($message, $url) {
|
||||||
// array_key_last() only available as of php v7.3.0
|
|
||||||
return key(array_slice($array, -1));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param $url the full URL to display
|
|
||||||
* @param $pageLink if not null, means no URL rewritting
|
|
||||||
*/
|
|
||||||
function getMenu(string $scheme, string $domain, string $path, string $prefix=null) {
|
|
||||||
global $txt_icon;
|
|
||||||
$links = \htmgem\split_path_links($path, $prefix);
|
|
||||||
|
|
||||||
// Removes the last part, as it won't hold a link
|
|
||||||
$lastLink = array_key_last_slice($links);
|
|
||||||
if ("index.gmi"==$lastLink) {
|
|
||||||
// removes the index page
|
|
||||||
array_pop($links);
|
|
||||||
$lastLink = array_key_last_slice($links);
|
|
||||||
}
|
|
||||||
array_pop($links);
|
|
||||||
|
|
||||||
$links = array($domain => "$prefix/") + $links;
|
|
||||||
$linkList = array();
|
|
||||||
foreach ($links as $label=>$link) {
|
|
||||||
$linkList []= "<a href='$link'>$label</a>\n";
|
|
||||||
}
|
|
||||||
$linkList [] = $lastLink."\n"; // The last part holds no link
|
|
||||||
$output = "<div class='menu-line'>\n";
|
|
||||||
$output .= "<strong>$txt_icon</strong>$scheme\n";
|
|
||||||
$output .= implode(" / ", $linkList);
|
|
||||||
$output .= "</div>\n";
|
|
||||||
return $output;
|
|
||||||
}
|
|
||||||
|
|
||||||
function getFooter(\htmgem\GemtextTranslate_html $gt_html) {
|
|
||||||
return "</body>\n</html>\n";
|
|
||||||
}
|
|
||||||
|
|
||||||
function getHtmlWithMenu($gt_html, $scheme, $domain, $path, $prefix=null) {
|
|
||||||
$menu = getMenu($scheme, $domain, $path, $prefix);
|
|
||||||
echo getHeader($gt_html);
|
|
||||||
echo "<body>\n";
|
|
||||||
echo "<div class='menu'>\n";
|
|
||||||
echo $menu;
|
|
||||||
echo "<hr>\n";
|
|
||||||
echo "</div>\n";
|
|
||||||
echo "<div id='gmi'>\n";
|
|
||||||
echo $gt_html->translatedGemtext;
|
|
||||||
echo "</div>\n";
|
|
||||||
echo "<div class='menu'>\n";
|
|
||||||
echo "<hr>\n";
|
|
||||||
echo $menu;
|
|
||||||
echo "</div>\n";
|
|
||||||
echo getFooter($gt_html);
|
|
||||||
}
|
|
||||||
|
|
||||||
function get404Gmipage($url) {
|
|
||||||
return <<<EOF
|
return <<<EOF
|
||||||
# ⚠ $url ⚠
|
# ⚠ $message
|
||||||
|
|
||||||
* **Page non trouvée**
|
|
||||||
* **Page not found**
|
|
||||||
|
|
||||||
|
**$url**
|
||||||
|
|
||||||
|
=> .. 🔄 🔄
|
||||||
EOF;
|
EOF;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -5,133 +5,89 @@ require_once dirname(__FILE__)."/../lib-htmgem.inc.php";
|
|||||||
|
|
||||||
final class miscTest extends TestCase {
|
final class miscTest extends TestCase {
|
||||||
|
|
||||||
public function test_split_path_links(): void {
|
public function test_resolveLink(): void {
|
||||||
$this->assertSame(
|
$this->assertSame(
|
||||||
array(),
|
\htmgem\GemtextTranslate_html::resolve_path(""),
|
||||||
\htmgem\split_path_links(""),
|
|
||||||
"empty link"
|
|
||||||
);
|
|
||||||
$this->assertSame(
|
|
||||||
array(
|
|
||||||
"noslash" => "noslash",
|
|
||||||
),
|
|
||||||
\htmgem\split_path_links("noslash"),
|
|
||||||
"no slash"
|
|
||||||
);
|
|
||||||
$this->assertSame(
|
|
||||||
array(),
|
|
||||||
\htmgem\split_path_links("/"),
|
|
||||||
"only a slash"
|
|
||||||
);
|
|
||||||
$this->assertSame(
|
|
||||||
array(
|
|
||||||
"one" => "/one",
|
|
||||||
),
|
|
||||||
\htmgem\split_path_links("/one"),
|
|
||||||
"/one"
|
|
||||||
);
|
|
||||||
$this->assertSame(
|
|
||||||
array(
|
|
||||||
"one" => "one",
|
|
||||||
"two" => "one/two",
|
|
||||||
),
|
|
||||||
\htmgem\split_path_links("one/two"),
|
|
||||||
"one/two"
|
|
||||||
);
|
|
||||||
$this->assertSame(
|
|
||||||
array(
|
|
||||||
"one" => "/one",
|
|
||||||
"two" => "/one/two",
|
|
||||||
"file.ext" => "/one/two/file.ext",
|
|
||||||
),
|
|
||||||
\htmgem\split_path_links("/one/two/file.ext"),
|
|
||||||
"/one/two/file.ext"
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
public function test_resolve_path(): void {
|
|
||||||
$this->assertSame(
|
|
||||||
\htmgem\resolve_path(""),
|
|
||||||
"",
|
"",
|
||||||
"empty link"
|
"empty link"
|
||||||
);
|
);
|
||||||
$this->assertSame(
|
$this->assertSame(
|
||||||
\htmgem\resolve_path("test"),
|
\htmgem\GemtextTranslate_html::resolve_path("test"),
|
||||||
"test",
|
"test",
|
||||||
"single word"
|
"single word"
|
||||||
);
|
);
|
||||||
$this->assertSame(
|
$this->assertSame(
|
||||||
\htmgem\resolve_path(" "),
|
\htmgem\GemtextTranslate_html::resolve_path(" "),
|
||||||
" ",
|
" ",
|
||||||
"single space"
|
"single space"
|
||||||
);
|
);
|
||||||
$this->assertSame(
|
$this->assertSame(
|
||||||
\htmgem\resolve_path(" A B "),
|
\htmgem\GemtextTranslate_html::resolve_path(" A B "),
|
||||||
" A B ",
|
" A B ",
|
||||||
"several space"
|
"several space"
|
||||||
);
|
);
|
||||||
$this->assertSame(
|
$this->assertSame(
|
||||||
\htmgem\resolve_path("/"),
|
\htmgem\GemtextTranslate_html::resolve_path("/"),
|
||||||
"/",
|
"/",
|
||||||
"one slash"
|
"one slash"
|
||||||
);
|
);
|
||||||
$this->assertSame(
|
$this->assertSame(
|
||||||
\htmgem\resolve_path("//"),
|
\htmgem\GemtextTranslate_html::resolve_path("//"),
|
||||||
"/",
|
"/",
|
||||||
"two slashes"
|
"two slashes"
|
||||||
);
|
);
|
||||||
$this->assertSame(
|
$this->assertSame(
|
||||||
\htmgem\resolve_path("/////"),
|
\htmgem\GemtextTranslate_html::resolve_path("/////"),
|
||||||
"/",
|
"/",
|
||||||
"five slashes"
|
"five slashes"
|
||||||
);
|
);
|
||||||
$this->assertSame(
|
$this->assertSame(
|
||||||
\htmgem\resolve_path("one/"),
|
\htmgem\GemtextTranslate_html::resolve_path("one/"),
|
||||||
"one",
|
"one",
|
||||||
"strip the last slash"
|
"strip the last slash"
|
||||||
);
|
);
|
||||||
$this->assertSame(
|
$this->assertSame(
|
||||||
\htmgem\resolve_path("/two"),
|
\htmgem\GemtextTranslate_html::resolve_path("/two"),
|
||||||
"/two",
|
"/two",
|
||||||
"slash at the beginning"
|
"slash at the beginning"
|
||||||
);
|
);
|
||||||
$this->assertSame(
|
$this->assertSame(
|
||||||
\htmgem\resolve_path("/two/"),
|
\htmgem\GemtextTranslate_html::resolve_path("/two/"),
|
||||||
"/two",
|
"/two",
|
||||||
"slash at the beginning and the end"
|
"slash at the beginning and the end"
|
||||||
);
|
);
|
||||||
$this->assertSame(
|
$this->assertSame(
|
||||||
\htmgem\resolve_path("one/two/"),
|
\htmgem\GemtextTranslate_html::resolve_path("one/two/"),
|
||||||
"one/two",
|
"one/two",
|
||||||
"only the last slash remains"
|
"only the last slash remains"
|
||||||
);
|
);
|
||||||
$this->assertSame(
|
$this->assertSame(
|
||||||
\htmgem\resolve_path("one/two/three//"),
|
\htmgem\GemtextTranslate_html::resolve_path("one/two/three//"),
|
||||||
"one/two/three",
|
"one/two/three",
|
||||||
"strip the last slashes"
|
"strip the last slashes"
|
||||||
);
|
);
|
||||||
$this->assertSame(
|
$this->assertSame(
|
||||||
\htmgem\resolve_path("one/../"),
|
\htmgem\GemtextTranslate_html::resolve_path("one/../"),
|
||||||
"",
|
"",
|
||||||
"empty one"
|
"empty one"
|
||||||
);
|
);
|
||||||
$this->assertSame(
|
$this->assertSame(
|
||||||
\htmgem\resolve_path("one/two/../"),
|
\htmgem\GemtextTranslate_html::resolve_path("one/two/../"),
|
||||||
"one",
|
"one",
|
||||||
"empty one two"
|
"empty one two"
|
||||||
);
|
);
|
||||||
$this->assertSame(
|
$this->assertSame(
|
||||||
\htmgem\resolve_path("one/two/../.."),
|
\htmgem\GemtextTranslate_html::resolve_path("one/two/../.."),
|
||||||
"",
|
"",
|
||||||
"empty one two twice"
|
"empty one two twice"
|
||||||
);
|
);
|
||||||
$this->assertSame(
|
$this->assertSame(
|
||||||
\htmgem\resolve_path("one/../two/./../three"),
|
\htmgem\GemtextTranslate_html::resolve_path("one/../two/./../three"),
|
||||||
"three",
|
"three",
|
||||||
"waltz"
|
"waltz"
|
||||||
);
|
);
|
||||||
$this->assertSame(
|
$this->assertSame(
|
||||||
\htmgem\resolve_path("one/../.."),
|
\htmgem\GemtextTranslate_html::resolve_path("one/../.."),
|
||||||
"/",
|
"/",
|
||||||
"directory traversal"
|
"directory traversal"
|
||||||
);
|
);
|
||||||
|
Loading…
Reference in New Issue
Block a user