forked from berhsi/matrix-register
340 lines
10 KiB
PHP
340 lines
10 KiB
PHP
<?php
|
|
|
|
/**
|
|
* file: db.php
|
|
* date: 25.01.2021
|
|
* author: bernd@nr18.space
|
|
* desc: Anbindung an die (Postgres) Datenbank.
|
|
*/
|
|
|
|
|
|
function testDriver(): bool
|
|
{
|
|
print_r(PDO::getAvailableDrivers());
|
|
return true;
|
|
}
|
|
|
|
function getDatabase(&$config, $log): Database {
|
|
|
|
/**
|
|
* Erstellt ein Datenbank Objekt und gibt dieses zurück. Im Fehlerfall
|
|
* wird eine Exception mit der Meldung der PDOException ausgelöst.
|
|
*/
|
|
|
|
try {
|
|
$pdo = Connection::get()->connect($config);
|
|
$db = new Database($pdo, $log);
|
|
} catch (PDOException $e) {
|
|
throw new Exception($e->getMessage());
|
|
}
|
|
return $db;
|
|
}
|
|
|
|
class Connection {
|
|
|
|
/**
|
|
* Stellt die Verbindung zur Datenbank her. Derzeit sind Postgres, MySQL
|
|
* und SQLite Datenbanken möglich.
|
|
*/
|
|
|
|
private static $conn;
|
|
|
|
public function connect(&$config)
|
|
{
|
|
|
|
$driver = $config->getDbDriver();
|
|
$file = $config->getDbFile();
|
|
$host = $config->getDbHost();
|
|
$port = $config->getDbPort();
|
|
$base = $config->getDbBase();
|
|
$user = $config->getDbUser();
|
|
$pass = $config->getDbPass();
|
|
|
|
try {
|
|
if ($driver === "PDO_PGSQL") {
|
|
$pdo = new PDO("pgsql:host=$host;port=$port;dbname=$base", $user, $pass);
|
|
}
|
|
else if ($driver === "PDO_SQLITE") {
|
|
$pdo = new PDO("sqlite:$file");
|
|
}
|
|
else {
|
|
throw new Exception("Wrong driver for database: {$driver}");
|
|
return false;
|
|
}
|
|
} catch (PDOException $e) {
|
|
throw new Exception($e->getMessage());
|
|
}
|
|
if (isset($pdo)) {
|
|
$pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
|
|
}
|
|
return $pdo;
|
|
}
|
|
|
|
public static function get()
|
|
{
|
|
if (null === static::$conn)
|
|
{
|
|
static::$conn = new static();
|
|
}
|
|
return static::$conn;
|
|
}
|
|
|
|
public static function close()
|
|
{
|
|
static::$conn = null;
|
|
return true;
|
|
}
|
|
|
|
}
|
|
|
|
|
|
class Database {
|
|
|
|
/**
|
|
* Stellt das Datenbankobjekt und die Methoden zum Arbeiten mit der
|
|
* Datenbank zur verfügung.
|
|
*/
|
|
|
|
private $pdo;
|
|
private $log;
|
|
|
|
public function __construct($pdo, $log)
|
|
{
|
|
$this->pdo = $pdo;
|
|
$this->log = $log;
|
|
$this->log->d(Databaseobject created);
|
|
// hier vielleicht TableCreate hin
|
|
|
|
}
|
|
|
|
public function TableExists(): int
|
|
{
|
|
$stmt = "SELECT * FROM information_schema.tables WHERE
|
|
table_type = 'BASE TABLE' and
|
|
table_name = 'requests'";
|
|
$response = $this->pdo->query($stmt);
|
|
$count = $response->rowCount();
|
|
return $count;
|
|
}
|
|
|
|
public function createTable()
|
|
{
|
|
$stmt = "CREATE TABLE IF NOT EXISTS requests (
|
|
id serial PRIMARY KEY,
|
|
nick varchar(80) NOT NULL UNIQUE,
|
|
email varchar(80) NOT NULL,
|
|
token char(32) NOT NULL UNIQUE,
|
|
time integer NOT NULL);";
|
|
$this->pdo->exec($stmt);
|
|
return $this;
|
|
}
|
|
|
|
|
|
public function UserExistsInUsers(string $nick): bool
|
|
{
|
|
/**
|
|
* Sucht in der Tabelle users nach bereits angelegten Nutzern. Die
|
|
* Abfrage der Datenbank wird an die Funktion searchUser delegiert.
|
|
* Sollte diese eine Exception werfen, wird true (es gibt einen
|
|
* Benutzer) zurück gegeben. Ansonsten wird der Rückgabewert
|
|
* von der Funktion getNick ausgewertet, die aus der übergebenen
|
|
* Matrix-ID den localpart extrahiert.
|
|
*/
|
|
|
|
$this->log->d("Search for localpart {$nick} in users");
|
|
$query = "SELECT name FROM users WHERE name LIKE :nick";
|
|
$pattern = "%$nick%";
|
|
try {
|
|
$response = $this->searchUser($query, $pattern);
|
|
} catch (PDOException $e) {
|
|
$this->log->e("searchUser() returns true because PDOException");
|
|
return true;
|
|
}
|
|
$count = count($response);
|
|
if ($count == 0)
|
|
{
|
|
$this->log->d("Nothing found");
|
|
return false;
|
|
}
|
|
else
|
|
{
|
|
foreach ($response as $array) {
|
|
$uid = $this->getNick($array['name']);
|
|
$this->log->d("Compare {$nick} with {$uid}");
|
|
if ($uid === $nick) {
|
|
$this->log->i("MID localpart already exists: {$nick}");
|
|
return true;
|
|
} else {
|
|
$this->log->d("False");
|
|
}
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
|
|
public function UserExistsInRequests(string $nick): bool
|
|
{
|
|
/**
|
|
* Sucht in der Tabelle requests nach breits beantragten
|
|
* Nutzernamen. Die Abfrage der Datenbank wird an die Funktion
|
|
* searchUser delegiert. Sollte diese eine Exception werfen, wird
|
|
* true (es gibt einen benutzer) zurück gegeben. Ansonsten wird die
|
|
* Anzahl der Treffer ausgewertet.
|
|
*/
|
|
|
|
$this->log->d("Search for localpart {$nick} in requests");
|
|
$query = "SELECT nick FROM requests WHERE nick = :nick";
|
|
try {
|
|
$response = $this->searchUser($query, $nick);
|
|
} catch (PDOException $e) {
|
|
$this->log->e("searchUser() returns true because PDOException");
|
|
return true;
|
|
}
|
|
$count = count($response);
|
|
if ($count > 0) {
|
|
$this->log->d("Search for {$nick}: {$count} hit(s)");
|
|
return true;
|
|
}
|
|
$this->log->d("Nothing found");
|
|
return false;
|
|
}
|
|
|
|
private function searchUser(string $query, string $nick): array
|
|
{
|
|
/**
|
|
* Führt die Suchoperartion auf der Datenbank aus. Bekommt dafür den
|
|
* Querystring und den Nick übergeben. Sollte Abfrage der Datenbank
|
|
* fehlschlagen, wirft die Funktion die Exception an die aufrufende
|
|
* Funktion.
|
|
*/
|
|
|
|
try
|
|
{
|
|
$stmt = $this->pdo->prepare($query,
|
|
array(PDO::ATTR_CURSOR => PDO::CURSOR_FWDONLY));
|
|
$stmt->execute(array(':nick' => $nick)); // gibt bool zurück
|
|
$response = $stmt->fetchAll();
|
|
return $response;
|
|
}
|
|
catch (PDOException $e)
|
|
{
|
|
$errormsg = $e->getMessage();
|
|
$this->log->e("A PDO-Exception occurres");
|
|
$this->log->e("Error: {$errormsg}");
|
|
throw new PDOException($errormsg);
|
|
}
|
|
}
|
|
|
|
private function getNick(string $mid): string
|
|
{
|
|
/**
|
|
* Extrahiert aus einer Matrix-ID den localpart.
|
|
* TODO: In eine bibliothek auslagern? (/lib/common)
|
|
*/
|
|
|
|
$this->log->d("Extract nick from {$mid}");
|
|
$uid = "";
|
|
$append = false;
|
|
$strarray = str_split($mid);
|
|
foreach ($strarray as $char)
|
|
{
|
|
if ($char == '@')
|
|
{
|
|
$append = true;
|
|
}
|
|
else if ($char == ':')
|
|
{
|
|
$this->log->d("Extracted: {$uid}");
|
|
return $uid;
|
|
}
|
|
else
|
|
{
|
|
if ($append === true)
|
|
{
|
|
$uid = $uid.$char;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
public function saveRequest($token): bool
|
|
{
|
|
/**
|
|
* Speichert den gewünschten Nick, die Emailadresse, das Token und
|
|
* einen Zeitstempel in der Tabelle Requests.
|
|
* TODO: Sollten/Müssen Nick und Email noch durch htmlspecialchars()
|
|
* oder reichen die prepared Statments?
|
|
*/
|
|
|
|
$nick = $_POST['login'];
|
|
$email = $_POST['email'];
|
|
date_default_timezone_set("Europe/Berlin");
|
|
$time = time();
|
|
$this->log->d("Save request for: {$nick} with {$token} at {$time}");
|
|
try {
|
|
$stmt = $this->pdo->prepare("INSERT INTO requests
|
|
(nick, email, token, time) VALUES
|
|
(:nick, :email, :token, :time)");
|
|
$response = $stmt->execute(array(':nick' => $nick,
|
|
':email' => $email,
|
|
':token' => $token,
|
|
':time' => $time));
|
|
} catch (PDOException $e) {
|
|
$errmsg = $e->getMessage();
|
|
$this->log->e("Saving request failed");
|
|
$this->log->e("Error: {$errmsg}");
|
|
return false;
|
|
}
|
|
$this->log->i("Request saved successfull");
|
|
$this->log->d("Database returns: {$response}");
|
|
return true;
|
|
}
|
|
|
|
public function getToken(): array {
|
|
|
|
/**
|
|
* Sucht in der Tabelle requests nach dem Token. Gibt im Erfolgsfall
|
|
* ein Array mit ID, Name und Token zurück. Andernfalls ein leeres
|
|
* Array. Im Falle eines Datenbankfehlers wird eine Exception
|
|
* geworfen.
|
|
*/
|
|
|
|
$token = $_GET['token'];
|
|
$query = "SELECT id, nick, token FROM requests WHERE token = :token";
|
|
try {
|
|
$stmt = $this->pdo->prepare($query,
|
|
array(PDO::ATTR_CURSOR => PDO::CURSOR_FWDONLY));
|
|
$stmt->execute(array(':token' => $token)); // gibt bool zurück
|
|
$response = $stmt->fetchAll();
|
|
} catch (PDOException $e) {
|
|
$this->log->e("PDO Exception occures");
|
|
throw new Exception($e->getMessage());
|
|
}
|
|
$this->log->d("Database operation successfull");
|
|
return $response;
|
|
}
|
|
|
|
public function removeRequest(int $id): int {
|
|
|
|
/**
|
|
* Entfernt den Request aus der Tabelle requests. Wird aufgerufen,
|
|
* wenn die Registrierung des Nicks am Matrixserver erfolgreich war.
|
|
*/
|
|
|
|
$query = "DELETE FROM requests WHERE id = :id";
|
|
try {
|
|
$stmt = $this->pdo->prepare($query,
|
|
array(PDO::ATTR_CURSOR => PDO::CURSOR_FWDONLY));
|
|
$stmt->execute(array(':id' => $id)); // gibt bool zurück
|
|
} catch (PDOException $e) {
|
|
$this->log->e("PDO Exception occures");
|
|
throw new Exception($e->getMessage());
|
|
return false;
|
|
}
|
|
$this->log->d("Database operation successfull");
|
|
return $stmt->rowCount();;
|
|
}
|
|
|
|
}
|
|
|
|
?>
|