フォーク元 tak4/bibis
213 行
5.0 KiB
PHP
213 行
5.0 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);
|
|
unset($prev);
|
|
|
|
foreach ($rows as $row) {
|
|
$user = parse_user_row($row);
|
|
if ($user['id'] == '') { continue; }
|
|
|
|
$user['hash_password'] = ''; // HIDE
|
|
$users_cache[$user['id']] = $user;
|
|
unset($user);
|
|
}
|
|
unset($rows);
|
|
|
|
return $users_cache;
|
|
}
|
|
|
|
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+');
|
|
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];
|
|
unset($array);
|
|
}
|
|
$output .= "{$id}\t{$username}\t{$hash_password}\t{$trip}" . PHP_EOL;
|
|
unset($id);
|
|
unset($username);
|
|
unset($hash_password);
|
|
unset($trip);
|
|
|
|
$changed = true;
|
|
}
|
|
unset($rows);
|
|
|
|
if (
|
|
!ftruncate($fp, 0)
|
|
|| !rewind($fp)
|
|
|| !fwrite($fp, $output)
|
|
|| !fflush($fp)
|
|
) { return ['ファイルの書き込みに失敗。']; }
|
|
|
|
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 が既存ユーザーと重複。']; }
|
|
unset($match);
|
|
|
|
$hash_password = hash_password($password);
|
|
$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, 644);
|
|
|
|
return [];
|
|
}
|
|
|
|
// Profile (bio)
|
|
|
|
// プロフィールは PROFILE_DIR (data/profile) 配下に {ID}.txt のファイル名で保存される。
|
|
// 先頭に「-」だけの行があり、それより後の行がプロフィール本文になる。
|
|
// 将来的に「-」より前の行にユーザーごとの設定値などを記録する予定。
|
|
|
|
function load_profile($id) {
|
|
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] ?? '');
|
|
|
|
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 ['ファイルの書き込みに失敗。']; }
|
|
|
|
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;
|
|
}
|