"); } ?> Installation de HtmGem \n\n"; die(); } ######################################## /Installation page # Removes the headling and trailling slashes, to be sure there's not any. $filePath = rtrim($_SERVER['DOCUMENT_ROOT'], "/")."/".ltrim($url, "/"); $fileContents = @file_get_contents($filePath); ######################################## 404 page if (empty($fileContents)) { error_log("HtmGem: 404 $url $filePath"); http_response_code(404); ?> $url Recharger 🔄 => / EOF; echo translateGemToHtml($text404); echo "\n"; die(); } ######################################## /404 page # Removes the Byte Order Mark $fileContents = preg_replace("/\xEF\xBB\xBF/", "", $fileContents); /** * Replaces markups things like __underlined__ to underlined. * @param $instruction the characters to replace, ex. _ * @param $markup the markup to replace to, ex. "u" to get * @param &$text where to replace. */ function markupPreg($instruction, $markup, &$text) { $output = $text; # Replaces couples "__word__" into "word". $output = mb_ereg_replace("${instruction}(.+?)${instruction}", "<{$markup}>\\1", $output); # Replaces a remaining __ into "" to the end of the line. $output = mb_ereg_replace("${instruction}(.+)?", "<{$markup}>\\1", $output); $text = $output; } /** * Adds text attributes sucj as underline, bold, … to $line * @param $line the line to process */ function addTextAttributes(&$line) { global $textDecoration; if (!$textDecoration) return; markupPreg("__", "u", $line); markupPreg("\*\*", "strong", $line); markupPreg("//", "em", $line); markupPreg("~~", "del", $line); } /** * Prepares the raw text to be displayed in HTML environment: * * Escapes the HTML entities yet contained in the Gemtext. * * Puts thin unbrakable spaces before some characters. * @param $text1, $text2 texts to process */ function htmlPrepare(&$text) { $text = htmlspecialchars($text, ENT_HTML5|ENT_NOQUOTES, "UTF-8", false); $text = mb_ereg_replace("\ ([?!:;»€$])", NARROW_NO_BREAK_SPACE."\\1", $text); $text = mb_ereg_replace("([«])\ ", "\\1".NARROW_NO_BREAK_SPACE, $text); # Espace fine insécable # Warning: using a monospace font editor may not display dashes as they should be! # Adds no-break spaces to stick the (EM/EN dashes) to words : aaaaaa – bb – ccccc ==> aaaaaa –$bb$– ccccc $text = mb_ereg_replace("([".DASHES."]) ([^".DASHES.".]+) ([".DASHES."])", "\\1".NARROW_NO_BREAK_SPACE."\\2".NARROW_NO_BREAK_SPACE."\\3", $text); # Adds no-break space to stick the (EM/EN dashes) to words : aaaaaa – bb. ==> aaaaaa –$bb. $text = mb_ereg_replace("([—–]) ([^.]+)\.", "\\1".NARROW_NO_BREAK_SPACE."\\2.", $text); } function translateGemToHtml($fileContents) { $fileLines = preg_split("/\n/", $fileContents); if (empty($fileLines[-1])) array_pop($fileLines); # Don't output a last empty line ob_start(); $mode = null; $mode_textAttributes = true; foreach ($fileLines as $line) { $reDoCount = 0; $mode_textAttributes_temp = false; while (true) { if ($reDoCount>2) { error_log("HtmGem: Too many loops, mode == '$mode'"); $mode = null; $reDoCount = 0; break; } $reDoCount += 1; $line1 = substr($line, 0, 1); // $line can be modified $line2 = substr($line, 0, 2); // in the meantime. $line3 = substr($line, 0, 3); if (is_null($mode)) { if (empty($line)) { echo "

 

\n"; } elseif ('^^^' == $line3) { $mode_textAttributes = !$mode_textAttributes; } elseif ('^' == $line1 and !$mode_textAttributes_temp) { if (preg_match("/^\^\s*(.+)$/", $line, $parts)) { $line = $parts[1]; $mode_textAttributes_temp = true; } else { $mode = "raw"; } continue; } elseif ("#" == $line1) { if (preg_match("/^(#{1,3})\s*(.+)/", $line, $sharps)) { $h_level = strlen($sharps[1]); $text = $sharps[2]; htmlPrepare($text); switch ($h_level) { case 1: echo "

".$text."

\n"; break; case 2: echo "

".$text."

\n"; break; case 3: echo "

".$text."

\n"; break; } } else { $mode = "raw"; continue; } } elseif ("=>" == $line2) { if (preg_match("/^=>\s*([^\s]+)(?:\s+(.*))?$/", $line, $linkParts)) { $url_link = $linkParts[1]; $url_label = @$linkParts[2]; preg_match("/^([^:]+):/", $url_link, $matches); $url_protocol = @$matches[1]; if (empty($url_protocol)) $url_protocol = "local"; if (empty(trim($url_label))) { $url_label = $url_link; } else { // the label is humain-made, apply formatting htmlPrepare($url_label); if ($mode_textAttributes xor $mode_textAttributes_temp) addTextAttributes($url_label); } echo "

$url_label

\n"; } else { $mode = "raw"; continue; } } elseif ("```" == $line3) { preg_match("/^```\s*(.*)$/", $line, $matches); $alt_text = trim($matches[1]); if (empty($alt_text)) { echo "
\n";
                    } else {
                        echo "
\n";
                    }
                    $mode="pre";
                } elseif (">" == $line1) {
                    echo "
\n"; $mode = "quote"; continue; } elseif ("*" == $line1) { echo "
    \n"; $mode = "ul"; continue; } else { $mode = "raw"; continue; } } else { if ("raw"==$mode) { if (empty($line)) { $line = " "; } else { htmlPrepare($line); if ($mode_textAttributes xor $mode_textAttributes_temp) addTextAttributes($line); } echo "

    $line

    \n"; $mode = null; } elseif ("pre"==$mode) { if ("```" == $line3) { echo "
\n"; $mode = null; } else { htmlPrepare($line); echo $line."\n"; } } elseif ("quote"==$mode) { if (">" == $line1) { preg_match("/^>\s*(.*)$/", $line, $quoteParts); $quote = $quoteParts[1]; if (empty($quote)) echo "

 

\n"; else { htmlPrepare($quote); if ($mode_textAttributes xor $mode_textAttributes_temp) addTextAttributes($line); echo "

".$quote."

\n"; } } else { echo "\n"; $mode = null; continue; } } elseif ("ul"==$mode) { if ("*" == $line1) { preg_match("/^\*\s*(.*)$/", $line, $ulParts); $li = $ulParts[1]; if (empty($li)) { echo "
  •  \n"; } else { htmlPrepare($li); if ($mode_textAttributes xor $mode_textAttributes_temp) addTextAttributes($li); echo "
  • ".$li."\n"; } } else { echo "\n"; $mode = null; continue; } } else { die("Unexpected mode: $mode!"); } } break; // exits the while(true) as no continue occured } // while(true) } $html = ob_get_contents(); ob_clean(); return $html; } # Gets the page title: the first occurrence with # at the line start mb_ereg("#\s*([^\n]+)\n", $fileContents, $matches); $page_title = @$matches[1]; ###################################### CSS Management /** * if &style=source displays the source directly and stops. * if there's a filename.css besides filename.gmi, use the css and stops. * if &style= then embbed the default style, and stops. * if &style= then use htmgem/word.css * if &style=/… then use the … as as stylesheet. **/ if ("source" == $style) { $basename = basename($filePath); header("Cache-Control: public"); header("Content-Disposition: attachment; filename=$basename"); header("Content-Type: text/plain"); header("Content-Transfer-Encoding: binary"); header('Content-Length: ' . filesize($filePath)); readfile($filePath); exit(); } elseif ("pre" == $style) { $fileContents = htmlspecialchars($fileContents, ENT_HTML5|ENT_NOQUOTES, "UTF-8", false); echo << $page_title
    $fileContents
    EOL; } else { $parts = pathinfo($filePath); $localCss = $parts["filename"].".css"; $localCssFilePath = $parts["dirname"]."/".$localCss; if (file_exists($localCssFilePath)) { # Warning, using htmhem.php?url=… will make $localCss not found # as the path is relative to htmgem.php and not / ! $cssContent = ""; } else { if (empty($style)) { $cssContent = "\n"; } else { if ("none" == $style) { $cssContent = ""; } else { if ("/" == $style[0]) $href = $style; else $href = "/htmgem/css/$style.css"; $cssContent = ""; } } } echo << $page_title $cssContent EOL; echo "\n".translateGemToHtml($fileContents); echo "\n\n"; } ob_end_flush(); ?>