Compare commits
84 Commits
release/1.
...
master
Author | SHA1 | Date |
---|---|---|
Anonymous Contributor | 685853a9f9 | |
Anonymous Contributor | 36ef1c5721 | |
Anonymous Contributor | 882c5ae372 | |
Anonymous Contributor | e4e050908b | |
Anonymous Contributor | 2b5c00db1c | |
Anonymous Contributor | 2f9caf8923 | |
Anonymous Contributor | 939f600b3f | |
Anonymous Contributor | 8231fbb08c | |
Anonymous Contributor | eb5a850869 | |
Anonymous Contributor | ce41e107af | |
Anonymous Contributor | 204fcb96e1 | |
Anonymous Contributor | 891f1dff70 | |
Anonymous Contributor | 6a4c343b03 | |
Anonymous Contributor | dbcb57f71f | |
Anonymous Contributor | 1a869b62c2 | |
Anonymous Contributor | 93d8aafd6f | |
Anonymous Contributor | 2ed8285c93 | |
Anonymous Contributor | a166e65421 | |
Anonymous Contributor | e6ba73430b | |
Anonymous Contributor | 80db5f35d1 | |
Anonymous Contributor | bb40c8c9a4 | |
Anonymous Contributor | a213a38b3c | |
Anonymous Contributor | b18b960fb0 | |
Anonymous Contributor | c416ec0992 | |
Anonymous Contributor | 13495cd041 | |
Anonymous Contributor | 9e0267513b | |
Anonymous Contributor | 8e20909f23 | |
Anonymous Contributor | f87fa5d5bb | |
Anonymous Contributor | 5274f306e3 | |
Anonymous Contributor | 9483889e55 | |
Anonymous Contributor | 37ad81fb16 | |
Anonymous Contributor | f50053a745 | |
Anonymous Contributor | 07f196fc51 | |
Anonymous Contributor | fc0412d50a | |
Anonymous Contributor | f9453d5dec | |
Anonymous Contributor | 598e55dd6f | |
Anonymous Contributor | 7be78e387d | |
Anonymous Contributor | 79959cc696 | |
Anonymous Contributor | 01eb373798 | |
Anonymous Contributor | 27fe2187b4 | |
Anonymous Contributor | c7bf6f4d6e | |
Anonymous Contributor | 3bc2fee80a | |
Anonymous Contributor | 2e3124406a | |
Anonymous Contributor | ef9cb8831e | |
Anonymous Contributor | cbc065f3a4 | |
Anonymous Contributor | eca5aa0d92 | |
Anonymous Contributor | 1ac6474194 | |
Anonymous Contributor | a4b008f7ae | |
Anonymous Contributor | 6dae322a2a | |
Anonymous Contributor | ea5c1ee4d7 | |
Anonymous Contributor | 16dcd2ab46 | |
Anonymous Contributor | 94d84ab935 | |
Anonymous Contributor | d33a89b355 | |
Anonymous Contributor | 9ebb54ce64 | |
Anonymous Contributor | b68884f33c | |
Anonymous Contributor | 6b96f8281c | |
Anonymous Contributor | 1cc4746c6a | |
Anonymous Contributor | 27899ce9c1 | |
Anonymous Contributor | 686e991266 | |
Anonymous Contributor | cc240f47a2 | |
Anonymous Contributor | a80919fdce | |
Anonymous Contributor | b163f4d764 | |
Anonymous Contributor | 024a140609 | |
Anonymous Contributor | 6c22684b2f | |
Anonymous Contributor | ea2fffa872 | |
Anonymous Contributor | d6ca2e6e00 | |
Anonymous Contributor | c5871a626b | |
Anonymous Contributor | 007e0ac4fb | |
Anonymous Contributor | 48882cbb1b | |
Anonymous Contributor | 120fb3772e | |
Anonymous Contributor | 9a5182816f | |
Anonymous Contributor | bfeb4f5eef | |
Anonymous Contributor | 6f150ac55c | |
Anonymous Contributor | fb605bcf4a | |
Anonymous Contributor | 3b35e88a9f | |
Anonymous Contributor | f19e186cd3 | |
Anonymous Contributor | 0991d5a487 | |
Anonymous Contributor | eda4c5a030 | |
Anonymous Contributor | 1ee795a399 | |
Anonymous Contributor | 88e9c25bb0 | |
Anonymous Contributor | 82157cad76 | |
Anonymous Contributor | 406cdcce31 | |
Anonymous Contributor | 94e8b2e6af | |
Anonymous Contributor | b400f0c4e5 |
|
@ -1 +1,2 @@
|
|||
config.php
|
||||
config.php
|
||||
node_modules
|
41
README.md
41
README.md
|
@ -1,2 +1,41 @@
|
|||
# OpenSim-Gridverwaltung
|
||||
# MCP: OpenSim-Gridverwaltung
|
||||
|
||||
Das MCP ist ein PHP-Webinterface für Benutzer und Administratoren von OpenSimulator-Grids. Es ermöglicht Benutzern die Registrierung (auf Einladung) und Verwaltung des eigenen OpenSimulator-Accounts im Self-Service-Verfahren. Administratoren können Accounts und Regionen einfacher verwalten.
|
||||
|
||||
## Installation
|
||||
|
||||
Voraussetzung ist, dass die Datenbankstruktur eines OpenSimulator-Grids bereits existiert. Das MCP muss vor der Nutzung mit den Zugangsdaten derselben Datenbank konfiguriert werden. Eigene Tabellen des MCP besitzen zur Vermeidung von Konflikten den Präfix `mcp_`.
|
||||
|
||||
Folgende PHP-Erweiterungen werden benötigt:
|
||||
1. php-curl
|
||||
2. php-mysql (PDO)
|
||||
3. php-xml
|
||||
4. php-xmlrpc
|
||||
|
||||
Für bessere Performance kann optional `php-apcu` installiert werden.
|
||||
|
||||
Die Installation läuft folgendermaßen ab:
|
||||
1. Gewünschtes Release als ZIP/TAR-Archiv oder per `git clone` herunterladen
|
||||
2. Verzeichnisse `app`, `data`, `lib`, `public` und `templates` in das Verzeichnis des Webservers entpacken
|
||||
3. Öffentliche Stammverzeichnis des Webservers (Apache: `DocumentRoot`, nginx: `root`) auf Pfad zum Verzeichnis `public` ändern
|
||||
4. Index des Webservers auf index.php ändern, falls erforderlich
|
||||
5. Beispielkonfiguration `config.example.ini` anpassen, in `config.ini` umbenennen und in das Verzeichnis der in Schritt 2 entpackten Verzeichnisse verschieben
|
||||
|
||||
## Aktualisierung
|
||||
|
||||
Zur Aktualisierung müssen lediglich die Verzeichnisse `app`, `lib`, `public` und `templates`, sowie der Inhalt von `data` (außer `iars`) ersetzt werden.
|
||||
Die Migration der Datenbankstruktur erfolgt automatisch. Möglicherweise erforderliche Änderungen an der Konfiguration sind den Release-Informationen zu entnehmen.
|
||||
|
||||
## Entwickler
|
||||
|
||||
Die Abhängigkeiten des Frontends werden über [npm](https://www.npmjs.com/) verwaltet. Alle erforderlichen Pakete können nach dem Download des Repository über `npm install` heruntergeladen werden.
|
||||
In `package.json` ist zudem ein Buildprozess (Befehl: `npm build`) definiert, durch den die Sass-Stylesheets im Verzeichnis `scss` kompiliert und optimiert und zusammen mit Schriftarten und Skripts im öffentlichen Webverzeichnis abgelegt werden.
|
||||
|
||||
Das Backend besitzt kein Dependency Management. Die einzige Abhängigkeit, [PHPMailer](https://github.com/PHPMailer/PHPMailer), wurde manuell in das Repository eingefügt. Der Autoloader sucht im Verzeichnis `lib` nach solchen externen Klassen.
|
||||
|
||||
### Verarbeitung von Anfragen
|
||||
|
||||
Das Skript `index.php` wird bei allen Anfragen aufgerufen. Die angeforderte Route wird als GET-Parameter `<Gruppe>=<Name>` übermittelt. Gruppen (momentan `api` und `page`), zugehörige Seiten und die assoziierte `RequestHandler`-Subklasse sind in `Mcp.php` definiert.
|
||||
|
||||
Ist zu einer Anfrage eine Route definiert, wird der zugehörige `RequestHandler` erzeugt. Ist eine `Middleware`-Klasse für diesen definiert, ist die weitere Verarbeitung von dem Rückgabewert von `Middleware::canAccess()` abhängig.
|
||||
Schließlich wird je nach Methode der Anfrage `RequestHandler::get()` bzw. `RequestHandler::post()` aufgerufen.
|
|
@ -1 +0,0 @@
|
|||
Deny from all
|
110
api/economy.php
110
api/economy.php
|
@ -1,110 +0,0 @@
|
|||
<?php
|
||||
|
||||
# Copyright (c)Melanie Thielker and Teravus Ovares (http://opensimulator.org/)
|
||||
#
|
||||
# Redistribution and use in source and binary forms, with or without
|
||||
# modification, are permitted provided that the following conditions are met:
|
||||
# * Redistributions of source code must retain the above copyright
|
||||
# notice, this list of conditions and the following disclaimer.
|
||||
# * Redistributions in binary form must reproduce the above copyright
|
||||
# notice, this list of conditions and the following disclaimer in the
|
||||
# documentation and/or other materials provided with the distribution.
|
||||
# * Neither the name of the OpenSim Project nor the
|
||||
# names of its contributors may be used to endorse or promote products
|
||||
# derived from this software without specific prior written permission.
|
||||
#
|
||||
# THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
|
||||
# EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
# DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
|
||||
# DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
# ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
#
|
||||
|
||||
# updated for Robust installations: BlueWall 2011
|
||||
# further minor changes by justincc (http://justincc.org)
|
||||
|
||||
# Tables
|
||||
$presence = "Presence";
|
||||
|
||||
# XMLRPC
|
||||
$xmlrpc_server = xmlrpc_server_create();
|
||||
xmlrpc_server_register_method($xmlrpc_server, "preflightBuyLandPrep", "buy_land_prep");
|
||||
|
||||
function validate_user($agent_id, $s_session_id)
|
||||
{
|
||||
$stmt = $RUNTIME['PDO']->prepare("SELECT UserID FROM Presence WHERE UserID=? AND SecureSessionID = ?");
|
||||
$stmt->execute(array($agent_id, $s_session_id));
|
||||
|
||||
if($stmt->rowCount() == 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$res = $stmt->fetch();
|
||||
return $res['UserID'];
|
||||
}
|
||||
|
||||
function buy_land_prep($method_name, $params, $app_data)
|
||||
{
|
||||
$confirmvalue = "";
|
||||
$req = $params[0];
|
||||
$agentid = $req['agentId'];
|
||||
$sessionid = $req['secureSessionId'];
|
||||
$amount = $req['currencyBuy'];
|
||||
$billableArea = $req['billableArea'];
|
||||
|
||||
$ID = validate_user($agentid, $sessionid);
|
||||
|
||||
if($ID)
|
||||
{
|
||||
$membership_levels = array(
|
||||
'levels' => array(
|
||||
'id' => "00000000-0000-0000-0000-000000000000",
|
||||
'description' => "some level"));
|
||||
|
||||
$landUse = array(
|
||||
'upgrade' => False,
|
||||
'action' => "".SYSURL."");
|
||||
|
||||
$currency = array(
|
||||
'estimatedCost' => "200.00"); // convert_to_real($amount));
|
||||
|
||||
$membership = array(
|
||||
'upgrade' => False,
|
||||
'action' => "".SYSURL."",
|
||||
'levels' => $membership_levels);
|
||||
|
||||
$response_xml = xmlrpc_encode(array(
|
||||
'success' => True,
|
||||
'currency' => $currency,
|
||||
'membership' => $membership,
|
||||
'landUse' => $landUse,
|
||||
'currency' => $currency,
|
||||
'confirm' => $confirmvalue));
|
||||
|
||||
header("Content-type: text/xml");
|
||||
print $response_xml;
|
||||
}
|
||||
else
|
||||
{
|
||||
header("Content-type: text/xml");
|
||||
$response_xml = xmlrpc_encode(array(
|
||||
'success' => False,
|
||||
'errorMessage' => "\n\nUnable to Authenticate\n\nClick URL for more info.",
|
||||
'errorURI' => "".SYSURL.""));
|
||||
|
||||
print $response_xml;
|
||||
}
|
||||
|
||||
return "";
|
||||
}
|
||||
|
||||
$request_xml = file_get_contents('php://input');
|
||||
xmlrpc_server_call_method($xmlrpc_server, $request_xml, '');
|
||||
xmlrpc_server_destroy($xmlrpc_server);
|
||||
|
||||
?>
|
|
@ -1,29 +0,0 @@
|
|||
<?php
|
||||
$membership_levels = array(
|
||||
'levels' => array(
|
||||
'id' => "00000000-0000-0000-0000-000000000000",
|
||||
'description' => "some level"));
|
||||
|
||||
$landUse = array(
|
||||
'upgrade' => False,
|
||||
'action' => "");
|
||||
|
||||
$currency = array(
|
||||
'estimatedCost' => "200.00"); // convert_to_real($amount));
|
||||
|
||||
$membership = array(
|
||||
'upgrade' => False,
|
||||
'action' => "",
|
||||
'levels' => $membership_levels);
|
||||
|
||||
$response_xml = xmlrpc_encode(array(
|
||||
'success' => True,
|
||||
'currency' => $currency,
|
||||
'membership' => $membership,
|
||||
'landUse' => $landUse,
|
||||
'currency' => $currency,
|
||||
'confirm' => "200.00"));
|
||||
|
||||
header("Content-type: text/xml");
|
||||
print $response_xml;
|
||||
?>
|
|
@ -1,5 +0,0 @@
|
|||
1148b04d-7a93-19e9-b3c9-ea1cdeec38f7
|
||||
1148b04d-7a93-29e9-b3c9-ea1cdeec38f7
|
||||
1148b04d-7a93-39e9-b3c9-ea1cdeec38f7
|
||||
1148b04d-7a93-49e9-b3c9-ea1cdeec38f7
|
||||
1148b04d-7a93-59e9-b3c9-ea1cdeec38f7
|
|
@ -1,36 +0,0 @@
|
|||
<html>
|
||||
<head>
|
||||
<meta http-equiv="refresh" content="15">
|
||||
</head>
|
||||
<body style="background-image: url('./style/images/fabric-pattern.png')">
|
||||
<?php
|
||||
|
||||
$statement = $RUNTIME['PDO']->prepare("SELECT UserID,RegionID FROM Presence WHERE RegionID != '00000000-0000-0000-0000-000000000000' ORDER BY RegionID ASC");
|
||||
$statement->execute();
|
||||
|
||||
if($statement->rowCount() == 0)
|
||||
{
|
||||
echo "<h1>Es ist niemand online!</h1>";
|
||||
}else{
|
||||
|
||||
echo '<table style="width:350px;margin-left:auto;margin-right:auto;margin-top:25px"><tr><th align="left" style="background-color: #FF8000;">Name</th><th align="left" style="background-color: #FF8000;">Region</th></tr>';
|
||||
$entryColor = TRUE;
|
||||
include 'app/OpenSim.php';
|
||||
$opensim = new OpenSim();
|
||||
while($row = $statement->fetch())
|
||||
{
|
||||
if($entryColor == TRUE)
|
||||
$entry = '<tr style="background-color: #F2F2F2;"><td>'.trim($opensim->getUserName($row['UserID'])).'</td><td>'.$opensim->getRegionName($row['RegionID']).'</td></tr>';
|
||||
|
||||
if($entryColor == FALSE)
|
||||
$entry = '<tr style="background-color: #E6E6E6;"><td>'.trim($opensim->getUserName($row['UserID'])).'</td><td>'.$opensim->getRegionName($row['RegionID']).'</td></tr>';
|
||||
|
||||
echo $entry;
|
||||
$entryColor = !$entryColor;
|
||||
}
|
||||
|
||||
echo '</table>';
|
||||
}
|
||||
?>
|
||||
</body>
|
||||
</html>
|
|
@ -1,35 +0,0 @@
|
|||
<?php
|
||||
include 'app/OpenSim.php';
|
||||
$opensim = new OpenSim();
|
||||
|
||||
$HTML = new HTML();
|
||||
$HTML->setHTMLTitle("Spalsh");
|
||||
$HTML->importHTML("viewerWelcomeImages.html");
|
||||
|
||||
$IMAGES = array();
|
||||
if ($handle = opendir('./data/viewerWelcomeImages'))
|
||||
{
|
||||
while (false !== ($entry = readdir($handle)))
|
||||
{
|
||||
if ($entry != "." && $entry != "..")
|
||||
{
|
||||
$IMAGES = array_merge($IMAGES, array("./data/viewerWelcomeImages/".$entry));
|
||||
}
|
||||
}
|
||||
|
||||
closedir($handle);
|
||||
}
|
||||
|
||||
shuffle($IMAGES);
|
||||
|
||||
$HTML->ReplaceLayoutInhalt("%%JSONIMAGEARRAY%%", json_encode($IMAGES));
|
||||
$HTML->ReplaceLayoutInhalt("%%GRIDNAME%%", $RUNTIME['GRID']['NAME']);
|
||||
$HTML->ReplaceLayoutInhalt("%%SHOWNEWS%%", $RUNTIME['GRID']['MAIN_NEWS']);
|
||||
|
||||
|
||||
$HTML->ReplaceLayoutInhalt("%%SHOWSTATS%%", "Registrierte User: ".$opensim->getUserCount()."<br>Regionen: ".$opensim->getRegionCount()."<br>Aktuell Online: ".($opensim->getOnlineCount()-1));
|
||||
|
||||
|
||||
$HTML->build();
|
||||
echo $HTML->ausgabe();
|
||||
?>
|
|
@ -0,0 +1,11 @@
|
|||
<?php
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Mcp;
|
||||
|
||||
use PDO;
|
||||
|
||||
interface ConnectionProvider
|
||||
{
|
||||
public function db(): PDO;
|
||||
}
|
|
@ -1,29 +1,35 @@
|
|||
<?php
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Mcp;
|
||||
|
||||
class FormValidator {
|
||||
|
||||
private array $fieldValidation;
|
||||
|
||||
public function __construct(array $fieldValidation) {
|
||||
public function __construct(array $fieldValidation)
|
||||
{
|
||||
$this->fieldValidation = $fieldValidation;
|
||||
}
|
||||
|
||||
public function isValid(array $req) {
|
||||
if(!isset($req['csrf']) || $req['csrf'] !== $_SESSION['csrf']) {
|
||||
public function isValid(array $req): bool
|
||||
{
|
||||
if (!isset($req['csrf']) || $req['csrf'] !== $_SESSION['csrf']) {
|
||||
return false;
|
||||
}
|
||||
|
||||
foreach($this->fieldValidation as $field => $params) {
|
||||
if(isset($req[$field]) && strlen(trim($req[$field])) > 0) {
|
||||
if(isset($params['regex'])) {
|
||||
if(!preg_match($params['regex'], $req[$field])) {
|
||||
foreach ($this->fieldValidation as $field => $params) {
|
||||
if (isset($req[$field]) && strlen(trim($req[$field])) > 0) {
|
||||
if (isset($params['regex'])) {
|
||||
if (!preg_match($params['regex'], $req[$field])) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else if(isset($params['equals']) && $params['equals'] !== $req[$field]) {
|
||||
elseif (isset($params['equals']) && $params['equals'] !== $req[$field]) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else if(isset($params['required']) && $params['required']) {
|
||||
elseif (isset($params['required']) && $params['required']) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
@ -32,4 +38,3 @@ class FormValidator {
|
|||
}
|
||||
|
||||
}
|
||||
?>
|
249
app/HTML.php
249
app/HTML.php
|
@ -1,249 +0,0 @@
|
|||
<?php
|
||||
class HTML
|
||||
{
|
||||
//Hier wird der HTML Code zum Ausgeben vorbereitet.
|
||||
//Dieser kann aus einer fertigen HTML Seite ausgelesen werden, oder aber auch st<73>ck f<>r St<53>ck
|
||||
//Zusammen gebaut werden.
|
||||
|
||||
//Die Einzelnen Daten k<>nnen nicht direkt von Au<41>en ver<65>ndert werden, sondern m<>ssen durch die Bereitgestellten Optionen gesetzt werden.
|
||||
|
||||
private $HTMLTitle = " "; //Wird in den <header> als <title> Geschrieben.
|
||||
private $StatusMeldung = " "; //Falls Vorhenden eine Statusmeldung vom Script im HTML Text.
|
||||
private $DasMenu = " "; //Beinhaltet das Fertige Men<65>
|
||||
private $DerInhalt = " "; //Beinhaltet den Fertigen Inhalt
|
||||
private $HTMLDatei = " "; //Der inhalt der eingelesen wurde.
|
||||
private $HTMLHeader = " "; //Der HTML HEADER der eingelesen wurde.
|
||||
private $FertigesHTML = " "; //Das Fertige HTML bereit zum Ausgeben.
|
||||
private $isBuild = false; //Hier wird festgehalten ob $FertigesHTML aktuell ist oder nicht.
|
||||
|
||||
//Der <title> wird Generiert.(%%EchoTitle%%)
|
||||
//Dieser wird im HTML Code sp<73>ter als %%HTMLTitle%% aufgerufen.
|
||||
|
||||
public function setHTMLTitle($neuerTitle){
|
||||
//Der Bisherige Title wird komplett <20>berschrieben und gleichzeitig ein neuer Gesetzt.
|
||||
$this->HTMLTitle = $neuerTitle;
|
||||
$this->isBuild = false;
|
||||
}
|
||||
|
||||
public function addHTMLTitle($Hinzufugen){
|
||||
//Zu dem Bisherigen Titel wird noch etwas am ende hinzugef<65>gt.
|
||||
$this->HTMLTitle = $this->HTMLTitle.$Hinzufugen;
|
||||
$this->isBuild = false;
|
||||
}
|
||||
|
||||
public function RemoveHTMLTitle(){
|
||||
//Der Titel wird Komplett gel<65>scht.
|
||||
$this->HTMLTitle = " ";
|
||||
$this->isBuild = false;
|
||||
}
|
||||
|
||||
|
||||
//Der HTML HEADER wird Generiert.(%%echoHeader%%)
|
||||
//Dieser wird im HTML Code sp<73>ter als %%echoHeader%% aufgerufen.
|
||||
|
||||
public function setHTMLHeader($neuerHeader){
|
||||
//Der Bisherige Header wird komplett <20>berschrieben und gleichzeitig ein neuer Gesetzt.
|
||||
$this->HTMLHeader = $neuerHeader;
|
||||
$this->isBuild = false;
|
||||
}
|
||||
|
||||
public function addHTMLHeader($Hinzufugen){
|
||||
//Zu dem Bisherigen Header wird noch etwas am ende hinzugef<65>gt.
|
||||
$this->HTMLHeader = $this->HTMLHeader.$Hinzufugen;
|
||||
$this->isBuild = false;
|
||||
}
|
||||
|
||||
public function RemoveHTMLHeader(){
|
||||
//Der Header wird Komplett gel<65>scht.
|
||||
$this->HTMLHeader = " ";
|
||||
$this->isBuild = false;
|
||||
}
|
||||
|
||||
public function importHTMLHeader($file){
|
||||
global $RUNTIME;
|
||||
//Der HTML Header wird aus einer Datei eingelesen und der bisherige gel<65>scht.
|
||||
$this->HTMLHeader = file_get_contents($RUNTIME['BASEDIR'].'/templates/'.$file);
|
||||
$this->isBuild = false;
|
||||
}
|
||||
|
||||
//Der StatusText wird ge<67>ndert.(%%StatusMeldung%%)
|
||||
//Dieser wird im HTML Code sp<73>ter als %%StatusMeldung%% aufgerufen.
|
||||
|
||||
public function setStatusMeldung($neueMeldung){
|
||||
//Die bisherige Status meldung wird komplett <20>berschrieben und gleichzeitig ein neuer Gesetzt.
|
||||
$this->StatusMeldung = $neueMeldung;
|
||||
$this->isBuild = false;
|
||||
}
|
||||
|
||||
public function RemoveStatusMeldung(){
|
||||
//Die Meldung wird Komplett gel<65>scht.
|
||||
$this->StatusMeldung = " ";
|
||||
$this->isBuild = false;
|
||||
}
|
||||
|
||||
//Ab hier wird das Men<65> Zusammengebaut. (%%EchoMenu%%)
|
||||
|
||||
public function importTextMenu($neuesMenu){
|
||||
//Das Komplette Men<65> wird direkt importiert und das alte <20>berschreiben.
|
||||
$this->DasMenu = $neuesMenu;
|
||||
$this->isBuild = false;
|
||||
}
|
||||
|
||||
public function importHTMLMenu($file){
|
||||
global $RUNTIME;
|
||||
//Das Komplette Men<65> wird aus einer Datei ausgelesen und das alte <20>berschrieben.
|
||||
$this->DasMenu = file_get_contents($RUNTIME['BASEDIR'].'/templates/'.$file);
|
||||
$this->isBuild = false;
|
||||
}
|
||||
|
||||
public function addToMenu($html){
|
||||
//Es wird noch etwas ans Men<65> angehengt.
|
||||
$this->DasMenu = $this->DasMenu.$html;
|
||||
$this->isBuild = false;
|
||||
}
|
||||
|
||||
|
||||
|
||||
//Der Seiten HTML Quelcode wird eingelesen.
|
||||
|
||||
public function importHTML($file){
|
||||
global $RUNTIME;
|
||||
//Der HTML Quelltext wird aus einer Datei eingelesen.
|
||||
$this->HTMLDatei = file_get_contents($RUNTIME['BASEDIR'].'/templates/'.$file);
|
||||
$this->isBuild = false;
|
||||
}
|
||||
|
||||
public function setHTML($htmlCode){
|
||||
//Der HTML Quelltext wird direkt gesetzt.
|
||||
$this->HTMLDatei = $htmlCode;
|
||||
$this->isBuild = false;
|
||||
}
|
||||
|
||||
public function addNachHTML($htmlCode){
|
||||
//Der HTML Quelltext wird direkt gesetzt.
|
||||
$this->HTMLDatei = $this->HTMLDatei.$htmlCode;
|
||||
$this->isBuild = false;
|
||||
}
|
||||
|
||||
public function addVorHTML($htmlCode){
|
||||
//Der HTML Quelltext wird direkt gesetzt.
|
||||
$this->HTMLDatei = $htmlCode.$this->HTMLDatei;
|
||||
$this->isBuild = false;
|
||||
}
|
||||
|
||||
public function DeleteHTML(){
|
||||
//Der HTML Quelltext wird gel<65>scht.
|
||||
$this->HTMLDatei = " ";
|
||||
$this->isBuild = false;
|
||||
}
|
||||
|
||||
//Der inhalt der Seite wird zusammen gesetzt (nicht der quelltext) (%%EchoInhalt%%)
|
||||
|
||||
public function importSeitenInhalt($file){
|
||||
global $RUNTIME;
|
||||
//L<>d einen fertigen Text aus einer datei.
|
||||
$this->DerInhalt = file_get_contents($RUNTIME['BASEDIR'].'/templates/'.$file);
|
||||
$this->isBuild = false;
|
||||
}
|
||||
|
||||
public function setSeitenInhalt($html){
|
||||
//Setz den Seiteninhalt und L<>scht den alten Komplett.
|
||||
$this->DerInhalt = $html;
|
||||
$this->isBuild = false;
|
||||
}
|
||||
|
||||
public function importAndAddSeitenInhalt($file){
|
||||
global $RUNTIME;
|
||||
//L<>d einen fertigen Text aus einer datei.
|
||||
$this->DerInhalt = $this->DerInhalt.file_get_contents($RUNTIME['BASEDIR'].'/templates/'.$file);
|
||||
$this->isBuild = false;
|
||||
}
|
||||
|
||||
public function addToSeitenInhalt($html){
|
||||
//Es wird noch weitere Text an den Seiteninhalt angeh<65>ngt.
|
||||
$this->DerInhalt = $this->DerInhalt.$html;
|
||||
$this->isBuild = false;
|
||||
}
|
||||
|
||||
public function GetSeitenInhalt(){
|
||||
//Der Seiteninhalt wird zur<75>ckgegeben.
|
||||
return $this->DerInhalt;
|
||||
}
|
||||
|
||||
public function DeleteSeitenInhalt(){
|
||||
//L<>scht den Seiten inhalt.
|
||||
$this->DerInhalt = " ";
|
||||
$this->isBuild = false;
|
||||
}
|
||||
|
||||
public function ReplaceSeitenInhalt($tag, $text){
|
||||
//Ersezt Seiten Inhalt
|
||||
$this->DerInhalt = str_replace($tag, $text, $this->DerInhalt);
|
||||
}
|
||||
|
||||
public function ReplaceLayoutInhalt($tag, $text){
|
||||
//Ersezt Layout Inhalt
|
||||
$this->HTMLDatei = str_replace($tag, $text, $this->HTMLDatei);
|
||||
}
|
||||
|
||||
public function CompressHTML(){
|
||||
if($this->isBuild){
|
||||
$this->FertigesHTML = str_replace(" ", "", $this->FertigesHTML);
|
||||
|
||||
$this->FertigesHTML = str_replace(" ", "", $this->FertigesHTML);
|
||||
}else{
|
||||
die("Es kann nur Fertiger HTML Code kompremiert werden.");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
//Hier wird der Fertige HTML Code generiert.
|
||||
//Und alle 3 Teile, Men<65> Titel und inhalt zusammengef<65>gt.
|
||||
public function build(){
|
||||
//Der HTML Code wird zusammen gesetzt.
|
||||
|
||||
$this->FertigesHTML = null; //Der Speicher wird gellert, falls schon einmal Quelltext generiert wurde.
|
||||
$this->FertigesHTML = $this->HTMLDatei; //Und der Unverarbeitete HTML Quelltext eingelesen.
|
||||
|
||||
//Das Men<65> wird in den HTML Quellcode eingef<65>gt.
|
||||
$this->FertigesHTML = str_replace("%%EchoMenu%%", $this->DasMenu, $this->FertigesHTML);
|
||||
|
||||
//Der inhalt wird in den HTML Quellcode eingef<65>gt.
|
||||
$this->FertigesHTML = str_replace("%%EchoInhalt%%", $this->DerInhalt, $this->FertigesHTML);
|
||||
|
||||
//Die Status Meldung wird in den HTML Quellcode eingef<65>gt.
|
||||
$this->FertigesHTML = str_replace("%%StatusMeldung%%", $this->StatusMeldung, $this->FertigesHTML);
|
||||
|
||||
//Der Titel wird in den HTML Quellcode eingef<65>gt.
|
||||
$this->FertigesHTML = str_replace("%%EchoTitle%%", $this->HTMLTitle, $this->FertigesHTML);
|
||||
|
||||
//Der HTML Header wird in den HTML Quellcode eingef<65>gt.
|
||||
$this->FertigesHTML = str_replace("%%echoHeader%%", $this->HTMLHeader, $this->FertigesHTML);
|
||||
|
||||
//Der Titel wird in den HTML Quellcode eingef<65>gt.
|
||||
$this->FertigesHTML = str_replace("%%datum%%", date("Y-m-dTH:i+2"), $this->FertigesHTML);
|
||||
|
||||
//Der Counter wird in den HTML Quellcode eingef<65>gt.
|
||||
$this->FertigesHTML = str_replace("%%GET_SITE%%", isset($_GET['seite']) ? $_GET['seite'] : ' ', $this->FertigesHTML);
|
||||
|
||||
//Die IP Adresse wird in den HTML Quellcode eingef<65>gt.
|
||||
$this->FertigesHTML = str_replace("%%GET_IP%%", isset($_SERVER["REMOTE_ADDR"]) ? $_SERVER['REMOTE_ADDR'] : ' ', $this->FertigesHTML);
|
||||
|
||||
// Add CSRF token
|
||||
$this->FertigesHTML = str_replace("%%CSRF%%", '<input type="hidden" name="csrf" value="'.(isset($_SESSION['csrf']) ? $_SESSION['csrf'] : '').'">', $this->FertigesHTML);
|
||||
|
||||
$this->isBuild = true;
|
||||
}
|
||||
|
||||
//Hier wird der Fertige HTML ausgegeben
|
||||
public function ausgabe(){
|
||||
if($this->isBuild){
|
||||
return $this->FertigesHTML;
|
||||
}else{
|
||||
die("Bitte erst den HTML Code zusammensetzen.");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
?>
|
|
@ -0,0 +1,149 @@
|
|||
<?php
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Mcp;
|
||||
|
||||
use Exception;
|
||||
use PDO;
|
||||
|
||||
class Mcp implements ConnectionProvider
|
||||
{
|
||||
|
||||
private ?PDO $db = null;
|
||||
private array $config;
|
||||
private string $dataDir;
|
||||
private string $templateDir;
|
||||
|
||||
const ROUTES = [
|
||||
'api' => [
|
||||
'economy' => 'Api\\Economy',
|
||||
'economylandtool' => 'Api\\EconomyLandTool',
|
||||
'economylandtool.php' => 'Api\\EconomyLandTool',
|
||||
'getAccessList' => 'Api\\GetAccessList',
|
||||
'onlineDisplay' => 'Api\\OnlineDisplay',
|
||||
'viewerWelcomeSite' => 'Api\\ViewerWelcomePage',
|
||||
'runCron' => 'Api\\CronStarter',
|
||||
'downloadIar' => 'Api\\DownloadIar'
|
||||
],
|
||||
'page' => [
|
||||
'dashboard' => 'Page\\Dashboard',
|
||||
'forgot' => 'Page\\ForgotPassword',
|
||||
'friends' => 'Page\\Friends',
|
||||
'groups' => 'Page\\Groups',
|
||||
'identities' => 'Page\\Identities',
|
||||
'login' => 'Page\\Login',
|
||||
'profile' => 'Page\\Profile',
|
||||
'regions' => 'Page\\Regions',
|
||||
'register' => 'Page\\Register',
|
||||
'reset-password' => 'Page\\ResetPassword',
|
||||
'user-online-state' => 'Page\\OnlineUsers',
|
||||
'users' => 'Page\\ManageUsers'
|
||||
]
|
||||
];
|
||||
|
||||
public function __construct($basedir)
|
||||
{
|
||||
$this->templateDir = $basedir.DIRECTORY_SEPARATOR.'templates';
|
||||
$this->dataDir = $basedir.DIRECTORY_SEPARATOR.'data';
|
||||
$this->config = array();
|
||||
try {
|
||||
$config = parse_ini_file($basedir.DIRECTORY_SEPARATOR.'config.ini', true);
|
||||
foreach ($config['general'] as $key => $val) {
|
||||
$this->config[$key] = $val;
|
||||
}
|
||||
unset($config['general']);
|
||||
$this->config = array_merge($config, $this->config);
|
||||
} catch (Exception $e) {
|
||||
error_log('Could not load config, aborting. Error: '.$e->getMessage());
|
||||
http_response_code(503);
|
||||
exit();
|
||||
}
|
||||
|
||||
$migrate = new MigrationManager($basedir.DIRECTORY_SEPARATOR.'data'.DIRECTORY_SEPARATOR.'migrate_ver');
|
||||
if (!$migrate->isMigrated() && !$migrate->migrate($this->db())) {
|
||||
error_log('Migration to latest DB structure version failed, aborting.');
|
||||
http_response_code(503);
|
||||
exit();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Connects to the MySQL database (if not done already) and returns the connection.
|
||||
*/
|
||||
public function db(): PDO
|
||||
{
|
||||
if ($this->db == null) {
|
||||
$this->db = new PDO('mysql:host='.$this->config['mysql']['host'].';dbname='.$this->config['mysql']['db'],
|
||||
$this->config['mysql']['user'],
|
||||
$this->config['mysql']['password']);
|
||||
}
|
||||
|
||||
return $this->db;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the value associated with the specified key in this config, as either a string, an integer or an array.
|
||||
* Keys are lower-cased for compatibility reasons.
|
||||
*
|
||||
* If there is no entry with this key, an empty array is returned.
|
||||
*/
|
||||
public function config($key): string|array|int
|
||||
{
|
||||
$realKey = strtolower($key);
|
||||
return isset($this->config[$realKey]) ? $this->config[$realKey] : array();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a hidden form field with the current CSRF token set.
|
||||
*/
|
||||
public function csrfField(): string
|
||||
{
|
||||
return '<input type="hidden" name="csrf" value="'.(isset($_SESSION['csrf']) ? $_SESSION['csrf'] : '').'">';
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a TemplateBuilder instance for the specified template file, setting some basic variables.
|
||||
*/
|
||||
public function template($name): TemplateBuilder
|
||||
{
|
||||
return (new TemplateBuilder($this->templateDir, $name))->vars([
|
||||
'domain' => $this->config['domain'],
|
||||
'title' => 'MCP',
|
||||
'admin' => isset($_SESSION['LEVEL']) && $_SESSION['LEVEL'] > 100
|
||||
])->unsafeVar('csrf', $this->csrfField());
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the path of the data/ directory, mostly used for dynamically created assets.
|
||||
*/
|
||||
public function getDataDir(): string
|
||||
{
|
||||
return $this->dataDir;
|
||||
}
|
||||
|
||||
public function handleRequest()
|
||||
{
|
||||
$reqClass = 'Mcp\\Page\\Error';
|
||||
if (empty($_GET)) {
|
||||
$reqClass = 'Mcp\\'.$this::ROUTES['page'][array_key_first($this::ROUTES['page'])];
|
||||
} else {
|
||||
if (isset($_GET['logout'])) {
|
||||
session_start();
|
||||
session_destroy();
|
||||
header('Location: /');
|
||||
return;
|
||||
}
|
||||
|
||||
foreach ($this::ROUTES as $type => $routes) {
|
||||
if (isset($_GET[$type])) {
|
||||
if (strlen($_GET[$type]) <= 100 && preg_match('/^[0-9a-zA-Z-_.]+$/', $_GET[$type]) && isset($routes[$_GET[$type]])) {
|
||||
$reqClass = 'Mcp\\'.$routes[$_GET[$type]];
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
(new $reqClass($this))->handleRequest();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,126 @@
|
|||
<?php
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Mcp;
|
||||
|
||||
use Exception;
|
||||
use PDO;
|
||||
|
||||
class MigrationManager
|
||||
{
|
||||
private const INIT = [
|
||||
'CREATE TABLE IF NOT EXISTS `mcp_user_identities` (`PrincipalID` CHAR(36) NOT NULL, `IdentityID` CHAR(36) NOT NULL, PRIMARY KEY (`PrincipalID`, `IdentityID`)) ENGINE=MyISAM CHARSET=utf8mb3 COLLATE=utf8mb3_general_ci',
|
||||
'CREATE TABLE IF NOT EXISTS `mcp_password_reset` (`PrincipalID` CHAR(36) NOT NULL, `Token` CHAR(32) NOT NULL, `RequestTime` BIGINT NOT NULL, PRIMARY KEY(`PrincipalID`), UNIQUE(`Token`)) ENGINE MyISAM DEFAULT CHARSET=utf8mb3 COLLATE=utf8mb3_general_ci',
|
||||
'CREATE TABLE IF NOT EXISTS `mcp_invites` (`InviteCode` CHAR(64) NOT NULL, PRIMARY KEY (`InviteCode`)) ENGINE InnoDB',
|
||||
'CREATE TABLE IF NOT EXISTS `mcp_offlineim_send` (`id` int(6) NOT NULL DEFAULT 0) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci',
|
||||
'CREATE TABLE IF NOT EXISTS `mcp_regions_info` (`regionID` CHAR(36) NOT NULL COLLATE utf8_unicode_ci, `RegionVersion` VARCHAR(128) NOT NULL DEFAULT "" COLLATE utf8_unicode_ci, `ProcMem` INT(11) NOT NULL, `Prims` INT(11) NOT NULL, `SimFPS` INT(11) NOT NULL, `PhyFPS` INT(11) NOT NULL, `OfflineTimer` INT(11) NOT NULL DEFAULT 0, PRIMARY KEY (`regionID`) USING BTREE) COLLATE=utf8_unicode_ci ENGINE=InnoDB',
|
||||
'CREATE TABLE IF NOT EXISTS `mcp_cron_runs` (`Name` VARCHAR(50) NOT NULL, `LastRun` INT(11) UNSIGNED NOT NULL, PRIMARY KEY(`Name`)) ENGINE InnoDB',
|
||||
'CREATE TABLE IF NOT EXISTS `mcp_iar_state` (`userID` CHAR(36) NOT NULL COLLATE utf8_unicode_ci, `filesize` BIGINT(20) NOT NULL DEFAULT 0, `iarfilename` VARCHAR(64) NOT NULL COLLATE utf8_unicode_ci, `state` TINYINT(1) UNSIGNED NOT NULL DEFAULT 0, `created` INT(11) UNSIGNED NOT NULL DEFAULT 0, PRIMARY KEY (`userID`) USING BTREE) COLLATE=utf8_unicode_ci ENGINE=InnoDB',
|
||||
'CREATE TRIGGER IF NOT EXISTS del_id_trig AFTER DELETE ON UserAccounts FOR EACH ROW DELETE FROM mcp_user_identities WHERE mcp_user_identities.PrincipalID = OLD.PrincipalID OR mcp_user_identities.IdentityID = OLD.PrincipalID',
|
||||
'CREATE TRIGGER IF NOT EXISTS del_pwres_trig AFTER DELETE ON UserAccounts FOR EACH ROW DELETE FROM mcp_password_reset WHERE mcp_password_reset.PrincipalID = OLD.PrincipalID'
|
||||
];
|
||||
|
||||
private const MIGRATIONS = [
|
||||
1 => [
|
||||
'RENAME TABLE IF EXISTS UserIdentitys TO mcp_user_identities, PasswordResetTokens TO mcp_password_reset, InviteCodes TO mcp_invites, im_offline_send TO mcp_offlineim_send, regions_info TO mcp_regions_info',
|
||||
'ALTER TABLE mcp_invites MODIFY COLUMN InviteCode CHAR(64) NOT NULL',
|
||||
'ALTER TABLE mcp_regions_info MODIFY COLUMN regionID CHAR(36), MODIFY COLUMN ProcMem INT(11) UNSIGNED NOT NULL, MODIFY COLUMN Prims INT(11) UNSIGNED NOT NULL, MODIFY COLUMN SimFPS FLOAT NOT NULL, MODIFY COLUMN PhyFPS FLOAT NOT NULL, MODIFY COLUMN OfflineTimer BIGINT UNSIGNED NOT NULL DEFAULT 0',
|
||||
'ALTER TABLE mcp_user_identities MODIFY COLUMN PrincipalID CHAR(36) COLLATE utf8mb3_general_ci, MODIFY COLUMN IdentityID CHAR(36) COLLATE utf8mb3_general_ci',
|
||||
'CREATE TRIGGER IF NOT EXISTS del_id_trig AFTER DELETE ON UserAccounts FOR EACH ROW DELETE FROM mcp_user_identities WHERE mcp_user_identities.PrincipalID = OLD.PrincipalID OR mcp_user_identities.IdentityID = OLD.PrincipalID',
|
||||
'CREATE TRIGGER IF NOT EXISTS del_pwres_trig AFTER DELETE ON UserAccounts FOR EACH ROW DELETE FROM mcp_password_reset WHERE mcp_password_reset.PrincipalID = OLD.PrincipalID'
|
||||
],
|
||||
2 => [
|
||||
'CREATE TABLE IF NOT EXISTS `mcp_cron_runs` (`Name` VARCHAR(50) NOT NULL, `LastRun` INT(11) UNSIGNED NOT NULL, PRIMARY KEY(`Name`)) ENGINE InnoDB'
|
||||
],
|
||||
3 => [
|
||||
'RENAME TABLE IF EXISTS iarstates TO mcp_iar_state',
|
||||
'ALTER TABLE mcp_iar_state MODIFY COLUMN userID CHAR(36) NOT NULL COLLATE utf8_unicode_ci, DROP COLUMN running, ADD COLUMN `state` TINYINT(1) UNSIGNED NOT NULL DEFAULT 0 AFTER iarfilename, ADD COLUMN created INT(11) UNSIGNED NOT NULL DEFAULT 0 AFTER `state`'
|
||||
]
|
||||
];
|
||||
|
||||
private const MIGRATE_VERSION_CURRENT = 4;
|
||||
|
||||
private int $migrateVersion;
|
||||
private string $migrateVersionFile;
|
||||
|
||||
public function __construct(string $migrateVersionFile)
|
||||
{
|
||||
$this->migrateVersionFile = $migrateVersionFile;
|
||||
$this->migrateVersion = 0;
|
||||
$apcu = false;
|
||||
if ($this->apcuAvailable()) {
|
||||
$this->migrateVersion = apcu_exists('mcp_migrate_version') ? apcu_fetch('mcp_migrate_version') : 0;
|
||||
$apcu = true;
|
||||
}
|
||||
|
||||
if ($this->migrateVersion == 0 && file_exists($migrateVersionFile)) {
|
||||
$migrateVer = file_get_contents($migrateVersionFile);
|
||||
if (preg_match('/^\d+$/', $migrateVer)) {
|
||||
$this->migrateVersion = intval($migrateVer);
|
||||
if ($apcu) {
|
||||
apcu_store('mcp_migrate_version', $this->migrateVersion);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public function isMigrated(): bool
|
||||
{
|
||||
return $this->migrateVersion == $this::MIGRATE_VERSION_CURRENT;
|
||||
}
|
||||
|
||||
public function migrate(PDO $db): bool
|
||||
{
|
||||
if ($this->migrateVersion == 0) {
|
||||
// MCP < v2.x.x might be initialized without migration data
|
||||
$checkLegacy = $db->prepare('SHOW TABLES LIKE ?');
|
||||
$checkLegacy->execute(['UserIdentitys']);
|
||||
if ($checkLegacy->rowCount() > 0) {
|
||||
$this->migrateVersion = 1;
|
||||
}
|
||||
else {
|
||||
return $this->runStatements($db, $this::INIT) && $this->updateVersion();
|
||||
}
|
||||
}
|
||||
|
||||
for ($ver = $this->migrateVersion; $ver <= count($this::MIGRATIONS); $ver++) {
|
||||
if (!isset($this::MIGRATIONS[$ver])) {
|
||||
break;
|
||||
}
|
||||
|
||||
if (!$this->runStatements($db, $this::MIGRATIONS[$ver])) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
$this->updateVersion();
|
||||
return true;
|
||||
}
|
||||
|
||||
private function updateVersion(): bool
|
||||
{
|
||||
file_put_contents($this->migrateVersionFile, $this::MIGRATE_VERSION_CURRENT);
|
||||
if ($this->apcuAvailable()) {
|
||||
apcu_store('mcp_migrate_version', $this::MIGRATE_VERSION_CURRENT);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
private function runStatements(PDO $db, array $stmts): bool
|
||||
{
|
||||
try {
|
||||
foreach ($stmts as $stmt) {
|
||||
$db->exec($stmt);
|
||||
}
|
||||
return true;
|
||||
} catch (Exception $e) {
|
||||
error_log('Could not execute statements: '.$e->getMessage()."\n".$e->getTraceAsString());
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
private function apcuAvailable(): bool
|
||||
{
|
||||
return function_exists('apcu_fetch') && apcu_enabled();
|
||||
}
|
||||
}
|
482
app/OpenSim.php
482
app/OpenSim.php
|
@ -1,216 +1,280 @@
|
|||
<?php
|
||||
class OpenSim
|
||||
{
|
||||
public function isLoginValid($name, $password)
|
||||
{
|
||||
global $RUNTIME;
|
||||
declare(strict_types=1);
|
||||
|
||||
$statementUser = $RUNTIME['PDO']->prepare("SELECT PrincipalID FROM UserAccounts WHERE FirstName = ? AND LastName = ? LIMIT 1");
|
||||
$statementUser->execute(explode(" ", trim($name)));
|
||||
namespace Mcp;
|
||||
|
||||
while($rowUser = $statementUser->fetch())
|
||||
{
|
||||
$statementAuth = $RUNTIME['PDO']->prepare("SELECT passwordHash,passwordSalt FROM auth WHERE UUID = ? LIMIT 1");
|
||||
$statementAuth->execute(array($rowUser['PrincipalID']));
|
||||
use Exception;
|
||||
use PDO;
|
||||
|
||||
while($rowAuth = $statementAuth->fetch())
|
||||
{
|
||||
return md5(md5($_POST['password']).":".$rowAuth['passwordSalt']) == $rowAuth['passwordHash'];
|
||||
}
|
||||
}
|
||||
class OpenSim
|
||||
{
|
||||
|
||||
return false;
|
||||
}
|
||||
private PDO $pdo;
|
||||
private bool $apcu;
|
||||
|
||||
public function getUserName($userID)
|
||||
{
|
||||
global $RUNTIME;
|
||||
|
||||
if($userID == "00000000-0000-0000-0000-000000000000")
|
||||
return "Unknown User";
|
||||
|
||||
if(isset($RUNTIME['CACHE']['USERNAME'][$userID]))
|
||||
return $RUNTIME['CACHE']['USERNAME'][$userID];
|
||||
|
||||
$statementUser = $RUNTIME['PDO']->prepare("SELECT FirstName,LastName FROM UserAccounts WHERE PrincipalID = ?");
|
||||
$statementUser->execute(array($userID));
|
||||
|
||||
while($rowUser = $statementUser->fetch())
|
||||
{
|
||||
$RUNTIME['CACHE']['USERNAME'][$userID] = $rowUser['FirstName']." ".$rowUser['LastName'];
|
||||
return $rowUser['FirstName']." ".$rowUser['LastName'];
|
||||
}
|
||||
|
||||
$statementGridUser = $RUNTIME['PDO']->prepare("SELECT UserID FROM GridUser");
|
||||
$statementGridUser->execute(array($userID));
|
||||
|
||||
while($rowGridUser = $statementGridUser->fetch())
|
||||
{
|
||||
$UserData = explode(";", $rowGridUser['UserID']);
|
||||
|
||||
if(count($UserData) >= 3)
|
||||
{
|
||||
$DBUserID = $UserData[0];
|
||||
$DBUserName = $UserData[2];
|
||||
|
||||
$RUNTIME['CACHE']['USERNAME'][$userID] = $DBUserName;
|
||||
|
||||
if($DBUserID == $userID)
|
||||
return $DBUserName;
|
||||
}
|
||||
}
|
||||
|
||||
$statementFriends = $RUNTIME['PDO']->prepare("SELECT PrincipalID FROM Friends");
|
||||
$statementFriends->execute(array($userID));
|
||||
|
||||
while($rowFriends = $statementFriends->fetch())
|
||||
{
|
||||
$UserData = explode(";", $rowFriends['PrincipalID']);
|
||||
|
||||
if(count($UserData) == 4)
|
||||
{
|
||||
$DBUserID = $UserData[0];
|
||||
$DBUserName = $UserData[2];
|
||||
|
||||
$RUNTIME['CACHE']['USERNAME'][$userID] = $DBUserName;
|
||||
|
||||
if($DBUserID == $userID)
|
||||
return $DBUserName;
|
||||
}
|
||||
}
|
||||
|
||||
return "Unknown User";
|
||||
}
|
||||
|
||||
public function getUserUUID($UserName)
|
||||
{
|
||||
global $RUNTIME;
|
||||
|
||||
$statementUser = $RUNTIME['PDO']->prepare("SELECT PrincipalID,FirstName,LastName FROM UserAccounts");
|
||||
$statementUser->execute();
|
||||
|
||||
while($rowUser = $statementUser->fetch())
|
||||
{
|
||||
$SQLUserName = $rowUser['FirstName']." ".$rowUser['LastName'];
|
||||
|
||||
if($SQLUserName == $UserName)
|
||||
{
|
||||
return $rowUser['PrincipalID'];
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public function getRegionName($regionID)
|
||||
{
|
||||
global $RUNTIME;
|
||||
|
||||
$statementRegion = $RUNTIME['PDO']->prepare("SELECT regionName FROM regions WHERE uuid = ?");
|
||||
$statementRegion->execute(array($regionID));
|
||||
|
||||
while($rowRegion = $statementRegion->fetch())
|
||||
{
|
||||
return $rowRegion['regionName'];
|
||||
}
|
||||
|
||||
return "Unknown Region";
|
||||
}
|
||||
|
||||
public function getPartner($userID)
|
||||
{
|
||||
global $RUNTIME;
|
||||
|
||||
$statement = $RUNTIME['PDO']->prepare("SELECT profilePartner FROM userprofile WHERE useruuid = ?");
|
||||
$statement->execute(array($userID));
|
||||
|
||||
while($row = $statement->fetch())
|
||||
{
|
||||
if($row['profilePartner'] != "00000000-0000-0000-0000-000000000000")
|
||||
return $row['profilePartner'];
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public function allowOfflineIM($userID)
|
||||
{
|
||||
global $RUNTIME;
|
||||
|
||||
$statement = $RUNTIME['PDO']->prepare("SELECT imviaemail FROM usersettings WHERE useruuid = ?");
|
||||
$statement->execute(array($userID));
|
||||
|
||||
while($row = $statement->fetch())
|
||||
{
|
||||
return strtoupper($row['imviaemail']);
|
||||
}
|
||||
|
||||
return "FALSE";
|
||||
}
|
||||
|
||||
public function getUserMail($userID)
|
||||
{
|
||||
global $RUNTIME;
|
||||
|
||||
$statement = $RUNTIME['PDO']->prepare("SELECT Email FROM UserAccounts WHERE PrincipalID = ?");
|
||||
$statement->execute(array($userID));
|
||||
|
||||
while($row = $statement->fetch())
|
||||
{
|
||||
return $row['Email'];
|
||||
}
|
||||
|
||||
return "";
|
||||
}
|
||||
|
||||
public function getUserCount()
|
||||
{
|
||||
global $RUNTIME;
|
||||
|
||||
$statementUser = $RUNTIME['PDO']->prepare("SELECT COUNT(*) FROM UserAccounts");
|
||||
$statementUser->execute();
|
||||
return $statementUser->fetchColumn();
|
||||
}
|
||||
|
||||
public function getRegionCount()
|
||||
{
|
||||
global $RUNTIME;
|
||||
|
||||
$statementUser = $RUNTIME['PDO']->prepare("SELECT COUNT(*) FROM regions");
|
||||
$statementUser->execute();
|
||||
return $statementUser->fetchColumn();
|
||||
}
|
||||
|
||||
public function getOnlineCount()
|
||||
{
|
||||
global $RUNTIME;
|
||||
|
||||
$statementUser = $RUNTIME['PDO']->prepare("SELECT COUNT(*) FROM Presence");
|
||||
$statementUser->execute();
|
||||
return $statementUser->fetchColumn();
|
||||
}
|
||||
|
||||
public function gen_uuid()
|
||||
{
|
||||
return sprintf( '%04x%04x-%04x-%04x-%04x-%04x%04x%04x',
|
||||
// 32 bits for "time_low"
|
||||
mt_rand( 0, 0xffff ), mt_rand( 0, 0xffff ),
|
||||
|
||||
// 16 bits for "time_mid"
|
||||
mt_rand( 0, 0xffff ),
|
||||
|
||||
// 16 bits for "time_hi_and_version",
|
||||
// four most significant bits holds version number 4
|
||||
mt_rand( 0, 0x0fff ) | 0x4000,
|
||||
|
||||
// 16 bits, 8 bits for "clk_seq_hi_res",
|
||||
// 8 bits for "clk_seq_low",
|
||||
// two most significant bits holds zero and one for variant DCE1.1
|
||||
mt_rand( 0, 0x3fff ) | 0x8000,
|
||||
|
||||
// 48 bits for "node"
|
||||
mt_rand( 0, 0xffff ), mt_rand( 0, 0xffff ), mt_rand( 0, 0xffff )
|
||||
);
|
||||
}
|
||||
public function __construct(PDO $pdo)
|
||||
{
|
||||
$this->pdo = $pdo;
|
||||
$this->apcu = function_exists('apcu_fetch') && apcu_enabled();
|
||||
}
|
||||
?>
|
||||
|
||||
private function getUserNameFromGridData($userID, $table, $row): ?string
|
||||
{
|
||||
$statementGridUser = $this->pdo->prepare('SELECT '.$row.' FROM '.$table.' WHERE '.$row.' LIKE ?');
|
||||
$statementGridUser->execute(array($userID.';%'));
|
||||
|
||||
while ($rowGridUser = $statementGridUser->fetch()) {
|
||||
$userData = explode(";", $rowGridUser[$row]);
|
||||
|
||||
if (count($userData) >= 3) {
|
||||
$dbUserID = $userData[0];
|
||||
$dbUserName = $userData[2];
|
||||
|
||||
if ($dbUserID == $userID) {
|
||||
if ($this->apcu) {
|
||||
apcu_store('os_username_'.$userID, $dbUserName, 600);
|
||||
}
|
||||
return $dbUserName;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public function getUserName($userID): string
|
||||
{
|
||||
if ($userID == "00000000-0000-0000-0000-000000000000") {
|
||||
return "Unknown User";
|
||||
}
|
||||
|
||||
if ($this->apcu && apcu_exists('os_username_'.$userID)) {
|
||||
return apcu_fetch('os_username_'.$userID);
|
||||
}
|
||||
|
||||
$statementUser = $this->pdo->prepare('SELECT FirstName,LastName FROM UserAccounts WHERE PrincipalID = ?');
|
||||
$statementUser->execute(array($userID));
|
||||
|
||||
if ($rowUser = $statementUser->fetch()) {
|
||||
$name = $rowUser['FirstName'].' '.$rowUser['LastName'];
|
||||
if ($this->apcu) {
|
||||
apcu_store('os_username_'.$userID, $name, 300);
|
||||
}
|
||||
|
||||
return $name;
|
||||
}
|
||||
|
||||
$res = $this->getUserNameFromGridData($userID, 'GridUser', 'UserID');
|
||||
if ($res == null) {
|
||||
$res = $this->getUserNameFromGridData($userID, 'Friends', 'PrincipalID');
|
||||
}
|
||||
|
||||
return $res == null ? "Unknown User" : $res;
|
||||
}
|
||||
|
||||
public function getUserUUID($userName): ?string
|
||||
{
|
||||
$statementUser = $this->pdo->prepare('SELECT PrincipalID,FirstName,LastName FROM UserAccounts WHERE FirstName = ? AND LastName = ?');
|
||||
$statementUser->execute(explode(' ', $userName));
|
||||
|
||||
if ($rowUser = $statementUser->fetch()) {
|
||||
return $rowUser['PrincipalID'];
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public function getRegionName($regionID): string
|
||||
{
|
||||
$statementRegion = $this->pdo->prepare("SELECT regionName FROM regions WHERE uuid = ?");
|
||||
$statementRegion->execute(array($regionID));
|
||||
|
||||
if ($rowRegion = $statementRegion->fetch()) {
|
||||
return $rowRegion['regionName'];
|
||||
}
|
||||
|
||||
return "Unknown Region";
|
||||
}
|
||||
|
||||
public function getPartner($userID): string
|
||||
{
|
||||
$statement = $this->pdo->prepare("SELECT profilePartner FROM userprofile WHERE useruuid = ?");
|
||||
$statement->execute(array($userID));
|
||||
|
||||
while ($row = $statement->fetch()) {
|
||||
if ($row['profilePartner'] != "00000000-0000-0000-0000-000000000000") {
|
||||
return $row['profilePartner'];
|
||||
}
|
||||
}
|
||||
|
||||
return '';
|
||||
}
|
||||
|
||||
public function allowOfflineIM($userID): string
|
||||
{
|
||||
$statement = $this->pdo->prepare("SELECT imviaemail FROM usersettings WHERE useruuid = ?");
|
||||
$statement->execute(array($userID));
|
||||
|
||||
if ($row = $statement->fetch()) {
|
||||
return strtoupper($row['imviaemail']);
|
||||
}
|
||||
|
||||
return "FALSE";
|
||||
}
|
||||
|
||||
public function getUserMail($userID): string
|
||||
{
|
||||
$statement = $this->pdo->prepare("SELECT Email FROM UserAccounts WHERE PrincipalID = ?");
|
||||
$statement->execute(array($userID));
|
||||
|
||||
if ($row = $statement->fetch()) {
|
||||
return $row['Email'];
|
||||
}
|
||||
|
||||
return "";
|
||||
}
|
||||
|
||||
private function getEntryCount($table): int
|
||||
{
|
||||
$statementCount = $this->pdo->prepare('SELECT COUNT(*) AS Count FROM '.$table);
|
||||
$statementCount->execute();
|
||||
if ($row = $statementCount->fetch()) {
|
||||
return $row['Count'];
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
public function getUserCount(): int
|
||||
{
|
||||
return $this->getEntryCount('UserAccounts');
|
||||
}
|
||||
|
||||
public function getRegionCount(): int
|
||||
{
|
||||
return $this->getEntryCount('regions');
|
||||
}
|
||||
|
||||
public function getOnlineCount(): int
|
||||
{
|
||||
return $this->getEntryCount('Presence');
|
||||
}
|
||||
|
||||
public function deleteUser($uuid): bool
|
||||
{
|
||||
try {
|
||||
$this->pdo->beginTransaction();
|
||||
|
||||
$statementAuth = $this->pdo->prepare('DELETE FROM auth WHERE UUID = ?');
|
||||
$statementAuth->execute([$uuid]);
|
||||
|
||||
$statementAgentPrefs = $this->pdo->prepare('DELETE FROM AgentPrefs WHERE PrincipalID = ?');
|
||||
$statementAgentPrefs->execute([$uuid]);
|
||||
|
||||
$statementAvatars = $this->pdo->prepare('DELETE FROM Avatars WHERE PrincipalID = ?');
|
||||
$statementAvatars->execute([$uuid]);
|
||||
|
||||
$statementGridUser = $this->pdo->prepare('DELETE FROM GridUser WHERE UserID = ?');
|
||||
$statementGridUser->execute([$uuid]);
|
||||
|