コミットを比較
11 コミット
47f2f0d82c
...
2d6f04d684
作成者 | SHA1 | 日付 |
---|---|---|
たかし | 2d6f04d684 | |
たかし | 3778101278 | |
たかし | 41ce8b4e9f | |
たかし | 549af48942 | |
たかし | 585037bcbe | |
たかし | 730de9bfbb | |
たかし | 0cf538a7cb | |
たかし | 54e62c3bc7 | |
たかし | 4e56eb746f | |
たかし | d831b416d0 | |
たかし | f804c23d75 |
|
@ -109,6 +109,14 @@ function output_csrf_token_hidden() {
|
|||
|
||||
// String
|
||||
|
||||
function anchor_to_link($s, $thread_id) {
|
||||
return preg_replace(
|
||||
'/>>([1-9]+[0-9]{0,10})/',
|
||||
'<a href="' . sitebase('post/?id=') . $thread_id . '&res=\1">>>\1</a>',
|
||||
$s
|
||||
);
|
||||
}
|
||||
|
||||
function url_to_link($s) {
|
||||
return preg_replace(
|
||||
'/((http|https):\/\/[\w-]+(\.[\w-]+)+([\w.,@?^=%&:\/~+#-]*[\w@?^=%&\/~+#-])?)/',
|
||||
|
|
|
@ -114,6 +114,29 @@ function get_post_metadata($file, $deleted = false) {
|
|||
return compact('id', 'is_guest', 'userid', 'detail_url', 'delete_url', 'user_url', 'datetime', 'time', 'thread_id', 'thread_title', 'thread_url', 'is_mine', 'is_future');
|
||||
}
|
||||
|
||||
function load_res_num($id) {
|
||||
$filepath = filepath_by_post_id($id);
|
||||
if ($filepath === null) { return 1; }
|
||||
|
||||
$file = basename($filepath);
|
||||
$meta = get_post_metadata($file);
|
||||
$thread_id = $meta['thread_id'];
|
||||
$meta = null;
|
||||
if ($thread_id <= '') { return 1; }
|
||||
|
||||
$pattern = "2*Z*.th{$thread_id}.txt";
|
||||
$list = glob(POST_DIR . $pattern);
|
||||
$search = ".id{$id}.";
|
||||
$i = 0;
|
||||
foreach ($list as $i => $filepath) {
|
||||
if (strpos(basename($filepath), $search) > 0) {
|
||||
return $i + 2;
|
||||
}
|
||||
}
|
||||
|
||||
return 1; // fallback
|
||||
}
|
||||
|
||||
function load_post($filepath) {
|
||||
$files = null;
|
||||
|
||||
|
@ -121,7 +144,6 @@ function load_post($filepath) {
|
|||
$deleted = $detail['deleted'];
|
||||
$title = $detail['title'];
|
||||
$body_raw = $detail['body'];
|
||||
$body = url_to_link(nl2br(htmlspecialchars($body_raw), false));
|
||||
$attachment_id = $detail['attachment_id'];
|
||||
$detail = null;
|
||||
|
||||
|
@ -139,6 +161,16 @@ function load_post($filepath) {
|
|||
$username = GUESTNAME;
|
||||
}
|
||||
|
||||
$body = url_to_link(
|
||||
nl2br(
|
||||
anchor_to_link(
|
||||
htmlspecialchars($body_raw),
|
||||
$metadata['thread_id'] ?? $metadata['id']
|
||||
),
|
||||
false
|
||||
)
|
||||
);
|
||||
|
||||
$attachments = [];
|
||||
if ($attachment_id > '') {
|
||||
$attachments[] = [
|
||||
|
@ -154,13 +186,8 @@ function load_post($filepath) {
|
|||
}
|
||||
|
||||
function load_post_by_id($id) {
|
||||
$files = glob(POST_DIR . '2*Z*.id' . $id . '.*.txt');
|
||||
if (sizeof($files) !== 1) {
|
||||
$files = null;
|
||||
return null;
|
||||
}
|
||||
$filepath = $files[0];
|
||||
|
||||
$filepath = filepath_by_post_id($id);
|
||||
if ($filepath === null) { return null; }
|
||||
return load_post($filepath);
|
||||
}
|
||||
|
||||
|
@ -177,7 +204,7 @@ function search_post($options = []) {
|
|||
$options = null;
|
||||
|
||||
$pattern = '2*Z*.txt';
|
||||
if ($key === 'userid' && $value > '') {
|
||||
if ($key === 'userid' && $value > '' && $value !== 'tl') {
|
||||
$pattern = "2*Z*.us{$value}.*.txt";
|
||||
}
|
||||
elseif ($key == 'thread' && $value >= 0) {
|
||||
|
@ -492,6 +519,14 @@ function count_post_today() {
|
|||
return $size;
|
||||
}
|
||||
|
||||
function filepath_by_post_id($id) {
|
||||
$files = glob(POST_DIR . '2*Z*.id' . $id . '.*.txt');
|
||||
if (sizeof($files) !== 1) {
|
||||
return null;
|
||||
}
|
||||
return $files[0];
|
||||
}
|
||||
|
||||
function load_post_title_by_id($id) {
|
||||
global $post_title_cache;
|
||||
|
||||
|
|
8
data.php
8
data.php
|
@ -37,6 +37,12 @@ function load_users() {
|
|||
return $users_cache;
|
||||
}
|
||||
|
||||
function load_users_with_special() {
|
||||
$users = load_users();
|
||||
$users['tl'] = ['id' => 'tl', 'username_raw' => SITENAME, 'username' => SITENAME, 'trip' => ''];
|
||||
return $users;
|
||||
}
|
||||
|
||||
function update_user($user) {
|
||||
// 注意:ここを変更したら、必ず、ユーザーが消えない事をテストすること。
|
||||
|
||||
|
@ -124,6 +130,8 @@ function add_user($user) {
|
|||
// 将来的に「-」より前の行にユーザーごとの設定値などを記録する予定。
|
||||
|
||||
function load_profile($id) {
|
||||
if ($id === 'tl') { return ['bio' => '']; }
|
||||
|
||||
$profile = @file_get_contents(PROFILE_DIR . $id . '.txt') ?? '';
|
||||
if ($profile <= '') { return null; }
|
||||
|
||||
|
|
|
@ -0,0 +1,2 @@
|
|||
<?php
|
||||
require_once __DIR__ . '/../../activitypub/webfinger.php';
|
|
@ -18,6 +18,32 @@ function do_get() {
|
|||
$post = load_post_by_id($id);
|
||||
if (!$post) { return on_error(400, ['書き込みが存在しない']); }
|
||||
|
||||
if (isset($_GET['res'])) {
|
||||
// TODO:to data-post (or common?)
|
||||
$res = $_GET['res'] ?? '';
|
||||
if ((int)$res <= 0 || (((int)$res) . '') !== $res) { return on_error(400, ['返信番号が不正']); }
|
||||
$redirect_id = null;
|
||||
if ($res === '1') {
|
||||
$redirect_id = $id;
|
||||
}
|
||||
elseif ((int)$res >= 2) {
|
||||
$result = search_post(['key' => 'thread', 'value' => $id]);
|
||||
foreach ($result['post_list'] as $i => $res_post) {
|
||||
if ($i + 2 === (int)$res) {
|
||||
$redirect_id = $res_post['id'];
|
||||
break;
|
||||
}
|
||||
}
|
||||
$result = null;
|
||||
$res_post = null;
|
||||
}
|
||||
if ($redirect_id === null) { return on_error(404, ['返信が存在しない']); }
|
||||
http_response_code(301);
|
||||
header('Location: ' . sitebase('post/?id=' . $redirect_id));
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
$view['post'] = $post;
|
||||
|
||||
$thread_id = $post['thread_id'];
|
||||
|
@ -32,6 +58,7 @@ function do_get() {
|
|||
$view['total'] = $total;
|
||||
$view['reply_list'] = $result['post_list'];
|
||||
}
|
||||
$view['res_num'] = load_res_num($id);
|
||||
$view['thread_size_over'] = ($total + 1 >= THREAD_SIZE);
|
||||
$result = null;
|
||||
$view['form'] = ['thread_id' => $is_reply ? $thread_id : $id];
|
||||
|
@ -74,6 +101,9 @@ function do_post() {
|
|||
$body = sanitize_post_body($body);
|
||||
$error_body = validate_post_body($body);
|
||||
}
|
||||
if (!$error_body && $thread_id !== NULL && !(ENABLE_IMAGE && $has_file)) {
|
||||
$error_body = validate_post_body_with_anchor($body);
|
||||
}
|
||||
|
||||
$errors = array_merge($error_title, $error_body);
|
||||
if ($errors) { return on_error(400, $errors); }
|
||||
|
|
|
@ -100,7 +100,6 @@ form ul li
|
|||
label
|
||||
{
|
||||
display: block;
|
||||
font-size: 80%;
|
||||
}
|
||||
|
||||
button, textarea, input
|
||||
|
@ -113,12 +112,12 @@ button, textarea, input
|
|||
|
||||
textarea, input
|
||||
{
|
||||
background: #2b2b2b;
|
||||
background: #12110c;
|
||||
box-sizing: border-box;
|
||||
border-color: #000;
|
||||
border-color: #4b4b4b;
|
||||
color: #ccc;
|
||||
width: 100%;
|
||||
padding: 0 0.25em;
|
||||
padding: 0.25em;
|
||||
}
|
||||
|
||||
input[type='checkbox']
|
||||
|
@ -130,15 +129,15 @@ input[type='checkbox']
|
|||
|
||||
input[type='file']
|
||||
{
|
||||
background: none;
|
||||
background: #12110c;
|
||||
color: #ccc;
|
||||
font-size: 70%;
|
||||
padding: 0.25em;
|
||||
padding: 0.4em;
|
||||
}
|
||||
|
||||
input[type='file']:hover
|
||||
{
|
||||
background: #4d4d4d;
|
||||
background: #2b2b2b;
|
||||
color: #ccc;
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,282 @@
|
|||
/** theme: nitter-linke **/
|
||||
/** bibis-version: 0.9.3 **/
|
||||
/*
|
||||
Copying and distribution of this file, with or without modification,
|
||||
are permitted in any medium without royalty provided the copyright
|
||||
notice and this notice are preserved. This file is offered as-is,
|
||||
without any warranty.
|
||||
*/
|
||||
|
||||
*
|
||||
{
|
||||
border: none;
|
||||
font-size: 100%;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
vertical-align: top;
|
||||
}
|
||||
|
||||
body
|
||||
{
|
||||
background: #0F0F0F;
|
||||
color: #F8F8F2;
|
||||
line-height: 1.5;
|
||||
margin: 1em;
|
||||
word-break: break-all;
|
||||
}
|
||||
|
||||
h1, h2, h3, h4, h5, h6, dl, ul, ol, p
|
||||
{
|
||||
background: #161616;
|
||||
color: #F8F8F2;
|
||||
}
|
||||
|
||||
h2, dl, ul
|
||||
{
|
||||
border-top: thin solid #3E3E35;
|
||||
}
|
||||
|
||||
h1, h2, button, label, b
|
||||
{
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
h1, h2, ul
|
||||
{
|
||||
padding: 0.25em 1em;
|
||||
}
|
||||
|
||||
h1
|
||||
{
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
ul
|
||||
{
|
||||
list-style: none;
|
||||
}
|
||||
|
||||
dd ul
|
||||
{
|
||||
border: thin solid #888889;
|
||||
margin: 0.5em 0 0;
|
||||
}
|
||||
|
||||
dl
|
||||
{
|
||||
display: block; /*dillo*/
|
||||
padding: 0.5em 1em 0;
|
||||
}
|
||||
|
||||
dt
|
||||
{
|
||||
/*color: rgb(205, 205, 200);*/
|
||||
font-weight: normal;
|
||||
}
|
||||
|
||||
dd
|
||||
{
|
||||
clear: both; /* see: .post-time */
|
||||
padding-bottom: 0.5em;
|
||||
}
|
||||
|
||||
p
|
||||
{
|
||||
padding: 0 1em 0.5em;
|
||||
}
|
||||
|
||||
form ul
|
||||
{
|
||||
padding-top: 0.5em;
|
||||
}
|
||||
|
||||
form ul li
|
||||
{
|
||||
padding: 0 0 0.5em;
|
||||
}
|
||||
|
||||
label
|
||||
{
|
||||
display: block;
|
||||
}
|
||||
|
||||
button, textarea, input
|
||||
{
|
||||
background: #121212;
|
||||
color: #F8F8F2;
|
||||
font-family: inherit;
|
||||
border: thin solid rgb(153, 69, 62);
|
||||
font-size: 100%;
|
||||
line-height: 1.5;
|
||||
}
|
||||
|
||||
button:hover, textarea:hover, input:hover
|
||||
{
|
||||
border-color: #FF6360;
|
||||
}
|
||||
|
||||
textarea, input
|
||||
{
|
||||
box-sizing: border-box;
|
||||
width: 100%;
|
||||
padding: 0.25em;
|
||||
}
|
||||
|
||||
input[type='checkbox']
|
||||
{
|
||||
padding: 0;
|
||||
vertical-align: baseline;
|
||||
width: auto;
|
||||
}
|
||||
|
||||
input[type='file']
|
||||
{
|
||||
background: #12110c;
|
||||
color: #ccc;
|
||||
font-size: 70%;
|
||||
padding: 0.4em;
|
||||
}
|
||||
|
||||
textarea
|
||||
{
|
||||
height: 6em;
|
||||
}
|
||||
|
||||
button
|
||||
{
|
||||
background: none;
|
||||
cursor: pointer;
|
||||
color: #FF6360;
|
||||
padding: 0.25em 1.5em;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
a
|
||||
{
|
||||
background: none;
|
||||
color: #FF6C60;
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
a:hover
|
||||
{
|
||||
text-decoration: underline;
|
||||
}
|
||||
|
||||
/* class */
|
||||
|
||||
.spooftime-text
|
||||
{
|
||||
font-style: italic;
|
||||
font-weight: 400;
|
||||
}
|
||||
|
||||
:checked ~ .spooftime-text
|
||||
{
|
||||
background: #0ff;
|
||||
color: #000;
|
||||
font-style: normal;
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.form-li-submit
|
||||
{
|
||||
text-align: right;
|
||||
}
|
||||
|
||||
.post-time
|
||||
{
|
||||
float: right;
|
||||
}
|
||||
|
||||
a.post-time
|
||||
{
|
||||
color: #FF6C60;
|
||||
}
|
||||
|
||||
.post-time.is-future
|
||||
{
|
||||
background: #0ff;
|
||||
color: #000;
|
||||
}
|
||||
|
||||
.pager
|
||||
{
|
||||
height: 3em;
|
||||
line-height: 2;
|
||||
padding: 1em;
|
||||
}
|
||||
|
||||
.pager-after a,
|
||||
.pager-before a
|
||||
{
|
||||
display: block;
|
||||
}
|
||||
|
||||
.pager-after
|
||||
{
|
||||
float: left;
|
||||
}
|
||||
|
||||
.pager-after a
|
||||
{
|
||||
padding: 0.5em 1em;
|
||||
}
|
||||
|
||||
.pager-after a:hover
|
||||
{
|
||||
}
|
||||
|
||||
.pager-before
|
||||
{
|
||||
float: right;
|
||||
}
|
||||
|
||||
.pager-before a
|
||||
{
|
||||
background: #222;
|
||||
color: #FF6C60;
|
||||
padding: 0.5em 1.5em 0.5em 2em;
|
||||
}
|
||||
|
||||
.pager-before a:hover
|
||||
{
|
||||
background: #282828;
|
||||
color: #FF6C60;
|
||||
}
|
||||
|
||||
/* for modern browsers, and netsurf */
|
||||
|
||||
@media (min-width: 880.1px)
|
||||
{
|
||||
|
||||
body
|
||||
{
|
||||
left: -125px;
|
||||
margin: 1em auto;
|
||||
position: relative;
|
||||
width: 600px;
|
||||
}
|
||||
|
||||
.menu
|
||||
{
|
||||
background: none;
|
||||
border: none;
|
||||
color: #ccc;
|
||||
margin: 0.75em 0 0 600px;
|
||||
position: fixed;
|
||||
top: 0;
|
||||
}
|
||||
|
||||
.menu li
|
||||
{
|
||||
width: 200px;
|
||||
}
|
||||
|
||||
.menu a
|
||||
{
|
||||
display: block;
|
||||
line-height: 2;
|
||||
}
|
||||
|
||||
}
|
|
@ -3,7 +3,7 @@ require_once(__DIR__ . '/../../require.php');
|
|||
|
||||
if ($_SERVER['REQUEST_METHOD'] === 'GET') {
|
||||
$user_list = load_users();
|
||||
ksort($user_list);
|
||||
ksort($user_list, SORT_STRING | SORT_FLAG_CASE);
|
||||
$view['user_list'] = $user_list;
|
||||
|
||||
output_html($view, ['header.php', 'user-list.php']);
|
||||
|
|
|
@ -2,10 +2,10 @@
|
|||
require_once(__DIR__ . '/../../require.php');
|
||||
|
||||
if ($_SERVER['REQUEST_METHOD'] === 'GET') {
|
||||
$id = $_GET['id'] ?? '';
|
||||
if (!strlen($id) || validate_register_id($id)) { return on_error(400, ['不正なリクエスト。']); }
|
||||
$id = '' . ($_GET['id'] ?? '');
|
||||
if ($id !== 'tl' && (!strlen($id) || validate_register_id($id))) { return on_error(400, ['不正なリクエスト。']); }
|
||||
|
||||
$users = load_users();
|
||||
$users = load_users_with_special();
|
||||
if (!isset($users[$id])) { return on_error(400, ['存在しない ID']); }
|
||||
|
||||
$view['user'] = $users[$id];
|
||||
|
|
|
@ -6,7 +6,7 @@ function validate_register_id($s) {
|
|||
$len = mb_strlen(mbtrim($s));
|
||||
if ($len < 3) { return ['ID は必須、3文字以上。']; }
|
||||
if ($len > 12) { return ['ID は 12文字以内。']; }
|
||||
if (!preg_match('/^[a-zA-Z0-9]+$/', $s)) { return ['ID は半角英數のみ。']; }
|
||||
if (!preg_match('/^[a-zA-Z0-9]+$/', $s)) { return ['ID は半角英数のみ。']; }
|
||||
return [];
|
||||
}
|
||||
|
||||
|
@ -64,6 +64,13 @@ function validate_post_body($s) {
|
|||
return [];
|
||||
}
|
||||
|
||||
function validate_post_body_with_anchor($s) {
|
||||
// アンカーのみ(返信時のデフォルト)は不許可
|
||||
$s = preg_replace('/^>>[0-9]+/', '', $s);
|
||||
if (mbtrim($s) === '') { return ['アンカー「>>○○」1つだけの返信は不可。']; }
|
||||
return [];
|
||||
}
|
||||
|
||||
function sanitize_post_body($s) {
|
||||
return sanitize_multiline($s);
|
||||
}
|
||||
|
|
|
@ -62,8 +62,8 @@ function view_post($post, $options = []) {
|
|||
<dt>件名:<b><?= $title ?></b></dt>
|
||||
<?php endif; ?>
|
||||
<dt><?= $res_num > 0 ? "{$res_num} " : '' ?><?= $html_user ?> <?= $html_time ?></dt>
|
||||
<?php if ($link_to_thread && $thread_id > ''): ?>
|
||||
<dd>RE: <a href="<?= $thread_url ?>"><?= $thread_title ?></a></dd>
|
||||
<?php if ($link_to_thread && $thread_id > '' && !$is_single): ?>
|
||||
<dd>RE:<a href="<?= $thread_url ?>"><?= $thread_title ?></a></dd>
|
||||
<?php endif; ?>
|
||||
<dd><?= $body ?>
|
||||
<?php if (ENABLE_ATTACHMENT && $html_attachment_items > ''): ?>
|
||||
|
|
|
@ -1,5 +1,9 @@
|
|||
<?php
|
||||
// Post form
|
||||
$value = '';
|
||||
if (($view['res_num'] ?? 0) >= 2) {
|
||||
$value = '>>' . $view['res_num'] . PHP_EOL;
|
||||
}
|
||||
?>
|
||||
<?php if (ENABLE_POST): ?>
|
||||
<?php if (isset($view['form']['thread_id']) && $view['form']['thread_id'] > ''): ?>
|
||||
|
@ -37,7 +41,7 @@ $view['form'] = $view['form'] ?? [];
|
|||
<?php if (!(isset($view['form']['thread_id']) && $view['form']['thread_id'] > '')): ?>
|
||||
<li><label for="TITLE">件名 (省略可)・Title (Optional)</label> <input type="text" id="TITLE" name="title">
|
||||
<?php endif; ?>
|
||||
<li><label for="BODY">本文 (500文字以内)・Text (500)</label> <textarea id="BODY" name="body" cols="40" rows="5"></textarea>
|
||||
<li><label for="BODY">本文 (500文字以内)・Text (500)</label> <textarea id="BODY" name="body" cols="40" rows="5"><?= htmlspecialchars($value) ?></textarea>
|
||||
<?php if (ENABLE_SPOOF_TIME): ?>
|
||||
<li><label><input type="checkbox" name="spooftime" value="1"> <b class="spooftime-text">ランダム予約投稿(3H~27H遅らせる)</b></label></li>
|
||||
<?php endif; ?>
|
||||
|
|
|
@ -3,7 +3,9 @@
|
|||
require __DIR__ . '/post-common.php';
|
||||
|
||||
$post = $view['post'] ?? [];
|
||||
$title = $post['title'] ?? '';
|
||||
$title = ($post['title']) ?? '';
|
||||
$thread_title = ($post['thread_title']) ?? '';
|
||||
$thread_url = ($post['thread_url']) ?? '';
|
||||
$reply_list = $view['reply_list'] ?? [];
|
||||
$total = sizeof($reply_list) + 1;
|
||||
$total_view = $total > 1 ? " ($total)" : '';
|
||||
|
@ -12,9 +14,13 @@ $total_view = $total > 1 ? " ($total)" : '';
|
|||
<h2>件名:<?= htmlspecialchars("$title{$total_view}") ?></h2>
|
||||
<?php elseif ($post['thread_id'] <= ''): ?>
|
||||
<h2><?= htmlspecialchars('無題#' . mb_substr($post['id'], 0, 7) . $total_view) ?></h2>
|
||||
<?php elseif ($thread_title > ''): ?>
|
||||
<h2>RE:<a href="<?= $thread_url ?>"><?= htmlspecialchars($thread_title) ?></a></h2>
|
||||
<?php elseif ($post['thread_id'] <= ''): ?>
|
||||
<h2>RE:<a href="<?= $thread_url ?>"><?= htmlspecialchars('無題#' . mb_substr($post['thread_id'], 0, 7)) ?></a></h2>
|
||||
<?php endif; ?>
|
||||
<?php
|
||||
view_post($post, ['res_num' => $post['thread_id'] > '' ? 0 : 1, 'is_single' => true, 'link_to_thread' => true]);
|
||||
view_post($post, ['res_num' => $post['thread_id'] > '' ? 0 : 1, 'is_single' => true, 'link_to_thread' => true, 'res_num' => $view['res_num'] ?? 1]);
|
||||
?>
|
||||
<?php
|
||||
foreach ($reply_list as $i => $reply) {
|
||||
|
|
読み込み中…
新しいイシューから参照