fix: FAQ PHP warnings, billing nav, XML fatal-skip, Steam Workshop user menu
Agent-Logs-Url: https://github.com/GameServerPanel/GSP/sessions/86bb1e0e-2bbd-439b-88cd-7a624ad24761 Co-authored-by: iaretechnician <2749183+iaretechnician@users.noreply.github.com>
This commit is contained in:
parent
13de7c8383
commit
5c463d381f
6 changed files with 98 additions and 18 deletions
26
home.php
26
home.php
|
|
@ -187,6 +187,12 @@ function ogpHome()
|
||||||
foreach ((array)$servers_by_game_name as $game_name => $server_homes )
|
foreach ((array)$servers_by_game_name as $game_name => $server_homes )
|
||||||
{
|
{
|
||||||
$server_xml = read_server_config(SERVER_CONFIG_LOCATION."/".$server_homes[0]['home_cfg_file']);
|
$server_xml = read_server_config(SERVER_CONFIG_LOCATION."/".$server_homes[0]['home_cfg_file']);
|
||||||
|
if ($server_xml === FALSE)
|
||||||
|
{
|
||||||
|
// Bad XML – skip this game from the navigation list; error is
|
||||||
|
// already collected and will be shown to admins below.
|
||||||
|
continue;
|
||||||
|
}
|
||||||
$mod = $server_homes[0]['mod_key'];
|
$mod = $server_homes[0]['mod_key'];
|
||||||
// If query name does not exist use mod key instead.
|
// If query name does not exist use mod key instead.
|
||||||
if ($server_xml->protocol == "gameq")
|
if ($server_xml->protocol == "gameq")
|
||||||
|
|
@ -223,6 +229,26 @@ function ogpHome()
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
$game_homes_list = "";
|
$game_homes_list = "";
|
||||||
|
|
||||||
|
// Show admin-only warning for any game config XMLs that failed to parse.
|
||||||
|
if ($isAdmin) {
|
||||||
|
$xml_errors = function_exists('gsp_get_xml_errors') ? gsp_get_xml_errors() : array();
|
||||||
|
if (!empty($xml_errors)) {
|
||||||
|
echo "<div style='background:#fff3cd;border:1px solid #ffc107;border-radius:4px;padding:10px 14px;margin:10px 0;color:#856404;font-size:0.9em;'>";
|
||||||
|
echo "<strong>⚠ One or more game config XML files failed to load and have been skipped:</strong><ul style='margin:6px 0 0 16px;'>";
|
||||||
|
foreach ($xml_errors as $xe) {
|
||||||
|
echo "<li><code>" . htmlspecialchars(basename($xe['file']), ENT_QUOTES, 'UTF-8') . "</code>: "
|
||||||
|
. htmlspecialchars($xe['title'], ENT_QUOTES, 'UTF-8');
|
||||||
|
if (!empty($xe['details'])) {
|
||||||
|
echo " — <em>" . nl2br(htmlspecialchars($xe['details'], ENT_QUOTES, 'UTF-8')) . "</em>";
|
||||||
|
}
|
||||||
|
echo "</li>";
|
||||||
|
}
|
||||||
|
echo "</ul>";
|
||||||
|
echo "<p style='margin:6px 0 0;'>Use <a href='?m=config_games'>Game/Mod Config</a> to edit and fix the broken file(s).</p>";
|
||||||
|
echo "</div>";
|
||||||
|
}
|
||||||
|
}
|
||||||
?>
|
?>
|
||||||
<div class="menu-bg">
|
<div class="menu-bg">
|
||||||
<div class="menu">
|
<div class="menu">
|
||||||
|
|
|
||||||
|
|
@ -30,12 +30,9 @@ $module_required = FALSE;
|
||||||
// Module description
|
// Module description
|
||||||
$module_description = "Billing storefront / provisioning integration. Public ordering runs as a standalone site; panel pages provide provisioning and admin order management.";
|
$module_description = "Billing storefront / provisioning integration. Public ordering runs as a standalone site; panel pages provide provisioning and admin order management.";
|
||||||
|
|
||||||
// Register module menus so panel can show links (user and admin views)
|
// No panel menu entries – billing runs as a standalone website, not panel pages.
|
||||||
$module_menus = array(
|
// Install/uninstall/update DB logic below is still active.
|
||||||
array('subpage' => 'my_orders', 'name' => 'My Orders', 'group' => 'user'),
|
$module_menus = array();
|
||||||
array('subpage' => 'provision_servers', 'name' => 'Provision Servers', 'group' => 'user'),
|
|
||||||
array('subpage' => 'admin_orders', 'name' => 'Manage Orders', 'group' => 'admin')
|
|
||||||
);
|
|
||||||
|
|
||||||
$install_queries = array();
|
$install_queries = array();
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -52,6 +52,40 @@ if (!function_exists('ogp_render_config_error')) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Collect a non-fatal XML parse/validation error for a game config file.
|
||||||
|
* Errors are stored in a static array and can be retrieved via
|
||||||
|
* gsp_get_xml_errors(). Does NOT stop page execution.
|
||||||
|
*/
|
||||||
|
if (!function_exists('gsp_collect_xml_error')) {
|
||||||
|
function gsp_collect_xml_error(string $file, string $title, string $details = ''): void
|
||||||
|
{
|
||||||
|
$log_message = "[GSP] $title" . (empty($details) ? '' : ' Details: ' . $details);
|
||||||
|
error_log($log_message);
|
||||||
|
|
||||||
|
static $errors = [];
|
||||||
|
$errors[] = array(
|
||||||
|
'file' => $file,
|
||||||
|
'title' => $title,
|
||||||
|
'details' => $details,
|
||||||
|
);
|
||||||
|
// Store in a predictable global so callers (e.g. home.php) can read it
|
||||||
|
// even across include boundaries without having to call the function.
|
||||||
|
$GLOBALS['_gsp_xml_errors'][] = array(
|
||||||
|
'file' => $file,
|
||||||
|
'title' => $title,
|
||||||
|
'details' => $details,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!function_exists('gsp_get_xml_errors')) {
|
||||||
|
function gsp_get_xml_errors(): array
|
||||||
|
{
|
||||||
|
return isset($GLOBALS['_gsp_xml_errors']) ? $GLOBALS['_gsp_xml_errors'] : array();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (!function_exists('ogp_render_missing_xml_extensions')) {
|
if (!function_exists('ogp_render_missing_xml_extensions')) {
|
||||||
function ogp_render_missing_xml_extensions($missing_extensions)
|
function ogp_render_missing_xml_extensions($missing_extensions)
|
||||||
{
|
{
|
||||||
|
|
@ -114,36 +148,47 @@ function read_server_config( $filename )
|
||||||
ogp_ensure_xml_support();
|
ogp_ensure_xml_support();
|
||||||
|
|
||||||
if (!is_readable($filename)) {
|
if (!is_readable($filename)) {
|
||||||
ogp_render_config_error(
|
gsp_collect_xml_error(
|
||||||
|
$filename,
|
||||||
"Game configuration file is missing or unreadable.",
|
"Game configuration file is missing or unreadable.",
|
||||||
"Expected at: {$filename}"
|
"Expected at: {$filename}"
|
||||||
);
|
);
|
||||||
|
return FALSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
$previous_error_state = libxml_use_internal_errors(true);
|
$previous_error_state = libxml_use_internal_errors(true);
|
||||||
$dom = new DOMDocument();
|
$dom = new DOMDocument();
|
||||||
if ($dom->load($filename) === FALSE)
|
if ($dom->load($filename) === FALSE)
|
||||||
{
|
{
|
||||||
ogp_render_config_error(
|
gsp_collect_xml_error(
|
||||||
|
$filename,
|
||||||
"Unable to load XML configuration.",
|
"Unable to load XML configuration.",
|
||||||
"File: {$filename}\n".ogp_format_libxml_errors()
|
"File: {$filename}\n".ogp_format_libxml_errors()
|
||||||
);
|
);
|
||||||
|
libxml_use_internal_errors($previous_error_state);
|
||||||
|
return FALSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ( $dom->schemaValidate(XML_SCHEMA) !== TRUE )
|
if ( $dom->schemaValidate(XML_SCHEMA) !== TRUE )
|
||||||
{
|
{
|
||||||
ogp_render_config_error(
|
gsp_collect_xml_error(
|
||||||
|
$filename,
|
||||||
"XML configuration failed schema validation.",
|
"XML configuration failed schema validation.",
|
||||||
"File: {$filename}\nSchema: ".XML_SCHEMA."\n".ogp_format_libxml_errors()
|
"File: {$filename}\nSchema: ".XML_SCHEMA."\n".ogp_format_libxml_errors()
|
||||||
);
|
);
|
||||||
|
libxml_use_internal_errors($previous_error_state);
|
||||||
|
return FALSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
$xml = simplexml_import_dom($dom);
|
$xml = simplexml_import_dom($dom);
|
||||||
if($xml === false){
|
if($xml === false){
|
||||||
ogp_render_config_error(
|
gsp_collect_xml_error(
|
||||||
|
$filename,
|
||||||
"Failed to parse XML configuration.",
|
"Failed to parse XML configuration.",
|
||||||
"File: {$filename}\n".ogp_format_libxml_errors()
|
"File: {$filename}\n".ogp_format_libxml_errors()
|
||||||
);
|
);
|
||||||
|
libxml_use_internal_errors($previous_error_state);
|
||||||
|
return FALSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
$xml->addChild('home_cfg_file',basename($filename));
|
$xml->addChild('home_cfg_file',basename($filename));
|
||||||
|
|
|
||||||
|
|
@ -70,12 +70,28 @@ class rss_php {
|
||||||
***/
|
***/
|
||||||
private function loadParser($rss=false) {
|
private function loadParser($rss=false) {
|
||||||
if($rss) {
|
if($rss) {
|
||||||
|
// Strip a leading UTF-8 BOM and any whitespace before the XML declaration
|
||||||
|
// to prevent "Extra content at the end of the document" and related errors.
|
||||||
|
$rss = preg_replace('/^\xEF\xBB\xBF/', '', (string)$rss);
|
||||||
|
$rss = ltrim($rss);
|
||||||
|
|
||||||
|
// Reject obviously non-XML content early to avoid noisy libxml warnings.
|
||||||
|
if(strlen($rss) < 5 || $rss[0] !== '<') {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
$this->document = array();
|
$this->document = array();
|
||||||
$this->channel = array();
|
$this->channel = array();
|
||||||
$this->items = array();
|
$this->items = array();
|
||||||
$DOMDocument = new DOMDocument;
|
$DOMDocument = new DOMDocument;
|
||||||
$DOMDocument->strictErrorChecking = false;
|
$DOMDocument->strictErrorChecking = false;
|
||||||
$DOMDocument->loadXML($rss);
|
$prevErrors = libxml_use_internal_errors(true);
|
||||||
|
$loaded = $DOMDocument->loadXML($rss);
|
||||||
|
libxml_clear_errors();
|
||||||
|
libxml_use_internal_errors($prevErrors);
|
||||||
|
if($loaded === false) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
$this->document = $this->extractDOM($DOMDocument->childNodes);
|
$this->document = $this->extractDOM($DOMDocument->childNodes);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -99,6 +115,7 @@ class rss_php {
|
||||||
|
|
||||||
private function extractDOM($nodeList,$parentNodeName=false) {
|
private function extractDOM($nodeList,$parentNodeName=false) {
|
||||||
$itemCounter = 0;
|
$itemCounter = 0;
|
||||||
|
$tempNode = array();
|
||||||
foreach ((array)$nodeList as $values) {
|
foreach ((array)$nodeList as $values) {
|
||||||
if(substr($values->nodeName,0,1) != '#') {
|
if(substr($values->nodeName,0,1) != '#') {
|
||||||
if($values->nodeName == 'item') {
|
if($values->nodeName == 'item') {
|
||||||
|
|
|
||||||
|
|
@ -27,11 +27,6 @@ $module_version = "2.1";
|
||||||
$db_version = 1;
|
$db_version = 1;
|
||||||
$module_required = TRUE;
|
$module_required = TRUE;
|
||||||
$module_menus = array(
|
$module_menus = array(
|
||||||
array(
|
|
||||||
'subpage' => 'main',
|
|
||||||
'name' => 'Steam Workshop',
|
|
||||||
'group' => 'user'
|
|
||||||
),
|
|
||||||
array(
|
array(
|
||||||
'subpage' => 'workshop_admin',
|
'subpage' => 'workshop_admin',
|
||||||
'name' => 'Steam Workshop',
|
'name' => 'Steam Workshop',
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
<navigation>
|
<navigation>
|
||||||
<page key="main" file="main.php" access="user,admin" />
|
<page key="main" file="main.php" access="admin" />
|
||||||
<page key="uninstall" file="uninstall.php" access="user,admin" />
|
<page key="uninstall" file="uninstall.php" access="admin" />
|
||||||
<page key="workshop_admin" file="workshop_admin.php" access="admin" />
|
<page key="workshop_admin" file="workshop_admin.php" access="admin" />
|
||||||
</navigation>
|
</navigation>
|
||||||
Loading…
Add table
Add a link
Reference in a new issue