📄 Source: users.php
<?php
/**
* JSON-backed user store. Passwords hashed with password_hash().
* Each account may optionally be bound to a device token.
*/
function users_file(): string {
return __DIR__ . '/../data/users.json';
}
function users_load(): array {
$f = users_file();
if (!is_file($f)) {
return ['users' => []];
}
$raw = file_get_contents($f);
$data = json_decode($raw, true);
if (!is_array($data) || !isset($data['users'])) {
return ['users' => []];
}
return $data;
}
function users_save(array $data): void {
$f = users_file();
$dir = dirname($f);
if (!is_dir($dir)) {
mkdir($dir, 0700, true);
}
file_put_contents($f, json_encode($data, JSON_PRETTY_PRINT), LOCK_EX);
@chmod($f, 0600);
}
function users_find(string $username): ?array {
$data = users_load();
foreach ($data['users'] as $u) {
if (strcasecmp($u['username'], $username) === 0) {
return $u;
}
}
return null;
}
function users_ensure_owner(string $username, string $password): void {
if (users_find($username) !== null) {
return;
}
$data = users_load();
$data['users'][] = [
'username' => $username,
'password_hash' => password_hash($password, PASSWORD_BCRYPT),
'is_owner' => true,
'device_bound' => false,
'device_token' => null,
'created_at' => time(),
];
users_save($data);
}
function users_verify(string $username, string $password): ?array {
$u = users_find($username);
if ($u === null) {
return null;
}
if (!password_verify($password, $u['password_hash'])) {
return null;
}
return $u;
}
function users_create(string $username, string $password, bool $device_bound): bool {
if (users_find($username) !== null) {
return false;
}
$data = users_load();
$data['users'][] = [
'username' => $username,
'password_hash' => password_hash($password, PASSWORD_BCRYPT),
'is_owner' => false,
'device_bound' => $device_bound,
'device_token' => null,
'created_at' => time(),
];
users_save($data);
return true;
}
function users_delete(string $username): bool {
$data = users_load();
$before = count($data['users']);
$data['users'] = array_values(array_filter(
$data['users'],
fn($u) => strcasecmp($u['username'], $username) !== 0 || $u['is_owner']
));
if (count($data['users']) === $before) {
return false;
}
users_save($data);
return true;
}
function users_bind_device(string $username, string $token): void {
$data = users_load();
foreach ($data['users'] as &$u) {
if (strcasecmp($u['username'], $username) === 0) {
$u['device_token'] = $token;
$u['device_bound'] = true;
}
}
unset($u);
users_save($data);
}
function users_unbind_device(string $username): void {
$data = users_load();
foreach ($data['users'] as &$u) {
if (strcasecmp($u['username'], $username) === 0) {
$u['device_token'] = null;
$u['device_bound'] = false;
}
}
unset($u);
users_save($data);
}
← Back