From c7537ab36f8a1fe8424d1c0036c0702ae5cbdd41 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?=E8=AB=8F=E8=A8=AA=E5=AD=90?=
+ 登録して下さい。
+
+
";
+ if (!$resPwd->isSuccess) $err .= $resPwd->message."
";
+ if (!$resEml->isSuccess) $err .= $resEml->message."
";
+
+ if ($err != '') return \Result::Error($err);
+ $err = '';
+
+ if (!mkdir($this->assDir.$username, 0755)) {
+ return \Result::Error('エラー:ユーザーのアイコンディレクトリの作成に失敗。');
+ }
+
+ $file = scandir($this->dataDir);
+ $lastId = 0;
+ if ($file) {
+ foreach ($file as $f) {
+ if ($f === '.kara' || $f === '.' || $f === '..') continue;
+ $base = substr($f, 0, -5); // .jsonの削除
+ $dot = strpos($base, '.');
+ if (!$dot) continue;
+ $id = substr($base, 0, $dot);
+ if (ctype_digit($id)) {
+ if ((int)$id > $lastId) $lastId = $id;
+ }
+ }
+ $lastId++;
+ }
+
+ $user = new \stdClass;
+ $user->id = $lastId;
+ $user->username = $username;
+ $user->password = password_hash($password, $algo);
+ $user->avatar = '';
+ $user->email = $email;
+ $user->regDate = time();
+ $user->namecolor = '';
+ $user->displayname = '';
+ $user->gender = -1;
+ $user->role = 0;
+ $user->tokens = [];
+
+ $path = "{$this->dataDir}{$lastId}.{$username}.json";
+ $json = json_encode($user, JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES);
+
+ if (file_put_contents($path, $json) === false) {
+ rmdir($this->assDir.$username);
+ return \Result::Error('エラー:ユーザーデータの保存に失敗。');
+ }
+
+ return \Result::Success();
+ }
+
////////////////////
+ private function verifyLogin(string $username, string $password): \Result {
+ $userData = $this->getUserData();
+ if ($username !== $userData->username || !password_verify($password, $userData->password)) {
+ return \Result::Error('エラー:ユーザー名又はパスワードが一致していません。');
+ }
+
+ if (password_needs_rehash($userData->password, $algo)) {
+ $userData->password = password_hash($password, $algo);
+ $path = $this->dataDir.$this->id.'.'.$userData->username.'.json';
+ $json = json_encode($userData, JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES);
+
+ if (file_put_contents($path, $json) === false) {
+ return \Result::Error('エラー:ユーザーデータの保存に失敗。');
+ }
+ }
+
+ return \Result::Success();
+ }
+
private function purgeOldTokens(\stdClass $userData): \stdClass|\Result {
// 有効期限切れたトークンの削除
$out = $userData;
@@ -178,7 +235,7 @@ class Auth {
$json = json_encode($userData, JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES);
if (file_put_contents($path, $json) === false) {
- return \Result::error('エラー:ユーザーデータの保存に失敗。');
+ return \Result::Error('エラー:ユーザーデータの保存に失敗。');
}
return $out;
@@ -191,7 +248,7 @@ class Auth {
$id = 0;
foreach ($file as $f) {
- if ($f === '.' || $f === '..') continue;
+ if ($f === '.kara' || $f === '.' || $f === '..') continue;
$path = "{$this->dataDir}{$f}";
if (!is_file($path)) continue;
@@ -215,7 +272,7 @@ class Auth {
$matches = [];
foreach ($file as $f) {
- if ($f === '.' || $f === '..') continue;
+ if ($f === '.kara' || $f === '.' || $f === '..') continue;
if (preg_match('/^'.$this->id.'\.(.*?)\.json$/', $f, $matches)) {
$userFile = $matches[0];
break;
@@ -239,41 +296,82 @@ class Auth {
return json_decode($lines);
}
- private function isEmailExist(?string $email): \Result {
- if (null === $password) return \Result::Error('エラー:パスワードをご入力下さい。');
+ private function isEmailExist(?string $email = null): \Result {
+ $userList = scandir($this->dataDir);
+ $matches = [];
+
+ foreach ($userList as $f) {
+ if ($f === '.kara' || $f === '.' || $f === '..') continue;
+ $path = "{$this->dataDir}{$f}";
+ if (!is_file($path)) continue;
+ $content = file_get_contents($path);
+ $file = str_replace('.json', '', $f);
+ if (str_contains($content, '"email": "'.$email.'",')) {
+ $matches[] = $email;
+ }
+ if (count($matches) > 0) return \Result::Error("ユーザー「{$email}」は既に存在します。");
+ }
+
+ return \Result::Success('エラー:メールアドレスが存在しません。');
+ }
+
+ private function verifyEmail(?string $email = null): \Result {
+ if (null === $email || '' === $email) return \Result::Error('エラー:メールアドレスをご入力下さい。');
+ if (strpos($email, '@') === false) return \Result::Error('エラー:メールアドレスは不正です。');
+
+ $domain = explode('@', $email)[1];
+ if (!filter_var($email, FILTER_VALIDATE_EMAIL)) {
+ return \Result::Error('エラー:メールアドレスは不正です。');
+ }
+
+ if (!checkdnsrr($domain, 'MX')) {
+ return \Result::Error('エラー:メールアドレスは不正です。');
+ }
+
+ $res = $this->isEmailExist($email);
+ if (!$res->isSuccess) return \Result::Error($res->message);
+
+ return \Result::Success();
}
private function verifyUsername(?string $username): \Result {
- if (null === $username) return \Result::Error('エラー:ユーザー名をご入力下さい。');
+ if (null === $username || '' === $username) return \Result::Error('エラー:ユーザー名をご入力下さい。');
if (strlen($username) < 6) return \Result::Error('エラー:ユーザー名は6文字以上をご入力下さい。');
- $accepted = 'A-Za-z0-9';
+ $res = $this->isUserExist($username);
+ if ($res->isSuccess) return \Result::Error($res->message);
- if (preg_match('/[^'.preg_quote($accepted, '/').']/', $password)) {
+ $accepted = 'A-Za-z0-9';
+ if (preg_match("/[^{$accepted}]/", $username)) {
return \Result::Error('エラー:ユーザー名に不正な文字が含みます。');
}
+
return \Result::Success();
}
- private function verifyPassword(?string $password): \Result {
+ private function verifyPassword(?string $password = null, ?string $passwordVerify = null): \Result {
+ if (null === $password || '' === $password) return \Result::Error('エラー:パスワードをご入力下さい。');
+ if ($password !== $passwordVerify) return \Result::Error('エラー:パスワードは一致していません。');
+
+ $res = $this->checkPasswordStandards($password);
+ if (!$res->isSuccess) {
+ return \Result::Error($res->message);
+ }
+
return \Result::Success();
}
- private function checkPasswordStandards(?string $password): \Result {
- if (null === $password) return \Result::Error('エラー:パスワードをご入力下さい。');
- if (strlen($password) < $this->minPassLen) return \Result::Error("エラー:パスワード数は{$this->minPassLen}以上をご入力下さい。");
+ private function checkPasswordStandards(?string $password = null): \Result {
+ if (strlen($password) < $this->minPassLen) return \Result::Error("エラー:パスワードは{$this->minPassLen}以上をご入力下さい。");
- $specChar = '!"#$%&\'()*+,-./:;<=>?@[\\]^_`{|}~]/';
- $accepted = 'A-Za-z0-9'.$specChar;
-
- if (preg_match('/[^'.preg_quote($accepted, '/').']/', $password)) {
+ if (!\countmatch($password)) {
return \Result::Error('エラー:パスワードに不正な文字が含みます。');
}
$countUpper = preg_match_all('/[A-Z]/', $password) < 2;
$countLower = preg_match_all('/[a-z]/', $password) < 2;
$countDigit = preg_match_all('/[0-9]/', $password) < 2;
- $countSymbol = preg_match_all('/['.$specChar.']/', $password) < 2;
+ $countSymbol = \count_special_chars($password) < 2;
if ($countUpper || $countLower || $countDigit || $countSymbol) {
return \Result::Error('エラー:パスワードは2つ以上の大文字、2つ以上の小文字、2つ以上の数字、及び2つ以上の特別文字を含む事が必須です。');
diff --git a/util.php b/util.php
index 03473e1..05e5b48 100644
--- a/util.php
+++ b/util.php
@@ -151,7 +151,7 @@ if (AUTH_ENABLED) {
$gender = 'color: '.($userData->gender === 0 ? $male : ($userData->gender === 1 ? $female : $ungender)).';';
$style = $userData->namecolor ?: ($userData->role >= 0 ? $gender : $ban);
- $showname = $userData->displayname ?? $userData->username;
+ $showname = $userData->displayname ?: $userData->username;
$color = "{$showname}";
if ($userData->role === 1) $color .= "✓";
@@ -160,4 +160,58 @@ if (AUTH_ENABLED) {
return $color.$suffix;
}
+}
+
+function count_special_chars(string $str): int {
+ $count = 0;
+ $len = strlen($str);
+
+ for ($i = 0; $i < $len; ++$i) {
+ if (str_contains('!', $str[$i])) ++$count;
+ if (str_contains('"', $str[$i])) ++$count;
+ if (str_contains('#', $str[$i])) ++$count;
+ if (str_contains('$', $str[$i])) ++$count;
+ if (str_contains('%', $str[$i])) ++$count;
+ if (str_contains('&', $str[$i])) ++$count;
+ if (str_contains('\'', $str[$i])) ++$count;
+ if (str_contains('(', $str[$i])) ++$count;
+ if (str_contains(')', $str[$i])) ++$count;
+ if (str_contains('-', $str[$i])) ++$count;
+ if (str_contains('=', $str[$i])) ++$count;
+ if (str_contains('^', $str[$i])) ++$count;
+ if (str_contains('~', $str[$i])) ++$count;
+ if (str_contains('\\', $str[$i])) ++$count;
+ if (str_contains('|', $str[$i])) ++$count;
+ if (str_contains('[', $str[$i])) ++$count;
+ if (str_contains(']', $str[$i])) ++$count;
+ if (str_contains(':', $str[$i])) ++$count;
+ if (str_contains('@', $str[$i])) ++$count;
+ if (str_contains('`', $str[$i])) ++$count;
+ if (str_contains('*', $str[$i])) ++$count;
+ if (str_contains('{', $str[$i])) ++$count;
+ if (str_contains('}', $str[$i])) ++$count;
+ if (str_contains(';', $str[$i])) ++$count;
+ if (str_contains('+', $str[$i])) ++$count;
+ if (str_contains(',', $str[$i])) ++$count;
+ if (str_contains('<', $str[$i])) ++$count;
+ if (str_contains('.', $str[$i])) ++$count;
+ if (str_contains('>', $str[$i])) ++$count;
+ if (str_contains('/', $str[$i])) ++$count;
+ if (str_contains('?', $str[$i])) ++$count;
+ if (str_contains('_', $str[$i])) ++$count;
+ }
+
+ return $count;
+}
+
+function countmatch(string $str): bool {
+ $len = strlen($str);
+
+ $numUpper = preg_match_all('/[A-Z]/', $str) ?? 0;
+ $numLower = preg_match_all('/[a-z]/', $str) ?? 0;
+ $numDigit = preg_match_all('/[0-9]/', $str) ?? 0;
+ $numSymbol = count_special_chars($str);
+ $sum = $numUpper + $numLower + $numDigit + $numSymbol;
+
+ return $len == $sum;
}
\ No newline at end of file
diff --git a/view/register.maron b/view/register.maron
new file mode 100644
index 0000000..eb50d6d
--- /dev/null
+++ b/view/register.maron
@@ -0,0 +1,47 @@
+{@ include(common/header) @}
+ 登録
+
+
+ +{@ include(common/footer) @} \ No newline at end of file