diff --git a/AdditionalSites/data.php b/AdditionalSites/data.php new file mode 100644 index 0000000..5f72fb2 --- /dev/null +++ b/AdditionalSites/data.php @@ -0,0 +1,137 @@ + ['PrincipalID','AccessPrefs','HoverHeight','Language','LanguageIsPublic','PermEveryone','PermGroup','PermNextOwner'], + 'assets' => ['name','description','assetType','local','temporary','data','id','create_time','access_time','asset_flags','CreatorID'], + 'auth' => ['UUID','passwordHash','passwordSalt','webLoginKey','accountType'], + 'Avatars' => ['PrincipalID','Name','Value'], + 'balances' => ['user','balance','status','type'], + 'classifieds' => ['classifieduuid','creatoruuid','creationdate','expirationdate','category','name','description','parceluuid','parentestate','snapshotuuid','simname','posglobal','parcelname','classifiedflags','priceforlisting'], + 'Friends' => ['PrincipalID','Friend','Flags','Offered'], + 'GridUser' => ['UserID','HomeRegionID','HomePosition','HomeLookAt','LastRegionID','LastPosition','LastLookAt','Online','Login','Logout'], + 'hg_traveling_data' => ['SessionID','UserID','GridExternalName','ServiceToken','ClientIPAddress','MyIPAddress','TMStamp'], + 'im_offline' => ['ID','PrincipalID','FromID','Message','TMStamp'], + 'inventoryfolders' => ['folderName','type','version','folderID','agentID','parentFolderID'], + 'inventoryitems' => ['assetID','assetType','inventoryName','inventoryDescription','inventoryNextPermissions','inventoryCurrentPermissions','invType','creatorID','inventoryBasePermissions','inventoryEveryOnePermissions','salePrice','saleType','creationDate','groupID','groupOwned','flags','inventoryID','avatarID','parentFolderID','inventoryGroupPermissions'], + 'migrations' => ['name','version'], + 'MuteList' => ['AgentID','MuteID','MuteName','MuteType','MuteFlags','Stamp'], + 'os_groups_groups' => ['GroupID','Location','Name','Charter','InsigniaID','FounderID','MembershipFee','OpenEnrollment','ShowInList','AllowPublish','MaturePublish','OwnerRoleID'], + 'os_groups_invites' => ['InviteID','GroupID','RoleID','PrincipalID','TMStamp'], + 'os_groups_membership' => ['GroupID','PrincipalID','SelectedRoleID','Contribution','ListInProfile','AcceptNotices','AccessToken'], + 'os_groups_notices' => ['GroupID','NoticeID','TMStamp','FromName','Subject','Message','HasAttachment','AttachmentType','AttachmentName','AttachmentItemID','AttachmentOwnerID'], + 'os_groups_principals' => ['PrincipalID','ActiveGroupID'], + 'os_groups_rolemembership' => ['GroupID','RoleID','PrincipalID'], + 'os_groups_roles' => ['GroupID','RoleID','Name','Description','Title','Powers'], + 'Presence' => ['UserID','RegionID','SessionID','SecureSessionID','LastSeen'], + 'regions' => ['uuid','regionHandle','regionName','regionRecvKey','regionSendKey','regionSecret','regionDataURI','serverIP','serverPort','serverURI','locX','locY','locZ','eastOverrideHandle','westOverrideHandle','southOverrideHandle','northOverrideHandle','regionAssetURI','regionAssetRecvKey','regionAssetSendKey','regionUserURI','regionUserRecvKey','regionUserSendKey','regionMapTexture','serverHttpPort','serverRemotingPort','owner_uuid','originUUID','access','ScopeID','sizeX','sizeY','flags','last_seen','PrincipalID','Token','parcelMapTexture'], + 'tokens' => ['UUID','token','validity'], + 'totalsales' => ['UUID','user','objectUUID','type','TotalCount','TotalAmount','time'], + 'transactions' => ['UUID','sender','receiver','amount','senderBalance','receiverBalance','objectUUID','objectName','regionHandle','regionUUID','type','time','secure','status','commonName','description'], + 'UserAccounts' => ['PrincipalID','ScopeID','FirstName','LastName','Email','ServiceURLs','Created','UserLevel','UserFlags','UserTitle','active'], + 'userdata' => ['UserId','TagId','DataKey','DataVal'], + 'userinfo' => ['user','simip','avatar','pass','type','class','serverurl'], + 'usernotes' => ['useruuid','targetuuid','notes'], + 'userpicks' => ['pickuuid','creatoruuid','toppick','parceluuid','name','description','snapshotuuid','user','originalname','simname','posglobal','sortorder','enabled','gatekeeper'], + 'userprofile' => ['useruuid','profilePartner','profileAllowPublish','profileMaturePublish','profileURL','profileWantToMask','profileWantToText','profileSkillsMask','profileSkillsText','profileLanguages','profileImage','profileAboutText','profileFirstImage','profileFirstText'], + 'usersettings' => ['useruuid','imviaemail','visible','email'], +]; +// Datenbank-Utility für alle Tabellen der Robust-Datenbank (OpenSim) +// Wiederverwendbar in anderen Skripten via require/include + +class RobustDB { + private $pdo; + + /** + * Erstelle RobustDB-Instanz. + * @param string|PDO $host Hostname oder PDO-Objekt + * @param string|null $dbname + * @param string|null $user + * @param string|null $pass + */ + public function __construct($host, $dbname = null, $user = null, $pass = null) { + if ($host instanceof PDO) { + $this->pdo = $host; + } else { + // Prüfe, ob datainc.php eine $pdo-Variable bereitstellt + if ($host === 'datainc') { + require_once __DIR__ . '/datainc.php'; + if (isset($pdo) && $pdo instanceof PDO) { + $this->pdo = $pdo; + return; + } else { + throw new Exception('Keine gültige PDO-Verbindung in datainc.php gefunden.'); + } + } + $dsn = "mysql:host=$host;dbname=$dbname;charset=utf8mb4"; + $options = [ + PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION, + PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC, + ]; + $this->pdo = new PDO($dsn, $user, $pass, $options); + } + } + + // Alle Tabellen auflisten + public function listTables() { + $stmt = $this->pdo->query("SHOW TABLES"); + return $stmt->fetchAll(PDO::FETCH_COLUMN); + } + + // Alle Einträge einer Tabelle lesen + public function getAll($table) { + $stmt = $this->pdo->query("SELECT * FROM `" . addslashes($table) . "`"); + return $stmt->fetchAll(); + } + + // Einzelnen Eintrag lesen (nach Primärschlüssel) + public function getById($table, $idColumn, $idValue) { + $sql = "SELECT * FROM `" . addslashes($table) . "` WHERE `$idColumn` = :id LIMIT 1"; + $stmt = $this->pdo->prepare($sql); + $stmt->execute(['id' => $idValue]); + return $stmt->fetch(); + } + + // Eintrag einfügen + public function insert($table, $data) { + $columns = array_keys($data); + $placeholders = array_map(function($col) { return ":$col"; }, $columns); + $sql = "INSERT INTO `" . addslashes($table) . "` (" . implode(",", $columns) . ") VALUES (" . implode(",", $placeholders) . ")"; + $stmt = $this->pdo->prepare($sql); + $stmt->execute($data); + return $this->pdo->lastInsertId(); + } + + // Eintrag aktualisieren + public function update($table, $idColumn, $idValue, $data) { + $set = []; + foreach ($data as $col => $val) { + $set[] = "`$col` = :$col"; + } + $sql = "UPDATE `" . addslashes($table) . "` SET " . implode(", ", $set) . " WHERE `$idColumn` = :id"; + $data['id'] = $idValue; + $stmt = $this->pdo->prepare($sql); + return $stmt->execute($data); + } + + // Eintrag löschen + public function delete($table, $idColumn, $idValue) { + $sql = "DELETE FROM `" . addslashes($table) . "` WHERE `$idColumn` = :id"; + $stmt = $this->pdo->prepare($sql); + return $stmt->execute(['id' => $idValue]); + } + + // Beliebige Abfrage (z.B. für komplexe Filter) + public function query($sql, $params = []) { + $stmt = $this->pdo->prepare($sql); + $stmt->execute($params); + return $stmt->fetchAll(); + } +} + +// Beispiel für die Nutzung in anderen Skripten: +// require_once 'statistics/data.php'; +// $db = new RobustDB($host, $dbname, $user, $pass); +// $result = $db->getAll('UserAccounts'); + +?> \ No newline at end of file diff --git a/AdditionalSites/datainc.php.example b/AdditionalSites/datainc.php.example new file mode 100644 index 0000000..e35355d --- /dev/null +++ b/AdditionalSites/datainc.php.example @@ -0,0 +1,30 @@ + true, + 'cookie_secure' => isset($_SERVER['HTTPS']) && $_SERVER['HTTPS'] === 'on', + 'cookie_samesite' => 'Strict', + ]); +} + +// Datenbankverbindung für Statistiksoftware +$dsn = 'mysql:host=localhost;dbname=opensim_database;charset=utf8mb4'; +$user = 'dein_db_user'; +$pass = 'dein_db_password'; +$options = [ + PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION, + PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC, + PDO::ATTR_EMULATE_PREPARES => false, +]; + +try { + $pdo = new PDO($dsn, $user, $pass, $options); +} catch (PDOException $e) { + // Im Produktivbetrieb keine Details ausgeben! + http_response_code(500); + exit('Interner Fehler.'); +} \ No newline at end of file diff --git a/AdditionalSites/datatest.php b/AdditionalSites/datatest.php new file mode 100644 index 0000000..db1e471 --- /dev/null +++ b/AdditionalSites/datatest.php @@ -0,0 +1,35 @@ + $columns) { + // Für assets: alle Spalten außer 'data' abfragen + if ($table === 'assets') { + $cols = array_filter($columns, function($c) { return $c !== 'data'; }); + $sql = "SELECT " . implode(", ", $cols) . " FROM `$table` LIMIT 1"; + $result = $db->query($sql); + echo "

$table

\n"; + if ($result && count($result) > 0) { + $row = $result[0]; + $row['[BLOB]'] = '[BLOB ausgeblendet]'; + echo '
' . htmlspecialchars(print_r($row, true)) . '
'; + } else { + echo 'Keine Einträge gefunden.'; + } + } else { + $result = $db->query("SELECT * FROM `$table` LIMIT 1"); + echo "

$table

\n"; + if ($result && count($result) > 0) { + echo '
' . htmlspecialchars(print_r($result[0], true)) . '
'; + } else { + echo 'Keine Einträge gefunden.'; + } + } +} \ No newline at end of file diff --git a/AdditionalSites/ssinc.php.example b/AdditionalSites/ssinc.php.example new file mode 100644 index 0000000..6161785 --- /dev/null +++ b/AdditionalSites/ssinc.php.example @@ -0,0 +1,30 @@ + true, + 'cookie_secure' => isset($_SERVER['HTTPS']) && $_SERVER['HTTPS'] === 'on', + 'cookie_samesite' => 'Strict', + ]); +} + +// Datenbankverbindung für Statistiksoftware +$dsn = 'mysql:host=localhost;dbname=opensim_stats;charset=utf8mb4'; +$user = 'dein_db_user'; +$pass = 'dein_db_passwort'; +$options = [ + PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION, + PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC, + PDO::ATTR_EMULATE_PREPARES => false, +]; + +try { + $pdo = new PDO($dsn, $user, $pass, $options); +} catch (PDOException $e) { + // Im Produktivbetrieb keine Details ausgeben! + http_response_code(500); + exit('Interner Fehler.'); +} \ No newline at end of file diff --git a/AdditionalSites/statistic.php b/AdditionalSites/statistic.php new file mode 100644 index 0000000..322ff36 --- /dev/null +++ b/AdditionalSites/statistic.php @@ -0,0 +1,409 @@ + true, + 'cookie_secure' => isset($_SERVER['HTTPS']) && $_SERVER['HTTPS'] === 'on', + 'cookie_samesite' => 'Strict', + ]); +} + +// CSRF-Basisschutz für POST-Formulare (falls später genutzt) +if ($_SERVER['REQUEST_METHOD'] === 'POST') { + if (!isset($_POST['csrf_token']) || !isset($_SESSION['csrf_token']) || $_POST['csrf_token'] !== $_SESSION['csrf_token']) { + http_response_code(403); + exit('Ungültiges CSRF-Token.'); + } +} + +// Regionen laden +$sql_regions = 'SELECT uuid, regionName, locX, locY, sizeX, sizeY, serverIP, serverPort FROM regions ORDER BY regionName'; +$regions = $pdo->query($sql_regions)->fetchAll(PDO::FETCH_ASSOC); + +// Online-User (Presence, falls leer: keine online) +$sql_online = 'SELECT p.UserID, ua.FirstName, ua.LastName, p.RegionID, r.regionName, p.LastSeen +FROM Presence p +LEFT JOIN UserAccounts ua ON p.UserID = ua.PrincipalID +LEFT JOIN regions r ON p.RegionID = r.uuid +ORDER BY p.LastSeen DESC'; +$online = $pdo->query($sql_online)->fetchAll(PDO::FETCH_ASSOC); + +// GridUser mit Status (Online/Offline) +$sql_griduser = 'SELECT gu.UserID, gu.LastRegionID, gu.Login, gu.Logout, gu.Online, ua.FirstName, ua.LastName +FROM GridUser gu +LEFT JOIN UserAccounts ua ON gu.UserID = ua.PrincipalID'; +$gridusers = $pdo->query($sql_griduser)->fetchAll(PDO::FETCH_ASSOC); + + +// MuteList laden +$sql_mute = 'SELECT m.AgentID, m.MuteID, m.MuteName, m.MuteType, ua.FirstName, ua.LastName FROM MuteList m LEFT JOIN UserAccounts ua ON m.MuteID = ua.PrincipalID'; +$mutelist = $pdo->query($sql_mute)->fetchAll(PDO::FETCH_ASSOC); + + +// Gruppen laden +$sql_groups = 'SELECT * FROM os_groups_groups ORDER BY Name ASC, Charter ASC'; +$groups = $pdo->query($sql_groups)->fetchAll(PDO::FETCH_ASSOC); + +// Benutzerinformationen laden +$sql_userinfo = 'SELECT * FROM userinfo ORDER BY simip ASC, avatar ASC, serverurl DESC'; +$userinfo = $pdo->query($sql_userinfo)->fetchAll(PDO::FETCH_ASSOC); + +?> + + + + + OpenSimulator Statistik + + + + + + + + + + + + + +
+ + OpenSimulator Statistik Dashboard +
+ +
+
+

OpenSimulator Region Statistik

+

Live-Statistiken zu Regionen und Benutzern

+
+ + + +
+

Regionen im Grid

+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameUUIDPositionGrößeServer-IPPort
Zur Zeit sind keine Regionen im Grid.
, x
+
+
+ + +
+

Gruppen im Grid

+
+ +
Zur Zeit sind keine Gruppen im Grid.
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
NameGruppenbeschreibung (Charter)Gründer (FounderID)LocationInsigniaIDMitgliedsbeitragOffen
+ +
+
+ + +
+

Online-Mitglieder

+
+ +
Zur Zeit befindet sich kein Mitglied im Grid.
+ + + + + + + + + + + + + + + + + + + + + + +
NameUserIDRegionRegion-NameLetzte Aktivität
+ +
+ +
+
+ + +
+

Benutzerinformationen

+
+ +
Zur Zeit sind keine Benutzerinformationen im Grid.
+ + + + + + + + + + + + + + + + +
AvatarServer-URL
+ +
+
+ + +
+

Alle GridUser

+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
StatusNameBenutzerkennungHeimatadresseVollständiger NameLetzte RegionLoginLogout
Zur Zeit gibt es keine GridUser im Grid.
+ + + Online + + Offline + +
+
+
+ + +
+

Stummgeschaltete Nutzer (MuteList)

+
+ +
Im Grid ist zur Zeit niemand stummgeschaltet.
+ + + + + + + + + + + + + + + + + + + + + + +
Stummschaltender (AgentID)Stummgeschaltet (MuteID)NameMuteNameMuteType
+ +
+
+ +
+ + + + + + + +