The version of vichan running on lainchan.org
Vous ne pouvez pas sélectionner plus de 25 sujets Les noms de sujets doivent commencer par une lettre ou un nombre, peuvent contenir des tirets ('-') et peuvent comporter jusqu'à 35 caractères.

424 lignes
12KB

  1. <?php
  2. /*
  3. * Copyright (c) 2010-2013 Tinyboard Development Group
  4. */
  5. if (realpath($_SERVER['SCRIPT_FILENAME']) == str_replace('\\', '/', __FILE__)) {
  6. // You cannot request this file directly.
  7. exit;
  8. }
  9. /*
  10. joaoptm78@gmail.com
  11. http://www.php.net/manual/en/function.filesize.php#100097
  12. */
  13. function format_bytes($size) {
  14. $units = array(' B', ' KB', ' MB', ' GB', ' TB');
  15. for ($i = 0; $size >= 1024 && $i < 4; $i++) $size /= 1024;
  16. return round($size, 2).$units[$i];
  17. }
  18. function doBoardListPart($list, $root, &$boards) {
  19. global $config;
  20. $body = '';
  21. foreach ($list as $key => $board) {
  22. if (is_array($board))
  23. $body .= ' <span class="sub" data-description="' . $key . '">[' . doBoardListPart($board, $root, $boards) . ']</span> ';
  24. else {
  25. if (gettype($key) == 'string') {
  26. $body .= ' <a href="' . $board . '">' . $key . '</a> /';
  27. } else {
  28. $title = '';
  29. if (array_key_exists($board,$config['boards_alias'])){
  30. $actual_board = $config['boards_alias'][$board];
  31. if (isset ($boards[$actual_board])) {
  32. $title = ' title="'.$boards[$actual_board].'"';
  33. }
  34. $body .= ' <a href="' . $root . $actual_board . '/' . $config['file_index'] . '"'.$title.'>' . $board . '</a> /';
  35. }
  36. else
  37. {
  38. if (isset ($boards[$board])) {
  39. $title = ' title="'.$boards[$board].'"';
  40. }
  41. $body .= ' <a href="' . $root . $board . '/' . $config['file_index'] . '"'.$title.'>' . $board . '</a> /';
  42. }
  43. }
  44. }
  45. }
  46. $body = preg_replace('/\/$/', '', $body);
  47. return $body;
  48. }
  49. function createBoardlist($mod=false) {
  50. global $config;
  51. if (!isset($config['boards'])) return array('top'=>'','bottom'=>'');
  52. $xboards = listBoards();
  53. $boards = array();
  54. foreach ($xboards as $val) {
  55. $boards[$val['uri']] = $val['title'];
  56. }
  57. $body = doBoardListPart($config['boards'], $mod?'?/':$config['root'], $boards);
  58. if ($config['boardlist_wrap_bracket'] && !preg_match('/\] $/', $body))
  59. $body = '[' . $body . ']';
  60. $body = trim($body);
  61. // Message compact-boardlist.js faster, so that page looks less ugly during loading
  62. $top = "<script type='text/javascript'>if (typeof do_boardlist != 'undefined') do_boardlist();</script>";
  63. return array(
  64. 'top' => '<div class="boardlist">' . $body . '</div>' . $top,
  65. 'bottom' => '<div class="boardlist bottom">' . $body . '</div>'
  66. );
  67. }
  68. function loginForm($error=false, $username=false, $redirect=false) {
  69. global $config;
  70. die(Element('page.html', array(
  71. 'index' => $config['root'],
  72. 'title' => _('Login'),
  73. 'config' => $config,
  74. 'body' => Element('login.html', array(
  75. 'config'=>$config,
  76. 'error'=>$error,
  77. 'username'=>utf8tohtml($username),
  78. 'redirect'=>$redirect
  79. )
  80. )
  81. )));
  82. }
  83. function pm_snippet($body, $len=null) {
  84. global $config;
  85. if (!isset($len))
  86. $len = &$config['mod']['snippet_length'];
  87. // Replace line breaks with some whitespace
  88. $body = preg_replace('@<br/?>@i', ' ', $body);
  89. // Strip tags but leave span tags which contain spoiler
  90. $body_with_spoiler_tags = strip_tags($body,'<span>');
  91. // Check for spoiler tags
  92. $spoiler = preg_match("/spoiler/", $body_with_spoiler_tags);
  93. // Strip tags
  94. $body = strip_tags($body);
  95. // Unescape HTML characters, to avoid splitting them in half
  96. $body = html_entity_decode($body, ENT_COMPAT, 'UTF-8');
  97. // calculate strlen() so we can add "..." after if needed
  98. $strlen = mb_strlen($body);
  99. $body = mb_substr($body, 0, $len);
  100. if ($spoiler){
  101. $value = "<span class=\"spoiler\">" . utf8tohtml($body) . "</span>";
  102. }
  103. else {
  104. $value = utf8tohtml($body);
  105. }
  106. // Re-escape the characters.
  107. return '<em>' . utf8tohtml($body) . ($strlen > $len ? '&hellip;' : '') . '</em>';
  108. }
  109. function capcode($cap) {
  110. global $config;
  111. if (!$cap)
  112. return false;
  113. $capcode = array();
  114. if (isset($config['custom_capcode'][$cap])) {
  115. if (is_array($config['custom_capcode'][$cap])) {
  116. $capcode['cap'] = sprintf($config['custom_capcode'][$cap][0], $cap);
  117. if (isset($config['custom_capcode'][$cap][1]))
  118. $capcode['name'] = $config['custom_capcode'][$cap][1];
  119. if (isset($config['custom_capcode'][$cap][2]))
  120. $capcode['trip'] = $config['custom_capcode'][$cap][2];
  121. } else {
  122. $capcode['cap'] = sprintf($config['custom_capcode'][$cap], $cap);
  123. }
  124. } else {
  125. $capcode['cap'] = sprintf($config['capcode'], $cap);
  126. }
  127. return $capcode;
  128. }
  129. function truncate($body, $url, $max_lines = false, $max_chars = false) {
  130. global $config;
  131. if ($max_lines === false)
  132. $max_lines = $config['body_truncate'];
  133. if ($max_chars === false)
  134. $max_chars = $config['body_truncate_char'];
  135. // We don't want to risk truncating in the middle of an HTML comment.
  136. // It's easiest just to remove them all first.
  137. $body = preg_replace('/<!--.*?-->/s', '', $body);
  138. $original_body = $body;
  139. $lines = substr_count($body, '<br/>');
  140. // Limit line count
  141. if ($lines > $max_lines) {
  142. if (preg_match('/(((.*?)<br\/>){' . $max_lines . '})/', $body, $m))
  143. $body = $m[0];
  144. }
  145. $body = mb_substr($body, 0, $max_chars);
  146. if ($body != $original_body) {
  147. // Remove any corrupt tags at the end
  148. $body = preg_replace('/<([\w]+)?([^>]*)?$/', '', $body);
  149. // Open tags
  150. if (preg_match_all('/<([\w]+)[^>]*>/', $body, $open_tags)) {
  151. $tags = array();
  152. for ($x=0;$x<count($open_tags[0]);$x++) {
  153. if (!preg_match('/\/(\s+)?>$/', $open_tags[0][$x]))
  154. $tags[] = $open_tags[1][$x];
  155. }
  156. // List successfully closed tags
  157. if (preg_match_all('/(<\/([\w]+))>/', $body, $closed_tags)) {
  158. for ($x=0;$x<count($closed_tags[0]);$x++) {
  159. unset($tags[array_search($closed_tags[2][$x], $tags)]);
  160. }
  161. }
  162. // remove broken HTML entity at the end (if existent)
  163. $body = preg_replace('/&[^;]+$/', '', $body);
  164. $tags_no_close_needed = array("colgroup", "dd", "dt", "li", "optgroup", "option", "p", "tbody", "td", "tfoot", "th", "thead", "tr", "br", "img");
  165. // Close any open tags
  166. foreach ($tags as &$tag) {
  167. if (!in_array($tag, $tags_no_close_needed))
  168. $body .= "</{$tag}>";
  169. }
  170. } else {
  171. // remove broken HTML entity at the end (if existent)
  172. $body = preg_replace('/&[^;]*$/', '', $body);
  173. }
  174. $body .= '<span class="toolong">'.sprintf(_('Post too long. Click <a href="%s">here</a> to view the full text.'), $url).'</span>';
  175. }
  176. return $body;
  177. }
  178. function bidi_cleanup($data) {
  179. // Closes all embedded RTL and LTR unicode formatting blocks in a string so that
  180. // it can be used inside another without controlling its direction.
  181. $explicits = '\xE2\x80\xAA|\xE2\x80\xAB|\xE2\x80\xAD|\xE2\x80\xAE';
  182. $pdf = '\xE2\x80\xAC';
  183. preg_match_all("!$explicits!", $data, $m1, PREG_OFFSET_CAPTURE | PREG_SET_ORDER);
  184. preg_match_all("!$pdf!", $data, $m2, PREG_OFFSET_CAPTURE | PREG_SET_ORDER);
  185. if (count($m1) || count($m2)){
  186. $p = array();
  187. foreach ($m1 as $m){ $p[$m[0][1]] = 'push'; }
  188. foreach ($m2 as $m){ $p[$m[0][1]] = 'pop'; }
  189. ksort($p);
  190. $offset = 0;
  191. $stack = 0;
  192. foreach ($p as $pos => $type){
  193. if ($type == 'push'){
  194. $stack++;
  195. }else{
  196. if ($stack){
  197. $stack--;
  198. }else{
  199. # we have a pop without a push - remove it
  200. $data = substr($data, 0, $pos-$offset)
  201. .substr($data, $pos+3-$offset);
  202. $offset += 3;
  203. }
  204. }
  205. }
  206. # now add some pops if your stack is bigger than 0
  207. for ($i=0; $i<$stack; $i++){
  208. $data .= "\xE2\x80\xAC";
  209. }
  210. return $data;
  211. }
  212. return $data;
  213. }
  214. function secure_link_confirm($text, $title, $confirm_message, $href) {
  215. global $config;
  216. return '<a onclick="if (event.which==2) return true;if (confirm(\'' . htmlentities(addslashes($confirm_message)) . '\')) document.location=\'?/' . htmlspecialchars(addslashes($href . '/' . make_secure_link_token($href))) . '\';return false;" title="' . htmlentities($title) . '" href="?/' . $href . '">' . $text . '</a>';
  217. }
  218. function secure_link($href) {
  219. return $href . '/' . make_secure_link_token($href);
  220. }
  221. function embed_html($link) {
  222. global $config;
  223. foreach ($config['embedding'] as $embed) {
  224. if ($html = preg_replace($embed[0], $embed[1], $link)) {
  225. if ($html == $link)
  226. continue; // Nope
  227. $html = str_replace('%%tb_width%%', $config['embed_width'], $html);
  228. $html = str_replace('%%tb_height%%', $config['embed_height'], $html);
  229. return $html;
  230. }
  231. }
  232. if ($link[0] == '<') {
  233. // Prior to v0.9.6-dev-8, HTML code for embedding was stored in the database instead of the link.
  234. return $link;
  235. }
  236. return 'Embedding error.';
  237. }
  238. class Post {
  239. public function __construct($post, $root=null, $mod=false) {
  240. global $config;
  241. if (!isset($root))
  242. $root = &$config['root'];
  243. foreach ($post as $key => $value) {
  244. $this->{$key} = $value;
  245. }
  246. if (isset($this->files) && $this->files)
  247. $this->files = @json_decode($this->files);
  248. $this->subject = utf8tohtml($this->subject);
  249. $this->name = utf8tohtml($this->name);
  250. $this->mod = $mod;
  251. $this->root = $root;
  252. if ($this->embed)
  253. $this->embed = embed_html($this->embed);
  254. $this->modifiers = extract_modifiers($this->body_nomarkup);
  255. if ($config['always_regenerate_markup']) {
  256. $this->body = $this->body_nomarkup;
  257. markup($this->body);
  258. }
  259. if ($this->mod)
  260. // Fix internal links
  261. // Very complicated regex
  262. $this->body = preg_replace(
  263. '/<a((([a-zA-Z]+="[^"]+")|[a-zA-Z]+=[a-zA-Z]+|\s)*)href="' . preg_quote($config['root'], '/') . '(' . sprintf(preg_quote($config['board_path'], '/'), $config['board_regex']) . ')/u',
  264. '<a $1href="?/$4',
  265. $this->body
  266. );
  267. }
  268. public function link($pre = '', $page = false) {
  269. global $config, $board;
  270. return $this->root . $board['dir'] . $config['dir']['res'] . link_for((array)$this, $page == '50') . '#' . $pre . $this->id;
  271. }
  272. public function build($index=false) {
  273. global $board, $config;
  274. return Element('post_reply.html', array('config' => $config, 'board' => $board, 'post' => &$this, 'index' => $index, 'mod' => $this->mod));
  275. }
  276. };
  277. class Thread {
  278. public function __construct($post, $root = null, $mod = false, $hr = true) {
  279. global $config;
  280. if (!isset($root))
  281. $root = &$config['root'];
  282. foreach ($post as $key => $value) {
  283. $this->{$key} = $value;
  284. }
  285. if (isset($this->files))
  286. $this->files = @json_decode($this->files);
  287. $this->subject = utf8tohtml($this->subject);
  288. $this->name = utf8tohtml($this->name);
  289. $this->mod = $mod;
  290. $this->root = $root;
  291. $this->hr = $hr;
  292. $this->posts = array();
  293. $this->omitted = 0;
  294. $this->omitted_images = 0;
  295. if ($this->embed)
  296. $this->embed = embed_html($this->embed);
  297. $this->modifiers = extract_modifiers($this->body_nomarkup);
  298. if ($config['always_regenerate_markup']) {
  299. $this->body = $this->body_nomarkup;
  300. markup($this->body);
  301. }
  302. if ($this->mod)
  303. // Fix internal links
  304. // Very complicated regex
  305. $this->body = preg_replace(
  306. '/<a((([a-zA-Z]+="[^"]+")|[a-zA-Z]+=[a-zA-Z]+|\s)*)href="' . preg_quote($config['root'], '/') . '(' . sprintf(preg_quote($config['board_path'], '/'), $config['board_regex']) . ')/u',
  307. '<a $1href="?/$4',
  308. $this->body
  309. );
  310. }
  311. public function link($pre = '', $page = false) {
  312. global $config, $board;
  313. return $this->root . $board['dir'] . $config['dir']['res'] . link_for((array)$this, $page == '50') . '#' . $pre . $this->id;
  314. }
  315. public function add(Post $post) {
  316. $this->posts[] = $post;
  317. }
  318. public function postCount() {
  319. return count($this->posts) + $this->omitted;
  320. }
  321. public function build($index=false, $isnoko50=false) {
  322. global $board, $config, $debug;
  323. $hasnoko50 = $this->postCount() >= $config['noko50_min'];
  324. event('show-thread', $this);
  325. $file = ($index && $config['file_board']) ? 'post_thread_fileboard.html' : 'post_thread.html';
  326. $built = Element($file, array('config' => $config, 'board' => $board, 'post' => &$this, 'index' => $index, 'hasnoko50' => $hasnoko50, 'isnoko50' => $isnoko50, 'mod' => $this->mod));
  327. return $built;
  328. }
  329. };