Merge pull request '「スレ状態を管理するファイルの導入」「!774、!gobiコマンドの実装」「本文内でのシステムメッセージの構造を変更」等' (#41) from konkon-fox/delightly-v2fork:main into main

Reviewed-on: #41
This commit is contained in:
統計部員2 2023-11-11 22:28:44 +09:00
commit ca415d001d
10 changed files with 499 additions and 20 deletions

View File

@ -36,7 +36,19 @@ $DATFILE = $PATH."dat/".$_POST['thread'].".dat"; //Shift_JIS 専ブラ用 ※過
$HAP_PATH = './HAP/';
mb_substitute_character('entity');
$M = $ken = $ncolor = $Cookmail = $LV = $CAPID = $accountid = $supervisorID = '';
$stop = $admin = $sage = $supervisor = $authorized = $PROXY = false;
$stop = $admin = $sage = $supervisor = $authorized = $PROXY = $threadsStatesReload = false;
/**
* スレ状態を管理するファイルです。
* ファイルは各板直下に生成されます。
* $threadsStatesは各コマンドファイルにおいてjson_decode(file_get_contents($THREADS_STATES_FILE), true)で取得される連想配列です。
* $threadsStatesのキーはスレッド番号となります。
*
* @var string $THREADS_STATES_FILE
* @var array<string, array{'774':string, 'gobi': string}> $threadsStates
*/
$THREADS_STATES_FILE = $PATH.'threads-states.cgi';
include './extend/extra-commands/utilities/ThreadsStatesUpdater.php';
$threadsStatesUpdater = new ThreadsStatesUpdater($THREADS_STATES_FILE);
// GETメソッド
if ($_SERVER['REQUEST_METHOD'] != 'POST') Error2("invalid:GET");
@ -329,8 +341,20 @@ if (!$newthread && !$tlonly) {
if ($SETTING['BBS_FORCE_SAGE'] && $_POST['thread'] + $SETTING['BBS_FORCE_SAGE'] < $NOWTIME) $sage = true;
}
// システムメッセージ用関数
@include './extend/extra-commands/utilities/add-system-message.php';
// !chttコマンド
@include './extend/extra-commands/chtt.php';
// !774設定
@include './extend/extra-commands/set-774.php';
// !gobi設定
@include './extend/extra-commands/set-gobi.php';
// !774適用
@include './extend/extra-commands/apply-774.php';
// !gobi適用
@include './extend/extra-commands/apply-gobi.php';
// スレ状態更新処理
@include './extend/extra-commands/utilities/show-threads-states.php';
// !xDy(dice)コマンド
@include './extend/extra-commands/dice.php';
@ -1081,6 +1105,23 @@ file_put_contents($subjectfile, json_encode($PAGEFILE, JSON_UNESCAPED_UNICODE),
}
fclose($fp);
}
// スレ状態ファイルから現存しないスレ番号キーを削除
// 定期的に行う必要がある処理だが、各レスごとに行う必要はないため$threadsStatesReloadをフラグとする。
if ($threadsStatesReload && is_file($THREADS_STATES_FILE)) {
$threadKeysList = array_map(function ($thread) {
return (int) $thread['thread'];
}, $PAGEFILE);
$threadsStates = $threadsStatesUpdater->get();
if($threadsStates){
foreach(array_keys($threadsStates) as $threadKey){
if(!in_array((int) $threadKey, $threadKeysList, true)){
unset($threadsStates[$threadKey]);
}
}
$threadsStatesUpdater->put($threadsStates);
}
}
}
// 投稿ログ

View File

@ -0,0 +1,50 @@
<?php
/**
* 設定された!774コマンドに応じて本文に語尾を追加する処理
*
* @param array $SETTING 板の設定
* @param boolean $tlonly TL判定
* @param boolean $admin 管理者判定(管理人or常時コマンド権限を持つCAP)
* @param string $CAPID 投稿者がCAPの場合のID
* @param string $THREADS_STATES_FILE スレ状態ファイルへのパス
*/
function apply774Command(
$SETTING,
$tlonly,
$admin,
$CAPID,
$THREADS_STATES_FILE
) {
if($SETTING['commands'] !== 'checked') {
return;
}
if ($SETTING['DISABLE_NAME'] === 'checked') {
return;
}
if($tlonly) {
return;
}
if($admin || $CAPID) {
return;
}
if ($_POST['name'] !== '') {
return;
}
if (!is_file($THREADS_STATES_FILE)) {
return;
}
$threadsStates = json_decode(file_get_contents($THREADS_STATES_FILE), true);
if(!isset($threadsStates[$_POST['thread']]['774'])) {
return;
}
// 名前変更
$_POST['name'] = $threadsStates[$_POST['thread']]['774'];
}
apply774Command(
$SETTING,
$tlonly,
$admin,
$CAPID,
$THREADS_STATES_FILE
);

View File

@ -0,0 +1,42 @@
<?php
/**
* 設定された!gobiコマンドに応じて本文に語尾を追加する処理
*
* @param array $SETTING 板の設定
* @param boolean $tlonly TL判定
* @param string $THREADS_STATES_FILE スレ状態ファイルへのパス
*/
function applyGobiCommand(
$SETTING,
$tlonly,
$THREADS_STATES_FILE
) {
if($SETTING['commands'] !== 'checked') {
return;
}
if($tlonly) {
return;
}
if (strpos($_POST['name'], '!nocmd') !== false) {
return;
}
if (!is_file($THREADS_STATES_FILE)) {
return;
}
$threadsStates = json_decode(file_get_contents($THREADS_STATES_FILE), true);
if(!isset($threadsStates[$_POST['thread']]['gobi'])) {
return;
}
// 元本文のみ取得 ※<hr>以降はシステムメッセージなので対象外
$commentParts = explode('<hr>', $_POST['comment']);
// 語尾追加
$commentParts[0] .= $threadsStates[$_POST['thread']]['gobi'];
// 本文変更
$_POST['comment'] = implode('<hr>', $commentParts);
}
applyGobiCommand(
$SETTING,
$tlonly,
$THREADS_STATES_FILE
);

View File

@ -38,23 +38,20 @@ function applyChttCommand(
if(strpos($_POST['comment'], '!chtt:') === false) {
return;
}
if(!preg_match('/\!chtt:(.*?)((?=\<br\>)|$)/', $_POST['comment'], $commandMatches)) {
$commentParts = explode('<hr>', $_POST['comment']);
if(!preg_match('/\!chtt:(.*?)((?=\<br\>)|$)/', $commentParts[0], $commandMatches)) {
return;
}
// コマンド文字列から新スレタイを抽出
$newThreadTitle = trim($commandMatches[1]);
// 本文にシステムメッセージ用ラインを追加
if(strpos($_POST['comment'], '<hr>') === false) {
$_POST['comment'] .= '<hr>';
}
// 空欄エラー
if($newThreadTitle === '') {
$_POST['comment'] .= '★新スレタイが空欄です。<br>';
addSystemMessage('★新スレタイが空欄です。<br>');
return;
}
// スレタイ長すぎエラー
if(mb_strlen($newThreadTitle, 'UTF-8') > $SETTING['BBS_SUBJECT_COUNT']) {
$_POST['comment'] .= '★新スレタイが長すぎます。<br>';
addSystemMessage('★新スレタイが長すぎます。<br>');
return;
}
// スレタイにIDが存在するかを判定
@ -63,12 +60,14 @@ function applyChttCommand(
// 成功メッセージ出力(本文)
$oldThreadTitle = $titleHasId ? preg_replace('/\s\[[^\[]+?★\]$/', '', $subject) : $subject;
$changeMessage = "★スレタイ変更【{$oldThreadTitle}】→【{$newThreadTitle}】<br>";
$_POST['comment'] .= $changeMessage;
addSystemMessage($changeMessage);
// 成功メッセージ出力(>>1) datへの反映はbbs-main.phpで行われる
if(strpos($message, '<hr>') === false) {
$message .= '<hr>';
$messageParts = explode('<hr>', $message);
if(count($messageParts) < 2) {
array_push($messageParts, '');
}
$message .= preg_replace('/\!(?=[a-zA-Z0-9])/', '', $changeMessage);
$messageParts[1] .= preg_replace('/\!(?=[a-zA-Z0-9])/', '&#33;', $changeMessage);
$message = implode('<hr>', $messageParts);
// 新スレタイに>>1のIDを追加
if($titleHasId) {
$newThreadTitle .= " [{$IDMatches[1]}★]";

View File

@ -58,21 +58,19 @@ function applyDiceCommand($SETTING)
$commentParts[0],
$DICE_LIMIT
);
$newComment = implode('<hr>', $commentParts);
// 本文変更
$_POST['comment'] = implode('<hr>', $commentParts);
// 例外メッセージ
if($xIsOver || $yIsOver) {
if(strpos($newComment, '<hr>') === false) {
$newComment .= '<hr>';
}
$systemMessage = '';
if($xIsOver) {
$newComment .= "★x(ダイスの個数)の最大値は{$MAX_NUM_OF_DICE}です。<br>";
$systemMessage .= "★x(ダイスの個数)の最大値は{$MAX_NUM_OF_DICE}です。<br>";
}
if($yIsOver) {
$newComment .= "★y(ダイスの出目)の最大値は{$MAX_DICE_VALUE}です。<br>";
$systemMessage .= "★y(ダイスの出目)の最大値は{$MAX_DICE_VALUE}です。<br>";
}
addSystemMessage($systemMessage);
}
// 本文変更
$_POST['comment'] = $newComment;
}
applyDiceCommand($SETTING);

View File

@ -0,0 +1,100 @@
<?php
/**
* !774コマンドを設定する際の処理
*
* @param array $SETTING 板の設定
* @param boolean $supervisor スレ主判定
* @param boolean $admin 管理者判定(管理人or常時コマンド権限を持つCAP)
* @param boolean $newthread スレ立て時判定
* @param boolean $tlonly TL判定
* @param ThreadsStatesUpdater $threadsStatesUpdater スレ状態ファイルを更新するオブジェクト
* @param boolean $threadsStatesReload スレ状態の変化を>>1に反映するか判定
*/
function set774Command(
$SETTING,
$supervisor,
$admin,
$newthread,
$tlonly,
$threadsStatesUpdater,
&$threadsStatesReload
) {
if($SETTING['commands'] !== 'checked') {
return;
}
if ($SETTING['DISABLE_NAME'] === 'checked') {
return;
}
if($tlonly) {
return;
}
if(!($supervisor || $admin)) {
return;
}
if (strpos($_POST['name'], '!nocmd') !== false) {
return;
}
if(strpos($_POST['comment'], '!774:') === false) {
return;
}
$commentParts = explode('<hr>', $_POST['comment']);
if(!preg_match('/\!774:(.*?)((?=\<br\>)|$)/', $commentParts[0], $commandMatches)) {
return;
}
// デフォ名無しの最大文字数
$MAX_774_LENGTH = $SETTING['BBS_NAME_COUNT'];
$name = trim($commandMatches[1]);
// 例外処理
if(mb_strlen($name, 'UTF-8') > $MAX_774_LENGTH) {
addSystemMessage("★デフォ名無しの最大文字数は{$MAX_774_LENGTH}です。<br>");
return;
}
/* --置換処理ここから-- */
// 変換
if ($SETTING['change_sakujyo'] == "checked") {
$name = str_replace("管理", '"管理"', $name);
$name = str_replace("削除", '"削除"', $name);
$name = str_replace("sakujyo", '"sakujyo"', $name);
}
// 偽キャップ、偽トリップ変換
$name = str_replace("", "", $name);
$name = preg_replace("/&#0*9733([^0-9]|$)/", "", $name);
$name = preg_replace("/&#[xX]0*2605([^a-zA-Z0-9]|$)/", "", $name);
$name = str_replace("", "", $name);
$name = preg_replace("/&#0*9670([^0-9]|$)/", "", $name);
$name = preg_replace("/&#[xX]0*25[cC]6([^a-zA-Z0-9]|$)/", "", $name);
/* --置換処理ここまで-- */
// スレッド情報ファイルに書き込み
$threadsStates = $threadsStatesUpdater->get();
if($threadsStates === false) {
addSystemMessage("★!774コマンドの発動に失敗しました。<br>");
return;
}
if(isset($threadsStates[$_POST['thread']])) {
$threadsStates[$_POST['thread']]['774'] = $name;
} else {
$threadsStates[$_POST['thread']] = ['774' => $name];
}
$systemMessage = "★デフォ名無しを「{$name}」に設定しました。<br>";
if($name === '') {
unset($threadsStates[$_POST['thread']]['774']);
$systemMessage = "★デフォ名無しを取り消しました。<br>";
}
$threadsStatesUpdater->put($threadsStates);
// 成功メッセージ出力(本文)
if(!$newthread) {
addSystemMessage($systemMessage);
}
// >>1更新判定
$threadsStatesReload = true;
}
set774Command(
$SETTING,
$supervisor,
$admin,
$newthread,
$tlonly,
$threadsStatesUpdater,
$threadsStatesReload
);

View File

@ -0,0 +1,83 @@
<?php
/**
* !gobiコマンドを設定する際の処理
*
* @param array $SETTING 板の設定
* @param boolean $supervisor スレ主判定
* @param boolean $admin 管理者判定(管理人or常時コマンド権限を持つCAP)
* @param boolean $newthread スレ立て時判定
* @param boolean $tlonly TL判定
* @param ThreadsStatesUpdater $threadsStatesUpdater スレ状態ファイルを更新するオブジェクト
* @param boolean $threadsStatesReload スレ状態の変化を>>1に反映するか判定
*/
function setGobiCommand(
$SETTING,
$supervisor,
$admin,
$newthread,
$tlonly,
$threadsStatesUpdater,
&$threadsStatesReload
) {
if($SETTING['commands'] !== 'checked') {
return;
}
if($tlonly) {
return;
}
if(!($supervisor || $admin)) {
return;
}
if (strpos($_POST['name'], '!nocmd') !== false) {
return;
}
if(strpos($_POST['comment'], '!gobi:') === false) {
return;
}
$commentParts = explode('<hr>', $_POST['comment']);
if(!preg_match('/\!gobi:(.*?):/', $commentParts[0], $commandMatches)) {
return;
}
// 語尾の最大文字数
$MAX_GOBI_LENGTH = 100;
$MAX_GOBI_LENGTH = min($MAX_GOBI_LENGTH, floor($SETTING['BBS_MESSAGE_COUNT'] / 2));
$gobi = trim($commandMatches[1]);
// 例外処理
if(mb_strlen($gobi, 'UTF-8') > $MAX_GOBI_LENGTH) {
addSystemMessage("★語尾の最大文字数は{$MAX_GOBI_LENGTH}です。<br>");
return;
}
// スレッド情報ファイルに書き込み
$threadsStates = $threadsStatesUpdater->get();
if($threadsStates === false) {
addSystemMessage("★!gobiコマンドの発動に失敗しました。<br>");
return;
}
if(isset($threadsStates[$_POST['thread']])) {
$threadsStates[$_POST['thread']]['gobi'] = $gobi;
} else {
$threadsStates[$_POST['thread']] = ['gobi' => $gobi];
}
$systemMessage = "★語尾を「{$gobi}」に設定しました。<br>";
if($gobi === '') {
unset($threadsStates[$_POST['thread']]['gobi']);
$systemMessage = "★語尾を取り消しました。<br>";
}
$threadsStatesUpdater->put($threadsStates);
// 成功メッセージ出力(本文)
if(!$newthread) {
addSystemMessage($systemMessage);
}
// >>1更新判定
$threadsStatesReload = true;
}
setGobiCommand(
$SETTING,
$supervisor,
$admin,
$newthread,
$tlonly,
$threadsStatesUpdater,
$threadsStatesReload
);

View File

@ -0,0 +1,70 @@
<?php
/**
* スレ情報ファイルthreads-states.cgiの更新を行うためのクラスです。
* get()でファイルをロックしput()でロックを解除するので必ずセットで使ってください。※get()でfalseを返した場合put()は不要です。
* 内容の取得のみを使いたい場合はこのクラスではなくfile_get_contentsを使用してください。
*/
class ThreadsStatesUpdater
{
private $path;
private $file;
/**
* @param string $path threads-states.cgiへのパス
*/
public function __construct($path)
{
$this->path = $path;
}
/**
* threads-states.cgiの内容を取得するメソッド
*
* @return array|false
*/
public function get()
{
if(!is_file($this->path)) {
return [];
}
$this->file = fopen($this->path, 'r+');
if(!flock($this->file, LOCK_EX)) {
fclose($this->file);
unset($this->file);
return false;
}
clearstatcache();
$text = fread($this->file, filesize($this->path));
return json_decode($text, true);
}
/**
* threads-states.cgiに新しい内容を書き込むメソッド
*
* @param array $threadsStates スレ状態
* @return boolean 成功判定
*/
public function put($threadsStates)
{
if(!is_file($this->path)) {
$this->file = fopen($this->path, 'w+');
if(!flock($this->file, LOCK_EX)) {
fclose($this->file);
unset($this->file);
return false;
}
}
if(!isset($this->file)) {
return false;
}
$data = json_encode($threadsStates, JSON_UNESCAPED_UNICODE);
ftruncate($this->file, 0);
rewind($this->file);
fwrite($this->file, $data);
flock($this->file, LOCK_UN);
fclose($this->file);
unset($this->file);
return true;
}
}

View File

@ -0,0 +1,16 @@
<?php
/**
* コマンド処理でのシステムメッセージを本文に追加する関数定義
*
* @param string $text 追加したいシステムメッセージ
* @return void
*/
function addSystemMessage($text)
{
$commentParts = explode('<hr>', $_POST['comment']);
if(count($commentParts) < 2) {
array_push($commentParts, '');
}
$commentParts[1] .= $text;
$_POST['comment'] = implode('<hr>', $commentParts);
}

View File

@ -0,0 +1,80 @@
<?php
/**
* コマンドによって変更されたスレ状態を>>1に反映する処理
*
* @param array $SETTING 板の設定
* @param boolean $newthread スレ立て時判定
* @param boolean $tlonly TL判定
* @param boolean $threadsStatesReload スレ状態の変化を>>1に反映するか判定
* @param string $THREADS_STATES_FILE スレ状態ファイルへのパス
* @param string &$message >>1の本文
* @param boolean &$reload >>1更新フラグ
* @return void
*/
function showThreadsStates(
$SETTING,
$newthread,
$tlonly,
$threadsStatesReload,
$THREADS_STATES_FILE,
&$message,
&$reload
) {
if($SETTING['commands'] !== 'checked') {
return;
}
if($tlonly) {
return;
}
if(!$threadsStatesReload) {
return;
}
if(!is_file($THREADS_STATES_FILE)) {
return;
}
// >>1の本文取得
if($newthread) {
$comment = $_POST['comment'];
} else {
$comment = $message;
}
// >>1の本文を3分割
$commentParts = explode('<hr>', $comment);
for($i = count($commentParts);$i <= 3;$i++) {
array_push($commentParts, '');
}
$commentParts[2] = '';
$threadsStates = json_decode(file_get_contents($THREADS_STATES_FILE), true);
// デフォ名無し情報追加
if(isset($threadsStates[$_POST['thread']]['774'])) {
$defaultName = $threadsStates[$_POST['thread']]['774'];
$defaultName = preg_replace('/\!(?=[a-zA-Z0-9])/', '&#33;', $defaultName);
$commentParts[2] .= "<font color=\"red\">※デフォ名無し=</font>{$defaultName}<br>";
}
// 語尾情報追加
if(isset($threadsStates[$_POST['thread']]['gobi'])) {
$gobi = $threadsStates[$_POST['thread']]['gobi'];
$gobi = preg_replace('/\!(?=[a-zA-Z0-9])/', '&#33;', $gobi);
$commentParts[2] .= "<font color=\"red\">※GOBI=</font>{$gobi}<br>";
}
// 分割された本文を統合
$comment = implode('<hr>', $commentParts);
$comment = preg_replace('/(<hr>)+$/', '', $comment);
// 元本文に反映
if($newthread) {
$_POST['comment'] = $comment;
} else {
$message = $comment;
$reload = true;
}
}
showThreadsStates(
$SETTING,
$newthread,
$tlonly,
$threadsStatesReload,
$THREADS_STATES_FILE,
$message,
$reload
);