フォーク元 tak4/bibis
199 行
4.6 KiB
PHP
199 行
4.6 KiB
PHP
<?php
|
|
// Data controller
|
|
|
|
// Post
|
|
|
|
require_once(__DIR__ . '/data-post.php');
|
|
|
|
// User
|
|
|
|
// ユーザー情報は USER_TSV (data/user.tsv) に保存される。
|
|
// 内容はタブ区切り・ヘッダー行は無い。
|
|
// {ID}<TAB>{名前}<TAB>{パスワードハッシュ値}<TAB>2chトリップ
|
|
|
|
$users_cache = null;
|
|
|
|
function load_users() {
|
|
global $users_cache;
|
|
|
|
if (isset($users_cache)) { return $users_cache; }
|
|
|
|
$users_cache = [];
|
|
$prev = @file_get_contents(USERS_TSV) ?? '';
|
|
$rows = explode(PHP_EOL, $prev);
|
|
$prev = null;
|
|
|
|
foreach ($rows as $row) {
|
|
$user = parse_user_row($row);
|
|
if ($user['id'] <= '') { continue; }
|
|
|
|
$user['hash_password'] = ''; // HIDE
|
|
$users_cache[$user['id']] = $user;
|
|
$user = null;
|
|
}
|
|
$rows = null;
|
|
$row = null;
|
|
|
|
return $users_cache;
|
|
}
|
|
|
|
function update_user($user) {
|
|
// 注意:ここを変更したら、必ず、ユーザーが消えない事をテストすること。
|
|
|
|
$id = $user['id'];
|
|
$username = $user['username'];
|
|
$password = $user['password'];
|
|
$trip = $user['trip'] ?? '';
|
|
|
|
$fp = @fopen(USERS_TSV, 'r+');
|
|
if ($fp === false || !flock($fp, LOCK_EX)) { return ['ファイルの取得に失敗。']; }
|
|
|
|
$prev = fread($fp, filesize(USERS_TSV));
|
|
if ($prev === false) { $prev = ''; }
|
|
|
|
$rows = explode(PHP_EOL, $prev);
|
|
$prev = null;
|
|
|
|
$output = '';
|
|
$search_id = $id . "\t";
|
|
$changed = false;
|
|
foreach ($rows as $row) {
|
|
if ($row === '') { continue; }
|
|
|
|
if (stripos($row, $search_id) !== 0) {
|
|
$output .= $row . PHP_EOL;
|
|
continue;
|
|
}
|
|
|
|
if ($password > '') {
|
|
$hash_password = hash_password($password);
|
|
} else {
|
|
$array = explode("\t", $row);
|
|
$hash_password = $array[2];
|
|
$array = null;
|
|
}
|
|
$output .= "{$id}\t{$username}\t{$hash_password}\t{$trip}" . PHP_EOL;
|
|
$id = null;
|
|
$username = null;
|
|
$hash_password = null;
|
|
$trip = null;
|
|
|
|
$changed = true;
|
|
}
|
|
$rows = null;
|
|
$row = null;
|
|
|
|
if (!$changed) { return ['ユーザーIDが不正。']; }
|
|
|
|
if (
|
|
!ftruncate($fp, 0)
|
|
|| !rewind($fp)
|
|
|| !fwrite($fp, $output)
|
|
|| !fflush($fp)
|
|
) { return ['ファイルの書き込みに失敗。']; }
|
|
|
|
@flock($fp, LOCK_UN);
|
|
@fclose($fp);
|
|
@chmod(USERS_TSV, 600);
|
|
|
|
return [];
|
|
}
|
|
|
|
function add_user($user) {
|
|
$id = $user['id'];
|
|
$username = $user['username'];
|
|
$password = $user['password'];
|
|
|
|
$match = find_user_row($id);
|
|
if (isset($match)) { return ['ID が既存ユーザーと重複。']; }
|
|
$match = null;
|
|
|
|
$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);
|
|
if ($result === false) { return ['ファイルの書き込みに失敗。']; }
|
|
@chmod(USERS_TSV, 600);
|
|
|
|
return [];
|
|
}
|
|
|
|
// Profile (bio)
|
|
|
|
// プロフィールは PROFILE_DIR (data/profile) 配下に {ID}.txt のファイル名で保存される。
|
|
// 先頭に「-」だけの行があり、それより後の行がプロフィール本文になる。
|
|
// 将来的に「-」より前の行にユーザーごとの設定値などを記録する予定。
|
|
|
|
function load_profile($id) {
|
|
$profile = @file_get_contents(PROFILE_DIR . $id . '.txt') ?? '';
|
|
if ($profile <= '') { return null; }
|
|
|
|
$split = preg_split('/^-$/m', $profile, 2);
|
|
$bio = mbtrim($split[1] ?? '');
|
|
|
|
return ['bio' => $bio];
|
|
}
|
|
|
|
function save_profile($id, $profile) {
|
|
$bio = $profile['bio'] ?? '';
|
|
|
|
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 [];
|
|
}
|
|
|
|
// Auth
|
|
|
|
function auth_user($id, $password) {
|
|
$id = trim($id);
|
|
|
|
$match = find_user_row($id);
|
|
if (!isset($match)) { return false; }
|
|
|
|
$user = parse_user_row($match);
|
|
if (hash_password($password) !== $user['hash_password']) { return false; }
|
|
|
|
return $user;
|
|
}
|
|
|
|
// Util
|
|
|
|
function find_user_row($id) {
|
|
$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;
|
|
}
|
|
}
|
|
|
|
return null;
|
|
}
|
|
|
|
function parse_user_row($row) {
|
|
$array = explode("\t", $row);
|
|
$id = $array[0] ?? '';
|
|
$username_raw = $array[1] ?? '';
|
|
$hash_password = $array[2] ?? '';
|
|
$trip = $array[3] ?? '';
|
|
$username = $username_raw . $trip;
|
|
$array = [];
|
|
|
|
return compact('id', 'username_raw', 'hash_password', 'trip', 'username');
|
|
}
|
|
|
|
function hash_password($password) {
|
|
$i = 0;
|
|
$hash = $password;
|
|
do {
|
|
$hash = hash('sha512', $hash . PASSWORD_SOLT);
|
|
$i++;
|
|
} while ($i < PASSWORD_ITER);
|
|
|
|
return $hash;
|
|
}
|