バグを修正

このコミットが含まれているのは:
守矢諏訪子 2023-12-05 17:35:37 +09:00
コミット f1955044e4
12個のファイルの変更141行の追加107行の削除

ファイルの表示

@ -17,7 +17,7 @@ date_default_timezone_set('UTC');
ini_set('zlib.output_compression', 1);
if (OPEN_BASEDIR > '') {
if (OPEN_BASEDIR != '') {
ini_set('open_basedir', OPEN_BASEDIR);
}

ファイルの表示

@ -37,7 +37,8 @@
$post_title_cache = [];
function load_postfile($filepath) {
$text = @file_get_contents($filepath);
$text = file_get_contents($filepath);
$split = preg_split('/^-$/m', $text, 2);
$text = null;
@ -97,17 +98,18 @@ function get_post_metadata($file, $deleted = false) {
$is_guest = $userid === '';
$thread_title = '';
if ($thread_id > '') {
if ($thread_id != '') {
$thread_title = load_post_title_by_id($thread_id);
if (!$thread_title > '') {
$thread_title = '無題#' . mb_substr($thread_id, 0, 7);
}
}
if ($thread_id != '' && $thread_title != '') {
$thread_title = '無題#' . mb_substr($thread_id, 0, 7);
}
$detail_url = sitebase('post/?id=' . $id);
$delete_url = sitebase('post-delete/?id=' . $id);
$user_url = $is_guest ? '' : sitebase('user/?id=' . $userid);
$thread_url = $thread_id > '' ? sitebase('post/?id=' . $thread_id) : '';
$thread_url = $thread_id != '' ? sitebase('post/?id=' . $thread_id) : '';
$is_mine = !$is_guest && $userid === ($_SESSION['user']['id'] ?? '');
// too long, sorry.
@ -129,18 +131,17 @@ function load_post($filepath) {
$userid = $metadata['userid'];
$users = load_users();
$username = GUESTNAME;
if ($deleted) {
$username = DELETEDNAME;
}
elseif ($userid > '') {
elseif ($userid != '') {
$username = $users[$userid]['username'] ?? 'UNKNOWN';
}
else {
$username = GUESTNAME;
}
$attachments = [];
if ($attachment_id > '') {
if ($attachment_id != '') {
$attachments[] = [
'url' => sitebase('attachment/?id=' . $attachment_id),
'name' => '添付画像(Image)',
@ -154,6 +155,10 @@ function load_post($filepath) {
}
function load_post_by_id($id) {
if (!file_exists(POST_DIR)) {
die(POST_DIR.': ディレクトリは存在しません。');
}
$files = glob(POST_DIR . '2*Z*.id' . $id . '.*.txt');
if (sizeof($files) !== 1) {
$files = null;
@ -165,6 +170,10 @@ function load_post_by_id($id) {
}
function search_post($options = []) {
if (!file_exists(POST_DIR)) {
die(POST_DIR.': ディレクトリは存在しません。');
}
$pagesize = $options['pagesize'] ?? 0;
$has_paging = $pagesize > 0;
$thread = false;
@ -176,7 +185,7 @@ function search_post($options = []) {
$options = null;
$pattern = '2*Z*.txt';
if ($key === 'userid' && $value > '') {
if ($key === 'userid' && $value != '') {
$pattern = "2*Z*.us{$value}.*.txt";
}
elseif ($key == 'thread' && $value >= 0) {
@ -188,7 +197,6 @@ function search_post($options = []) {
$key = null;
$value = null;
$now = date('Y-m-d\\TH:i:s\\Z');
$files = glob(POST_DIR . $pattern);
$files = array_filter(
@ -261,36 +269,35 @@ function add_post($userid, $title, $body, $attachment_id, $file_hash, &$post_id_
$id = md5(bin2hex(random_bytes(256)) . $userid . $title . $body);
if ($spooftime) {
$dto = new DateTime('+' . (mt_rand(60 * 60 * 3, 60 * 60 * 27 - 1)) . 'seconds');
} else {
$dto = new DateTime();
}
$dto = new DateTime($spooftime ? '+' . (mt_rand(60 * 60 * 3, 60 * 60 * 27 - 1)) . 'seconds' : '');
$datetime = $dto->format('Y-m-d\\TH:i:s\\Z');
$timestamp = $dto->getTimestamp();
$dto = null;
unset($dto);
$file = "{$datetime}.id{$id}.us{$userid}.to-.th{$thread_id}.txt";
if ($body !== '.' || $file_hash === '') {
$error = check_repeating_info($body, $datetime);
if ($error) { return ['すでに同様の書き込み有り(削除済みを含む)。連投防止。']; }
}
if ($file_hash > '') {
if ($file_hash != '') {
$error = check_repeating_info($body, $datetime, $file_hash);
if ($error) { return ['すでに同じ画像有り(削除済みを含む)。連投防止。']; }
}
mkdir_p(POST_DIR);
if (!mkdir_p(POST_DIR)) {
die("mkdir_pを実行に失敗しました。");
}
$result = file_put_contents(POST_DIR . $file, $text, LOCK_EX);
if ($result === false) { return ['書き込みの保存に失敗。']; }
@chmod(POST_DIR . $file, 0600);
@touch(POST_DIR . $file, $timestamp, $timestamp);
touch(POST_DIR . $file, $timestamp, $timestamp);
chmod(POST_DIR . $file, 0644);
if ($body !== '.' || $file_hash === '') {
add_repeating_info(make_repeating_info($body, $datetime));
}
if ($file_hash > '') {
if ($file_hash != '') {
add_repeating_info(make_repeating_info($body, $datetime, $file_hash));
}
@ -301,7 +308,7 @@ function add_post($userid, $title, $body, $attachment_id, $file_hash, &$post_id_
function check_uploaded_image($key) {
$size = $_FILES[$key]['size'] ?? 0;
if ($size <= 0) { return ['画像ファイルが不正。']; }
if ($size > 1024 * 500) { ['画像ファイルは 500 kb 以内。']; }
else if ($size > 1024 * 500) { ['画像ファイルは 500 kb 以内。']; }
$buffer = file_get_contents($_FILES[$key]['tmp_name']);
$type = get_image_type($buffer);
@ -316,16 +323,17 @@ function save_uploaded_image($key, $attachment_id) {
$type = get_image_type($buffer);
if (!isset($type)) { on_error(400, ['画像ファイルが不正。']); }
$result = mkdir_p(ATTACHMENT_DIR, 0700);
if (!$result) { return ['フォルダの作成に失敗。']; }
if (!$result = mkdir_p(ATTACHMENT_DIR, 0700)) {
return ['フォルダの作成に失敗。'];
}
$target = ATTACHMENT_DIR . $attachment_id . '.gz';
if (!$gz = gzopen($target, 'w1')) { return ['画像の書き込みに失敗。']; }
$result = gzwrite($gz, $buffer);
if ($result === false) { return ['画像の書き込みに失敗。']; }
@gzclose($gz);
@chmod($target, 0777);
gzclose($gz);
chmod($target, 0777);
return [];
}
@ -352,8 +360,6 @@ function delete_post($id) {
$result = file_put_contents($filepath, '', LOCK_EX);
if ($result === false) { return ['書き込みの削除に失敗。']; }
@chmod($filepath, 0600);
return [];
}
@ -380,7 +386,7 @@ function load_threads() {
if ($parent['deleted']) { continue; }
$thread = ['count' => 2];
if (($parent['title'] ?? '') > '') {
if (($parent['title'] ?? '') != '') {
$thread['title'] = $parent['title'];
}
else {
@ -405,21 +411,20 @@ function load_threads() {
}
function make_repeating_info($body, $datetime, $file_hash = '') {
if ($file_hash > '') {
$hash = $file_hash;
$size = 10;
if ($file_hash != '') {
return ['hash' => $file_fash, 'limit' => mb_substr($datetime, 0, 10)];
}
else {
$letter_only = preg_replace('/[^\p{Ll}\p{Lt}\p{Lo}\p{Lu}\p{N}]/u', '', $body);
if (mb_strlen($letter_only) > 0) { $body = $letter_only; }
$hash = md5($body);
$len = mb_strlen($body);
if ($len <= 2) { $size = 16; }
elseif ($len <= 30) { $size = 13; }
elseif ($len <= 40) { $size = 10; }
else { $size = 7; }
}
$letter_only = preg_replace('/[^\p{Ll}\p{Lt}\p{Lo}\p{Lu}\p{N}]/u', '', $body);
if (mb_strlen($letter_only) > 0) { $body = $letter_only; }
$hash = md5($body);
$len = mb_strlen($body);
if ($len <= 2) { $size = 16; }
elseif ($len <= 30) { $size = 13; }
elseif ($len <= 40) { $size = 10; }
else { $size = 7; }
return [
'hash' => $hash,
'limit' => mb_substr($datetime, 0, $size),
@ -432,12 +437,15 @@ function add_repeating_info($repeating_info) {
$limit = $repeating_info['limit'] ?? '';
$text = "$hash\t$limit" . PHP_EOL;
$result = file_put_contents(LIMIT_TSV, $text, FILE_APPEND | LOCK_EX);
if ($result !== false) { @chmod(LIMIT_TSV . $file, 0600); }
}
function check_repeating_info($body, $datetime, $file_hash = '') {
if (!file_exists(LIMIT_TSV)) {
die(LIMIT_TSV.": ファイルを見つけられません。");
}
$hash = make_repeating_info($body, $datetime, $file_hash)['hash'];
$text = @file_get_contents(LIMIT_TSV) ?? '';
$text = file_get_contents(LIMIT_TSV) ?? '';
$lines = explode(PHP_EOL, $text);
$text = null;
@ -454,13 +462,13 @@ function check_repeating_info($body, $datetime, $file_hash = '') {
$count += 1;
}
}
$array = null;
}
$lines = null;
$line = null;
unset($array);
unset($line);
}
unset($lines);
$result = file_put_contents(LIMIT_TSV, $out, LOCK_EX);
if ($result !== false) { @chmod(LIMIT_TSV . $file, 0600); }
return $count >= 1;
}
@ -468,6 +476,10 @@ function check_repeating_info($body, $datetime, $file_hash = '') {
// Util
function count_post() {
if (!file_exists(POST_DIR)) {
die(POST_DIR.': ディレクトリは存在しません。');
}
$pattern = '2*Z*.txt';
$files = glob(POST_DIR . '2*Z*.txt');
$size = sizeof($files);
@ -477,6 +489,10 @@ function count_post() {
}
function count_post_today() {
if (!file_exists(POST_DIR)) {
die(POST_DIR.': ディレクトリは存在しません。');
}
$date = date('Y-m-d');
$pattern = "{$date}T*Z.*.txt";
$files = glob(POST_DIR . $pattern);
@ -487,6 +503,10 @@ function count_post_today() {
}
function load_post_title_by_id($id) {
if (!file_exists(POST_DIR)) {
die(POST_DIR.': ディレクトリは存在しません。');
}
global $post_title_cache;
if (isset($post_title_cache[$id])) { return $post_title_cache[$id]; }

ファイルの表示

@ -19,20 +19,19 @@ function load_users() {
if (isset($users_cache)) { return $users_cache; }
$users_cache = [];
$prev = @file_get_contents(USERS_TSV) ?? '';
$prev = file_get_contents(USERS_TSV) ?? '';
$rows = explode(PHP_EOL, $prev);
$prev = null;
unset($prev);
foreach ($rows as $row) {
$user = parse_user_row($row);
if ($user['id'] <= '') { continue; }
if ($user['id'] == '') { continue; }
$user['hash_password'] = ''; // HIDE
$users_cache[$user['id']] = $user;
$user = null;
unset($user);
}
$rows = null;
$row = null;
unset($rows);
return $users_cache;
}
@ -40,12 +39,14 @@ function load_users() {
function update_user($user) {
// 注意:ここを変更したら、必ず、ユーザーが消えない事をテストすること。
if (!$user) { return ['ユーザーが不正。']; }
if (!isset($user['id'])) { return ['ユーザーIDが不正。']; }
$id = $user['id'];
$username = $user['username'];
$password = $user['password'];
$trip = $user['trip'] ?? '';
$fp = @fopen(USERS_TSV, 'r+');
$fp = fopen(USERS_TSV, 'r+');
if ($fp === false || !flock($fp, LOCK_EX)) { return ['ファイルの取得に失敗。']; }
$prev = fread($fp, filesize(USERS_TSV));
@ -65,25 +66,22 @@ function update_user($user) {
continue;
}
if ($password > '') {
if ($password != '') {
$hash_password = hash_password($password);
} else {
$array = explode("\t", $row);
$hash_password = $array[2];
$array = null;
unset($array);
}
$output .= "{$id}\t{$username}\t{$hash_password}\t{$trip}" . PHP_EOL;
$id = null;
$username = null;
$hash_password = null;
$trip = null;
unset($id);
unset($username);
unset($hash_password);
unset($trip);
$changed = true;
}
$rows = null;
$row = null;
if (!$changed) { return ['ユーザーIDが不正。']; }
unset($rows);
if (
!ftruncate($fp, 0)
@ -92,27 +90,34 @@ function update_user($user) {
|| !fflush($fp)
) { return ['ファイルの書き込みに失敗。']; }
@flock($fp, LOCK_UN);
@fclose($fp);
@chmod(USERS_TSV, 600);
flock($fp, LOCK_UN);
fclose($fp);
return [];
}
function add_user($user) {
if (!file_exists(USERS_TSV)) {
die(USERS_TSV.': ファイルを見つけられません。');
}
$id = $user['id'];
$username = $user['username'];
$password = $user['password'];
$match = find_user_row($id);
if (isset($match)) { return ['ID が既存ユーザーと重複。']; }
$match = null;
unset($match);
$hash_password = hash_password($password);
$record = "{$id}\t{$username}\t{$hash_password}\t" . PHP_EOL;
$result = file_put_contents(USERS_TSV, $record, FILE_APPEND | LOCK_EX);
$record = "{$id}\t{$username}\t{$hash_password}\t" . PHP_EOL;
$result = false;
if (is_writable(USERS_TSV)) {
$result = file_put_contents(USERS_TSV, $record, FILE_APPEND | LOCK_EX);
}
if ($result === false) { return ['ファイルの書き込みに失敗。']; }
@chmod(USERS_TSV, 600);
chmod(USERS_TSV, 644);
return [];
}
@ -124,8 +129,18 @@ function add_user($user) {
// 将来的に「-」より前の行にユーザーごとの設定値などを記録する予定。
function load_profile($id) {
$profile = @file_get_contents(PROFILE_DIR . $id . '.txt') ?? '';
if ($profile <= '') { return null; }
if (!file_exists(PROFILE_DIR)) {
if (!mkdir_p(PROFILE_DIR, 755)) die(PROFILE_DIR.'を作成に失敗。');
}
if (!file_exists(PROFILE_DIR.$id.'.txt')) {
touch(PROFILE_DIR.$id.'.txt', time());
}
$profile = '';
if (is_writable(PROFILE_DIR.$id.'.txt')) {
$profile = file_get_contents(PROFILE_DIR . $id . '.txt') ?? '';
}
if ($profile == '') { return null; }
$split = preg_split('/^-$/m', $profile, 2);
$bio = mbtrim($split[1] ?? '');
@ -139,7 +154,6 @@ function save_profile($id, $profile) {
if (!mkdir_p(PROFILE_DIR)) { return ['フォルダーの作成に失敗。']; }
$result = file_put_contents(PROFILE_DIR . $id . '.txt', '-' . PHP_EOL . $bio . PHP_EOL);
if ($result === false) { return ['ファイルの書き込みに失敗。']; }
@chmod(PROFILE_DIR . $id . '.txt', 600);
return [];
}
@ -161,15 +175,15 @@ function auth_user($id, $password) {
// Util
function find_user_row($id) {
$users = @file_get_contents(USERS_TSV) ?? '';
$users = file_get_contents(USERS_TSV) ?? '';
$rows = explode(PHP_EOL, $users);
$search_id = $id . "\t";
foreach ($rows as $row) {
if (stripos($row, $search_id) === 0) {
return $row;
}
}
$search_id = $id . "\t";
foreach ($rows as $row) {
if (stripos($row, $search_id) === 0) {
return $row;
}
}
return null;
}

ファイルの表示

@ -5,7 +5,7 @@ if ($_SERVER['REQUEST_METHOD'] === 'GET') {
if (!ENABLE_ATTACHMENT) { return on_error(404, ['Not Found.']); }
$id = $_GET['id'] ?? '';
if ($id <= '' || !preg_match('/^[a-z0-9]{32}$/', $id)) { return on_error(400, ['URLが不正。']); }
if ($id == '' || !preg_match('/^[a-z0-9]{32}$/', $id)) { return on_error(400, ['URLが不正。']); }
$filepath = ATTACHMENT_DIR . $id . '.gz';
if (!file_exists($filepath)) { return on_error(404, ['Not Found.']); }

ファイルの表示

@ -21,7 +21,7 @@ function do_get() {
$view['post'] = $post;
$thread_id = $post['thread_id'];
$is_reply = $thread_id > '';
$is_reply = $thread_id != '';
if ($is_reply) {
$result = search_post(['key' => 'thread', 'value' => $thread_id]);
$total = $result['total'];

ファイルの表示

@ -34,7 +34,7 @@ function do_post() {
}
$error_bio = [];
if ($bio > '') {
if ($bio != '') {
$error_bio = validate_bio($bio);
if (!$error_bio) {
$bio = sanitize_bio($bio);
@ -43,7 +43,7 @@ function do_post() {
}
$error_password = [];
if ($password > '') {
if ($password != '') {
$error_password = validate_register_password($password, $password2);
}
@ -54,8 +54,8 @@ function do_post() {
if (!$notrip) {
$trip = $_SESSION['user']['trip'];
}
if ($tripkey > '') {
// $notrip == 1 かつ $tripkey > '' ならトリップを變更できる
if ($tripkey != '') {
// $notrip == 1 かつ $tripkey != '' ならトリップを變更できる
$trip = twochan_trip($tripkey);
}

ファイルの表示

@ -5,7 +5,7 @@ function validate_register_id($s) {
$s = mbtrim($s);
$len = mb_strlen(mbtrim($s));
if ($len < 3) { return ['ID は必須、3文字以上。']; }
if ($len > 12) { return ['ID は 12文字以内。']; }
else if ($len > 12) { return ['ID は 12文字以内。']; }
if (!preg_match('/^[a-zA-Z0-9]+$/', $s)) { return ['ID は半角英數のみ。']; }
return [];
}
@ -13,7 +13,7 @@ function validate_register_id($s) {
function validate_register_username($s) {
$len = mb_strlen(mbtrim($s));
if ($len < 1) { return ['名前は必須。']; }
if ($len > 50) { return ['名前は 50文字以内。']; }
else if ($len > 50) { return ['名前は 50文字以内。']; }
return [];
}

ファイルの表示

@ -33,7 +33,7 @@ function view_post($post, $options = []) {
$post_time_class = 'post-time';
if ($post['is_future']) { $post_time_class .= ' is-future'; }
if ($is_single || $detail_url <= '') {
if ($is_single || $detail_url == '') {
$html_time = '<span class="' . $post_time_class . '">' . $time . '</span>';
}
else {
@ -55,15 +55,15 @@ function view_post($post, $options = []) {
$html_attachment_items = join(PHP_EOL, $attachment_items);
?>
<dl<?= ($res_num > 0 ? ' id="N' . $res_num . '"' : '') ?>>
<?php if (!$is_single && $title > ''): ?>
<?php if (!$is_single && $title != ''): ?>
<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 > ''): ?>
<?php if ($link_to_thread && $thread_id != ''): ?>
<dd>RE: <a href="<?= $thread_url ?>"><?= $thread_title ?></a></dd>
<?php endif; ?>
<dd><?= $body ?>
<?php if (ENABLE_ATTACHMENT && $html_attachment_items > ''): ?>
<?php if (ENABLE_ATTACHMENT && $html_attachment_items != ''): ?>
<?= PHP_EOL ?>
<ul><?= $html_attachment_items ?></ul><?php endif; ?>
</dd>

ファイルの表示

@ -2,7 +2,7 @@
// Post form
?>
<?php if (ENABLE_POST): ?>
<?php if (isset($view['form']['thread_id']) && $view['form']['thread_id'] > ''): ?>
<?php if (isset($view['form']['thread_id']) && $view['form']['thread_id'] != ''): ?>
<h2 id="REPLY_FORM">返信・Reply</h2>
<?php endif; ?>
<?php if (!can_post()): ?>
@ -30,7 +30,7 @@ $view['form'] = $view['form'] ?? [];
<form method="POST" action="<?= sitebase('post/') ?>" enctype="multipart/form-data">
<ul>
<li><?= $view['logged_in'] ? 'ログイン中:<b>' . htmlspecialchars($view['login_user']['username']) . '</b>' : '<b>' . htmlspecialchars(GUESTNAME) . '</b>' ?>
<?php if (!(isset($view['form']['thread_id']) && $view['form']['thread_id'] > '')): ?>
<?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>
@ -41,7 +41,7 @@ $view['form'] = $view['form'] ?? [];
<li><label for="ATTACHMENT">画像 (gif/jpg/png・上限 500kb )</label> <input type="file" id="ATTACHMENT" name="attachment">
<?php endif; ?>
<li class="form-li-submit">
<?php if (isset($view['form']['thread_id']) && $view['form']['thread_id'] > ''): ?>
<?php if (isset($view['form']['thread_id']) && $view['form']['thread_id'] != ''): ?>
<input type="hidden" name="thread_id" value="<?= htmlspecialchars($view['form']['thread_id'] ?? '') ?>">
<?php endif; ?>
<?= output_csrf_token_hidden() ?>

ファイルの表示

@ -8,13 +8,13 @@ $reply_list = $view['reply_list'] ?? [];
$total = sizeof($reply_list) + 1;
$total_view = $total > 1 ? " ($total)" : '';
?>
<?php if ($title > ''): ?>
<?php if ($title != ''): ?>
<h2>件名:<?= htmlspecialchars("$title{$total_view}") ?></h2>
<?php elseif ($post['thread_id'] <= ''): ?>
<?php elseif ($post['thread_id'] == ''): ?>
<h2><?= htmlspecialchars('無題#' . mb_substr($post['id'], 0, 7) . $total_view) ?></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]);
?>
<?php
foreach ($reply_list as $i => $reply) {

ファイルの表示

@ -17,7 +17,7 @@ $reply_list_mode = isset($view['reply_list_mode']) && $view['reply_list_mode'];
$thread_url = $post['thread_url'] ?? '';
?>
<dl<?= ($reply_list_mode ? ' id="' . $no . '"' : '') ?>>
<?php if ($title > ''): ?>
<?php if ($title != ''): ?>
<dt><b>件名:<a href="<?= $detail_url ?>"><?= $title ?></a></b></dt>
<?php endif; ?>
<?php if ($is_guest): ?>

ファイルの表示

@ -3,7 +3,7 @@
?>
<dl>
<dt><b><?= htmlspecialchars($view['user']['username'] ?? '') ?></b> @<?= htmlspecialchars($view['user']['id']) ?></dt>
<?php if ($view['bio'] > ''): ?>
<?php if ($view['bio'] != ''): ?>
<dd><?= $view['bio'] /* bio is safe */ ?></dd>
<?php endif; ?>
<dd><b><?= $view['post_count'] ?></b> posts</dd>