Sistemas web de MU Online: WebEngine e outros CMS
Conheça os principais sistemas web para servidores de MU Online — WebEngine, MuCMS e outros, como instalar, configurar e integrar com o banco SQL Server do servidor.
O site do servidor de MU Online é a face pública do servidor para os jogadores — é onde se cadastram, verificam o ranking, ativam VIP e acompanham notícias. Existem opções de sistemas prontos (WebEngine e similares) e a alternativa de construir do zero.
O site do servidor de MU Online é a face pública do servidor para os jogadores — é onde se cadastram, verificam o ranking, ativam VIP e acompanham notícias. Existem opções de sistemas prontos (WebEngine e similares) e a alternativa de construir do zero.
Tipos de sistemas web para MU Online
| Tipo | Vantagem | Desvantagem |
|---|---|---|
| WebEngine / CMS prontos | Rápido de instalar, já integrado | Código fechado, difícil de customizar, segurança variável |
| Portal customizado (PHP próprio) | Total controle, mais seguro | Requer desenvolvimento |
| Site estático + site PHP | Site bonito + funcionalidades | Mais complexo de manter |
WebEngine — o CMS mais usado
O WebEngine é um sistema PHP que integra nativamente com o banco SQL Server do MuServer. Versões da comunidade incluem:
- WebEngine 1.x — versões antigas, mais simples;
- WebEngine 2.x — com painel admin melhorado;
- WebEngine MuS6 — versão para Season 6;
- Sistemas derivados — vários forks com nomes diferentes.
Estrutura do WebEngine
webengine/
├── config/
│ ├── config.php ← configuração principal (banco, domínio)
│ ├── database.php ← configuração de conexão com SQL Server
│ └── email.php ← configuração de SMTP
├── admin/
│ ├── index.php ← painel admin
│ ├── ban.php ← gerenciar bans
│ └── news.php ← gerenciar notícias
├── includes/
│ ├── functions.php ← funções comuns
│ ├── auth.php ← autenticação
│ └── db.php ← conexão com banco
├── templates/
│ └── default/ ← tema do site
├── index.php ← página inicial
├── register.php ← cadastro de conta
├── login.php ← login no site
├── ranking.php ← ranking de personagens
└── account.php ← painel da conta
Configurar o WebEngine
<?php
// config/config.php — configuração principal
// Banco de dados do MuServer (SQL Server)
define('MU_SQL_SERVER', '(local)'); // IP ou hostname do SQL Server
define('MU_SQL_DATABASE', 'MuOnline');
define('MU_SQL_USER', 'mu_app');
define('MU_SQL_PASSWORD', 'SenhaApp@2026!');
// Banco do site (MySQL) — usado para notícias, usuários do portal, etc.
define('SITE_DB_HOST', 'localhost');
define('SITE_DB_NAME', 'mu_site');
define('SITE_DB_USER', 'mu_web');
define('SITE_DB_PASSWORD', 'SenhaSite@2026!');
// Configuração do servidor
define('SERVER_NAME', 'Meu Servidor MU');
define('SERVER_IP', '45.90.100.150'); // IP da VPS
define('MAX_LEVEL', 400);
define('MAX_RESETS', 100);
// URL do site
define('SITE_URL', 'https://www.meuservidor.com.br');
define('SITE_DOMAIN', 'meuservidor.com.br');
// Segurança
define('SECRET_KEY', 'chave_aleatoria_unica_por_servidor_2026'); // mude isso!
define('SESSION_LIFETIME', 7200); // 2 horas em segundos
Instalação básica do WebEngine
- Extraia os arquivos do WebEngine para a pasta do site (
/var/www/html/mu/no Linux ouC:\AppServ\www\mu\no Windows); - Edite
config/config.phpcom os dados do banco; - Importe o banco MySQL do site:
``bash mysql -u root -p mu_site < database/mu_site.sql ``
- Crie o arquivo
.htaccesspara URLs amigáveis (Apache):
``apache RewriteEngine On RewriteCond %{REQUEST_FILENAME} !-f RewriteCond %{REQUEST_FILENAME} !-d RewriteRule ^(.*)$ index.php?route=$1 [QSA,L] ``
- Configure as permissões de pasta:
``bash sudo chown -R www-data:www-data /var/www/html/mu/ sudo chmod -R 755 /var/www/html/mu/ sudo chmod -R 777 /var/www/html/mu/uploads/ ``
Construir sistema web próprio do zero
Se preferir controle total, você pode construir um portal PHP integrado com o banco do MuServer:
Estrutura básica recomendada
meu-portal-mu/
├── public/ ← raiz pública (DocumentRoot do Apache)
│ ├── index.php
│ ├── register.php
│ ├── ranking.php
│ └── assets/
│ ├── css/
│ ├── js/
│ └── img/
├── src/
│ ├── Database.php ← classe de conexão ao banco
│ ├── Auth.php ← autenticação
│ ├── Character.php ← queries de personagens
│ └── Account.php ← queries de contas
├── config/
│ └── config.php ← configurações (fora da raiz pública)
└── templates/
├── header.php
├── footer.php
└── ranking.php
src/Database.php
<?php
// src/Database.php — abstração de banco
class Database {
private static ?self $instance = null;
private PDO $pdo;
private function __construct() {
// Conexão ao SQL Server (banco do MuServer)
$dsn = "sqlsrv:Server=" . MU_SQL_SERVER . ";Database=" . MU_SQL_DATABASE;
$this->pdo = new PDO($dsn, MU_SQL_USER, MU_SQL_PASSWORD, [
PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC,
]);
}
public static function getInstance(): self {
if (self::$instance === null) {
self::$instance = new self();
}
return self::$instance;
}
public function query(string $sql, array $params = []): PDOStatement {
$stmt = $this->pdo->prepare($sql);
$stmt->execute($params);
return $stmt;
}
public function fetchAll(string $sql, array $params = []): array {
return $this->query($sql, $params)->fetchAll();
}
public function fetchOne(string $sql, array $params = []): ?array {
$result = $this->query($sql, $params)->fetch();
return $result ?: null;
}
}
public/ranking.php — página de ranking completa
<?php
require_once '../config/config.php';
require_once '../src/Database.php';
$db = Database::getInstance();
// Tabs: Level, Resets, Guild
$tab = $_GET['tab'] ?? 'level';
$page = max(1, (int)($_GET['page'] ?? 1));
$perPage = 50;
$offset = ($page - 1) * $perPage;
$query = match($tab) {
'resets' => "
SELECT Name, Class, cLevel, Resets, ConnectStat,
ROW_NUMBER() OVER (ORDER BY Resets DESC, cLevel DESC) AS Pos
FROM Character
WHERE CtlCode = 0
ORDER BY Resets DESC, cLevel DESC
OFFSET ? ROWS FETCH NEXT ? ROWS ONLY
",
'guild' => "
SELECT g.Name AS GuildName, g.Score, COUNT(u.Id) AS Members
FROM Guild g
LEFT JOIN G_UserList u ON u.G_Name = g.Name
WHERE g.Name != ''
GROUP BY g.Name, g.Score
ORDER BY g.Score DESC
OFFSET ? ROWS FETCH NEXT ? ROWS ONLY
",
default => "
SELECT Name, Class, cLevel, Resets, ConnectStat,
ROW_NUMBER() OVER (ORDER BY cLevel DESC, Resets DESC) AS Pos
FROM Character
WHERE CtlCode = 0
ORDER BY cLevel DESC, Resets DESC
OFFSET ? ROWS FETCH NEXT ? ROWS ONLY
"
};
$ranking = $db->fetchAll($query, [$offset, $perPage]);
// Nomes das classes
function getClassName(int $class): string {
return match(intdiv($class, 16) * 16 + ($class % 16)) {
0 => 'Dark Wizard', 1 => 'Soul Master', 2 => 'Grand Master',
16 => 'Dark Knight', 17 => 'Blade Knight', 18 => 'Blade Master',
32 => 'Elf', 33 => 'Muse Elf', 34 => 'High Elf',
48 => 'Magic Gladiator', 49 => 'Duel Master',
64 => 'Dark Lord', 65 => 'Lord Emperor',
80 => 'Summoner', 81 => 'Bloody Summoner', 82 => 'Dimension Master',
96 => 'Rage Fighter', 97 => 'Fist Master',
default => "Classe $class"
};
}
?>
<!DOCTYPE html>
<html lang="pt-BR">
<head>
<meta charset="UTF-8">
<title>Ranking - <?= SERVER_NAME ?></title>
<link rel="stylesheet" href="/assets/css/style.css">
</head>
<body>
<?php include '../templates/header.php'; ?>
<div class="ranking-container">
<div class="tabs">
<a href="?tab=level" class="<?= $tab==='level' ? 'active' : '' ?>">Level</a>
<a href="?tab=resets" class="<?= $tab==='resets' ? 'active' : '' ?>">Resets</a>
<a href="?tab=guild" class="<?= $tab==='guild' ? 'active' : '' ?>">Guilds</a>
</div>
<table class="ranking-table">
<?php if ($tab === 'guild'): ?>
<tr><th>#</th><th>Guild</th><th>Score</th><th>Membros</th></tr>
<?php foreach ($ranking as $i => $row): ?>
<tr>
<td><?= $offset + $i + 1 ?></td>
<td><?= htmlspecialchars($row['GuildName']) ?></td>
<td><?= number_format($row['Score']) ?></td>
<td><?= $row['Members'] ?></td>
</tr>
<?php endforeach; ?>
<?php else: ?>
<tr><th>#</th><th>Personagem</th><th>Classe</th><th>Level</th><th>Resets</th><th></th></tr>
<?php foreach ($ranking as $row): ?>
<tr class="<?= $row['ConnectStat'] ? 'online' : '' ?>">
<td><?= $row['Pos'] ?></td>
<td><?= htmlspecialchars($row['Name']) ?></td>
<td><?= getClassName((int)$row['Class']) ?></td>
<td><?= $row['cLevel'] ?></td>
<td><?= $row['Resets'] ?></td>
<td><?= $row['ConnectStat'] ? '🟢' : '' ?></td>
</tr>
<?php endforeach; ?>
<?php endif; ?>
</table>
<div class="pagination">
<?php if ($page > 1): ?>
<a href="?tab=<?= $tab ?>&page=<?= $page-1 ?>">← Anterior</a>
<?php endif; ?>
<span>Página <?= $page ?></span>
<?php if (count($ranking) === $perPage): ?>
<a href="?tab=<?= $tab ?>&page=<?= $page+1 ?>">Próxima →</a>
<?php endif; ?>
</div>
</div>
<?php include '../templates/footer.php'; ?>
</body>
</html>
Segurança em sistemas web de MU Online
Verificações essenciais antes de publicar
<?php
// Nunca fazer isso (SQL injection):
$user = $_POST['user'];
$sql = "SELECT * FROM MEMB_INFO WHERE memb_id = '$user'"; // VULNERÁVEL!
// Sempre fazer assim (prepared statements):
$stmt = $pdo->prepare("SELECT * FROM MEMB_INFO WHERE memb_id = ?");
$stmt->execute([$_POST['user']]); // SEGURO
// XSS — sempre usar htmlspecialchars() para exibir dados do banco:
echo htmlspecialchars($row['Name']); // SEGURO
echo $row['Name']; // VULNERÁVEL!
// CSRF — incluir token nos formulários:
$_SESSION['csrf_token'] = bin2hex(random_bytes(32));
// No form: <input type="hidden" name="csrf" value="<?= $_SESSION['csrf_token'] ?>">
// Na validação: if ($_POST['csrf'] !== $_SESSION['csrf_token']) die('CSRF');
Rate limiting no cadastro
<?php
// Limitar tentativas de cadastro por IP
function verificarRateLimit(string $ip, PDO $siteDb): bool {
$stmt = $siteDb->prepare("
SELECT COUNT(*) FROM registration_attempts
WHERE ip_address = ? AND attempt_at >= DATEADD(HOUR, -1, GETDATE())
");
$stmt->execute([$ip]);
$count = $stmt->fetchColumn();
if ($count >= 5) {
return false; // Máximo 5 cadastros por hora por IP
}
// Registrar esta tentativa
$siteDb->prepare("INSERT INTO registration_attempts (ip_address) VALUES (?)")
->execute([$ip]);
return true;
}
Checklist de sistema web
INSTALAÇÃO
[ ] Driver sqlsrv instalado no PHP
[ ] Conexão ao SQL Server testada
[ ] Banco MySQL do site importado
[ ] Permissões de pasta configuradas
FUNCIONALIDADES
[ ] Cadastro criando conta no SQL Server (MEMB_INFO)
[ ] Login no site funcionando
[ ] Ranking exibindo dados reais
[ ] Painel de conta exibindo personagens do jogador
[ ] Sistema de notícias funcionando
SEGURANÇA
[ ] Prepared statements em todas as queries
[ ] htmlspecialchars() em todos os outputs
[ ] Proteção CSRF nos formulários
[ ] Rate limiting no cadastro
[ ] HTTPS configurado (certificado SSL)
[ ] Senhas do banco fora da raiz pública (em config/ acima da public/)
Perguntas frequentes
O que é o WebEngine para MU Online?
WebEngine é um dos sistemas web mais conhecidos da comunidade de MU Online privado — um CMS PHP pré-pronto com cadastro de conta, ranking, sistema de VIP, doações e painel admin, integrado com o banco SQL Server do MuServer.
Preciso de WebEngine para ter um servidor?
Não — o servidor funciona sem site. O site é opcional, mas muito recomendado para cadastro de jogadores, ranking e comunicação com a comunidade.
Posso criar meu próprio site para MU Online sem usar sistemas prontos?
Sim — qualquer site PHP que se conecte ao SQL Server via driver sqlsrv pode integrar com o banco do MuServer. Os sistemas prontos economizam tempo, mas são menos customizáveis.
WebEngine é seguro?
Sistemas prontos da comunidade variam muito em qualidade de código. Antes de usar qualquer CMS de terceiros, revise o código para verificar se usa prepared statements e não tem backdoors.