isSuccess = $isSuccess; $this->message = $message; } public static function Success(?string $message = null): self { return new self(true, $message); } public static function Error(string $message): self { return new self(false, $message); } } function uuid(): string { $data = random_bytes(16); $data[6] = chr(ord($data[6]) & 0x0f | 0x40); $data[8] = chr(ord($data[8]) & 0x3f | 0x80); return vsprintf('%s%s-%s-%s-%s-%s%s%s', str_split(bin2hex($data), 4)); } function kys(mixed $arg): void { if (gettype($arg) == 'boolean') $arg = $arg === true ? 'true' : 'false'; if (gettype($arg) == 'array' || gettype($arg) == 'object') { foreach ($arg as $a) { if (gettype($a) == 'boolean') $a = $a === true ? 'true' : 'false'; } } echo ''; echo '
KILL
YOUR
SELF
'; echo '
';
  print_r($arg);
  echo '
';
  die();
}

function base58btc_encode(string $bin): string {
  $a = '123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz';
  $base = 58;
  $num = \gmp_import($bin, 1, GMP_LSW_FIRST | GMP_NATIVE_ENDIAN);
  $res = '';

  if (\gmp_cmp($num, 0) == 0) return '1';

  while (\gmp_cmp($num, 0) > 0) {
    $mod = \gmp_intval(\gmp_mod($num, $base));
    $res = $a[$mod].$res;
    $num = \gmp_div_q($num, $base);
  }

  $bytes = str_split($bin);
  foreach ($bytes as $byte) {
    if (ord($byte) === 0) {
      $res = '1'.$res;
    } else {
      break;
    }
  }

  return $res;
}

function logger(LogType $section, mixed $arg): void {
  if (LOGGING_ENABLED) {
    $logfile = ROOT.'/log/';
    if ($section == LogType::ActivityPub) $logfile .= 'ap_log.txt';
    else if ($section == LogType::Mailer) $logfile .= 'mail_log.txt';
    else if ($section == LogType::MySQL) $logfile .= 'mysql_log.txt';
    else if ($section == LogType::Csv) $logfile .= 'csv_log.txt';

    file_put_contents($logfile, $arg."\n", FILE_APPEND);
  }
}

function to_money($amount, $lang) {
  $amount = floatval($amount);

  switch (strtolower($lang)) {
    case 'ja':
      if ($amount >= 100000000) {
        $oku = $amount / 100000000;
        return $oku.'億円';
      } else if ($amount >= 10000) {
        $man = $amount / 10000;
        return $man.'万円';
      }
      return number_format($amount, 0).'円';
    case 'en':
      if ($amount >= 1000000000) {
        $billion = $amount / 1000000000;
        return '¥ '.$billion.' billion';
      } else if ($amount >= 1000000) {
        $million = $amount / 1000000;
        return '¥ '.$million.' million';
      } else if ($amount >= 1000) {
        $thousand = $amount / 1000;
        return '¥ '.$thousand.' thousand';
      }
      return '¥ '.number_format($amount, 0);
    default:
      return '¥ '.number_format($amount, 0);
  }
}

function randstr(): string {
  srand((int)floor(time() / (60*60*24)));
  $len = rand(1, 20);
  return bin2hex(random_bytes($len));
}

function assert_null(mixed $assertion, Throwable|string|null $description = null): bool {
  if (ini_get('zend.assertions') < 1) trigger_error('assert機能性が無効です。有効するには、php.iniで「zend.assertions = 1」に設定して下さい。', E_USER_WARNING);
  if (is_null($assertion)) return true;
  assert(false, $description ?? 'Assertion failed: value is not null');
  return false;
}

function assert_not_null(mixed $assertion, Throwable|string|null $description = null): bool {
  if (ini_get('zend.assertions') < 1) trigger_error('assert機能性が無効です。有効するには、php.iniで「zend.assertions = 1」に設定して下さい。', E_USER_WARNING);
  if (!is_null($assertion)) return true;
  assert(false, $description ?? 'Assertion failed: value is null');
  return false;
}

function assert_unless_success(Result $assertion, Throwable|string|null $description = null): bool {
  if (ini_get('zend.assertions') < 1) trigger_error('assert機能性が無効です。有効するには、php.iniで「zend.assertions = 1」に設定して下さい。', E_USER_WARNING);
  if ($assertion->isSuccess) return true;
  assert(false, $description ?? $assertion->message ?? 'Assertion failed: Result is not successful');
  return false;
}

if (AUTH_ENABLED) {
  function getcookie(string $name): string|null {
    return $_COOKIE[$name] ?? null;
  }

  function namecolor(\stdClass $userData): string {
    $ban = "#888888";
    $male = "#97ACEF";
    $female = "#F185C9";
    $ungender = "#7C60B0";

    $gender = 'color: '.($userData->gender === 0 ? $male : ($userData->gender === 1 ? $female : $ungender)).';';
    $style = $userData->namecolor ?: ($userData->role >= 0 ? $gender : $ban);

    $showname = $userData->displayname ?: $userData->username;

    $color = "{$showname}";
    if ($userData->role === 1) $color .= "";

    $suffix = $userData->gender === 0 ? 'くん' : ($userData->gender === 1 ? 'ちゃん' : 'さん');

    return $color.$suffix;
  }

  function make_csrf_token(?bool $force = false): string {
    if (null !== getcookie('csrf_token') && !$force) return getcookie('csrf_token');
    $token = bin2hex(random_bytes(32));
    setcookie('csrf_token', $token, [
      'expires' => time() + 300, // 5分
      'path' => '/',
      'domain' => $_SERVER['SERVER_NAME'],
      'secure' => (!empty($_SERVER['HTTPS']) && $_SERVER['HTTPS'] !== 'off'),
      'httponly' => true,
      'samesite' => 'Strict'
    ]);
    return $token;
  }

  function verify_csrf_token(string $token): bool {
    return hash_equals(getcookie('csrf_token'), $token);
  }
}

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;
}