render_post.php 4.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116
  1. <?php
  2. function render_post(object $current_post, string $thread_id) {
  3. $date = date("Y-m-d H:i:s", $current_post->timestamp);
  4. $date_iso8601 = date("Y-m-d\TH:i:s", $current_post->timestamp);
  5. $formatted_message = markdown_to_html(
  6. link_reference($current_post->message, $thread_id)
  7. );
  8. if (empty($current_post->email)) {
  9. $name_chunk = $current_post->name;
  10. } else {
  11. $name_chunk = "<a href=\"mailto:{$current_post->email}\">{$current_post->name}</a>";
  12. }
  13. if (isset($_GET['id'])) {
  14. $post_heading_level = '2';
  15. $post_onclick = "onclick=\"referencePost({$current_post->number}); return false;\"";
  16. } else {
  17. $post_heading_level = '3';
  18. $post_onclick = "";
  19. $formatted_message = truncate_long_post($formatted_message,
  20. $thread_id, $current_post->number);
  21. }
  22. echo "<section>";
  23. echo "<header>";
  24. echo "<h{$post_heading_level}>";
  25. echo "<a rel=\"nofollow\" {$post_onclick} href=\"/thread.php?id={$thread_id}&amp;p={$current_post->number}\">{$current_post->number}</a>";
  26. echo "</h{$post_heading_level}>";
  27. echo " <small>{$name_chunk}: <time datetime=\"{$date_iso8601}\">{$date}</time></small>";
  28. echo "</header>";
  29. echo "<p>{$formatted_message}</p>";
  30. echo "</section>";
  31. }
  32. function sanitize(string $input): string {
  33. // remove format chars
  34. $input = preg_replace('/\p{Cf}/u', '', $input);
  35. // Trim, sanitize HTML and return formatted string
  36. return htmlspecialchars(trim($input), ENT_QUOTES, 'UTF-8');
  37. };
  38. function link_reference (string $message, string $thread_id): string {
  39. // https://textboard.lol/thread.php?id=646a7fe0991da becomes a short link
  40. $message = preg_replace("|(https?://)?{$_SERVER['SERVER_NAME']}/thread\.php\?id=([0-9a-f]{13})(\s)|", '@$2$3', $message);
  41. // @6431cf2cd1b31 becomes a link to thread 6431cf2cd1b31
  42. $message = preg_replace('/@([0-9a-f]{13})([^a-z0-9\-]|$)/', '<a href="/thread.php?id=$1">@$1</a>$2', $message);
  43. // @6431cf2cd1b31->2 becomes a link to thread's 6431cf2cd1b31 second post
  44. $message = preg_replace('/@([0-9a-f]{13})-&gt;(\d+)/',
  45. "<a rel=\"nofollow\" href=\"/thread.php?id=$1&amp;p=$2\">@$1-&gt;$2</a>",
  46. $message);
  47. // >>3 becomes link to third post of the thread
  48. return preg_replace('/&gt;&gt;(\d+)/', "<a rel=\"nofollow\" href=\"/thread.php?id={$thread_id}&amp;p=$1\">&gt;&gt;$1</a>", $message);
  49. // check for non-existing post?
  50. }
  51. function markdown_to_html(string $text): string {
  52. // >quote
  53. $text = preg_replace('/(^|\r\n|\n|\r)&gt;(.*?)($|\r\n|\n|\r(?!\n))(?!(\r\n)?&gt;)(\r\n|\n|\r)*/s',
  54. '<blockquote>&gt;$2</blockquote>', $text);
  55. /*
  56. ```bash
  57. echo "code snippet"
  58. ```
  59. */
  60. $text = preg_replace('/```([a-z0-9-]{0,20})(\n|\r|\r\n)(.*?)\2```\2?/s', '<pre><code class="language-$1">$3</code></pre>', $text);
  61. /* replaces that depend on programmatic newlines
  62. should be put before this conversion
  63. */
  64. // newline
  65. $text = nl2br($text);
  66. // **bold**
  67. $text = preg_replace('/(\*\*)(?!\*)([^*]*?)(?<!\*)\1/', '<b>$2</b>', $text);
  68. // *italic*
  69. $text = preg_replace('/(\*)(?!\*)([^*]*?)(?<!\*)\1/', '<i>$2</i>', $text);
  70. // ~~strikethrough~~
  71. $text = preg_replace('/(~~)(.*?)\1/', '<del>$2</del>', $text);
  72. // __underscore__
  73. $text = preg_replace('/(__)(.*?)\1/', '<u>$2</u>', $text);
  74. // %%spoiler%%
  75. $text = preg_replace('/(%%)(.*?)\1/', '<span class="spoiler">$2</span>', $text);
  76. // teletype -- inline code
  77. $text = preg_replace('/`(?!`)(.*?)`/', '<code>$1</code>', $text);
  78. return $text;
  79. }
  80. function truncate_long_post(string $html, string $thread_id, string $post_number): string {
  81. $MAX_LINES = 10;
  82. $lines = explode('<br />', $html);
  83. if (count($lines) > $MAX_LINES) {
  84. $lines = array_slice($lines, 0, $MAX_LINES);
  85. $truncated_html = implode('<br />', $lines);
  86. $truncated_html = preg_replace('/<pre><code(.*?)>(.*)$/s', '', $truncated_html);
  87. $truncated_html = preg_replace('/<blockquote>((?:(?!<\/blockquote>).)*)$/s', '<blockquote>$1</blockquote>', $truncated_html);
  88. $truncated_html .=
  89. "<br /><br />"
  90. .
  91. "<i>(<a rel=\"nofollow\" href=\"/thread.php?id={$thread_id}&amp;p={$post_number}\">Post truncated</a>)</i>";
  92. return $truncated_html;
  93. }
  94. // Return the original HTML
  95. return $html;
  96. }
  97. ?>