PHP DO BÁSICO AO AVANÇADO – AULA 14 – Criando um SISTEMA baseado em PHP – A Estrutura Base

Tempo de Leitura: 14 Minutos

Nesta aula, vamos juntar todo o conteúdo que aprendemos e criar um sistema baseado em php e banco de dados, que tenha um login genérico, esta é praticamente uma necessidade de todos os sistemas baseados em internet, e devem permitir um gerenciamento de usuário e senha seguro e confiável. Escolhemos um sistema baseado em e-mail e senha, que possa ser facilmente expandido para permitir integração com redes sociais, controle de tempo de sessão, perfil de usuário, direcionamentos e páginas de acesso restrito ou aberto.

Para o funcionamento correto de qualquer sistema, devemos prever uma arquitetura genérica que possa atender e acomodar os diversos tipos de sistemas que iremos desenvolver na nossa carreira como programadores, e ser facilmente expandido para acomodar novas funcionalidades, e novos requisitos e padrões. Além de estar dentro dos princípios de codificação e de padrões de projetos.

Neste primeiro momento, vamos utilizar uma conexão PDO que pode ser feita com qualquer banco de dados, e criar as regras básicas de acesso ao sistema, onde de acordo com o perfil do usuário ele será direcionado para uma área específica, e que também permite a criação de páginas de acesso irrestrito, sem uso do login e senha.

Utilizando as práticas mais indicadas, usaremos uma arquitetura que separa os controles em PHP das views escritas em html e javascript, essa arquitetura é conhecida como MVC (Model View Controller) onde separamos as camadas de acesso, para uma melhor experiência, usaremos um conjunto de regras do servidor APACHE, que vai fazer o controle de acesso as páginas e diretórios, além de permitir para nosso sistema identificar as partes utilizando uma URL AMIGÁVEL, que será traduzida para o PHP em parâmetros, permitindo que todo o acesso ao sistema seja feito em um único ponto. Esta técnica é muito utilizada em diversos frameworks pois permite um maior controle do acesso por parte do programador, e garante uma facilidade de manutenção, em todas as rotinas.

Para que tudo isso funcione de maneira orquestrada, vamos criar um arquivo que faz um processo de boot e prepara o ambiente que vai funcionar como um arcabouço (esqueleto) do funcionamento, e permitir que ele seja facilmente expandido e acomode todas as necessidades criadas.

Quem quiser ver esse sistema em funcionamento, pode acessar o site: https://servja.brasap.com.br/ e o código fonte pode ser copiado e receber contribuições em https://github.com/RomeuTMC/ServJa onde você pode interagir através da Wiki e das Issues para contribuir com sugestões e com todos os detalhes de implementação e utilização do sistema.

A estrutura de pastas e arquivos, foi feita para uma melhor organização do conteúdo conforme seu tipo e sua função, criamos uma estrutura, onde, a pasta raiz (/) contém os arquivos de configuração, que devem ser editados pelo usuário para a instalação e configuração do sistema, de acordo com suas próprias necessidades. A pasta _framework contém os arquivos de bibliotecas de funções do core do sistema, necessárias para o funcionamento correto do sistema, e onde, são implementadas funções de uso que servem para todo o projeto como acesso a dados, controles de acesso, envio de emails e notificações, e outras funções criadas como um repositório de uso geral. A pasta _views possui todas as views feitas em HTML e possui subpastas com os arquivos CSS e JS das diversas bibliotecas. Por fim a pasta _controls possui todos os controles em PHP responsáveis por cada processo, e possui a subpasta ajax com arquivos PHP que respondem a chamadas AJAX para carregamento de conteúdo dinâmico, e a pasta classes para abrigar objetos e classes em PHP que podem vir a ser necessários no futuro, já que essa primeira parte do processo vai ser toda feita de maneira procedural.

Vamos a codificação de cada arquivo inicial de maneira detalhada. Você poderia setar qualquer outra configuração neste arquivo, nosso serviddor já possui no php.ini as configurações próprias do PHP, por isso não usamos nenhuma modificação, porém, você pode configurar ou pedir para o administrador do seu servidor de produção definir o que precisar, ou usar os conteúdos das primeiras aulas e configurar da melhor maneira para a sua necessidade. Em primeiro, para definir as regras de acesso, criamos um arquivo .htaccess com as regras básicas de controle de acesso ao sistema de arquivos, e também aos scripts, o próprio código já possui documentação para explicar cada parte do conteúdo:

# Desativa a listagem de conteúdo dos diretórios
Options -Indexes

# Bloqueia a abertura e execução de qualquer arquivo iniciado pelo sinal _
# Desta maneira, não precisa ficar checando em todos os arquivos PHP se foram chamados pelo index, basta nomea-los
#  com inicial _ que eles não são acessíveis, melhorando a performance.
# A estrutura do sistema já define nos includes esses nomes de maneira correta, veja nos código PHP
<Files "_*">
    Require all denied
</Files>

# Ativa o ROUTER para URL AMIGAVEL, ou seja, todo o conteúdo de diretórios e arquivos será traduzido para a variável
#  route, acessível via GET
Options +FollowSymLinks
RewriteEngine On
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^(.*)$ index.php?route=$1 [NC,L]

# HABILITA o CACHE AUTOMATICO do NAVEGADOR, com duração personalizada para imagens e arquivos estáticos, lembre-se 
#  que em desenvolvimento, você pode deixar o cache desabilitado, este cache prevê uso em producao
<IfModule mod_expires.c>
    ExpiresActive On
    # Images
    ExpiresByType image/jpeg "access plus 1 year"
    ExpiresByType image/gif "access plus 1 year"
    ExpiresByType image/png "access plus 1 year"
    ExpiresByType image/webp "access plus 1 year"
    ExpiresByType image/svg+xml "access plus 1 year"
    ExpiresByType image/x-icon "access plus 1 year"
    # Video
    ExpiresByType video/webm "access plus 1 year"
    ExpiresByType video/mp4 "access plus 1 year"
    ExpiresByType video/mpeg "access plus 1 year"
    # Fonts
    ExpiresByType font/ttf "access plus 1 year"
    ExpiresByType font/otf "access plus 1 year"
    ExpiresByType font/woff "access plus 1 year"
    ExpiresByType font/woff2 "access plus 1 year"
    ExpiresByType application/font-woff "access plus 1 year"
    # CSS, JavaScript
    ExpiresByType text/css "access plus 1 month"
    ExpiresByType text/javascript "access plus 1 month"
    ExpiresByType application/javascript "access plus 1 month"
    # Others
    ExpiresByType application/pdf "access plus 1 month"
    ExpiresByType image/vnd.microsoft.icon "access plus 1 year"
</IfModule>

# HABILITA a COMPACTAÇÃO ZIP se servidor e cliente permitirem, economiza banda e acelera o carregamento de arquivos
#  estáticos que podem ser re-distribuidos por uma CDN
<IfModule mod_deflate.c>
    AddOutputFilterByType DEFLATE text/html
    AddOutputFilterByType DEFLATE text/css
    AddOutputFilterByType DEFLATE text/javascript
    AddOutputFilterByType DEFLATE text/xml
    AddOutputFilterByType DEFLATE text/plain
    AddOutputFilterByType DEFLATE image/x-icon
    AddOutputFilterByType DEFLATE image/svg+xml
    AddOutputFilterByType DEFLATE application/rss+xml
    AddOutputFilterByType DEFLATE application/javascript
    AddOutputFilterByType DEFLATE application/x-javascript
    AddOutputFilterByType DEFLATE application/xml
    AddOutputFilterByType DEFLATE application/xhtml+xml
    AddOutputFilterByType DEFLATE application/x-font
    AddOutputFilterByType DEFLATE application/x-font-truetype
    AddOutputFilterByType DEFLATE application/x-font-ttf
    AddOutputFilterByType DEFLATE application/x-font-otf
    AddOutputFilterByType DEFLATE application/x-font-opentype
    AddOutputFilterByType DEFLATE application/vnd.ms-fontobject
    AddOutputFilterByType DEFLATE font/ttf
    AddOutputFilterByType DEFLATE font/otf
    AddOutputFilterByType DEFLATE font/opentype
    # Para Browser que nao permitem a COMPACTAÇÃO
    BrowserMatch ^Mozilla/4 gzip-only-text/html
    BrowserMatch ^Mozilla/4\.0[678] no-gzip
    BrowserMatch \bMSIE !no-gzip !gzip-only-text/html
</IfModule>

# Ativa a Compactação, se o MOD_DEFLATE não tiver habilitado, usa outro método do proprio apache
<ifModule mod_gzip.c>
    mod_gzip_on Yes
    mod_gzip_dechunk Yes
    mod_gzip_item_include file \.(html?|txt|css|js|php|pl)$
    mod_gzip_item_include mime ^application/x-javascript.*
    mod_gzip_item_include mime ^text/.*
    mod_gzip_item_exclude rspheader ^Content-Encoding:.*gzip.*
    mod_gzip_item_exclude mime ^image/.*
    mod_gzip_item_include handler ^cgi-script$
</ifModule>

# DESABILITA o XSS para Cros-Site-Request, Para que você possa servir micro-serviços da sua aplicação para outros
#  desenvolvedores e usar entre diferentes sites
Header always set Strict-Transport-Security max-age=31536000

O Arquivo index.php é o ponto principal da aplicação, e ele que vai ser o único meio de acesso a todos os dados do nosso aplicativo, sendo responsável pelo processamento de todas as requisições, e o direcionamento correto de cada chamada. Ele também faz o “boot” do ambiente, carregando todos os módulos do framework de trabalho que está sendo desenvolvido. Seu código é simples e está comentado para um melhor entendimento:

<?php
/**
 * BRASAP FRAMEWORK START FILE (INDEX)
 *  php version 7.4.3
 * 
 * @category PHP_SimplifiedFrameworkNoOOP
 * @package  BRASAP_FRAMEWORK
 * @author   Romeu Gomes de Sousa <[email protected]>
 * @license  GNU GPL 3.0 - Livre uso e Distribuição
 * @version  GIT:  
 * @link     https://brasap.com.br
 */

require_once __DIR__.'/_defs.php'; // arregas as definições do sistema e ambiente
require_once __DIR__.'/_load.php'; //Load do FRAMEWORK e funções gerais
require_once __DIR__.'/_startup.php'; // Inicialização sessão/autenticação/validação
// Executa o load do CONTROL requisitado pela URL
// Verifica se o arquivo requisitado existe e inclui
if (file_exists(__DIR__."/_controls/_".$_SESSION['control']."_control.php")) {
    include_once __DIR__."_controls/_".$_SESSION['control']."_control.php";
} else {
    // se o arquivo não existe, verifica se o sistema esta setado como ambiente 
    //  DEV ou produção e mostra a saida correta
    if (AMBIENTE == 'DEVELOPER') {
        _out("_".$_SESSION['control']."_control.php", 200);
    } else {
        _out('CHAMADA PARA PROCEDIMENTO INVÁLIDO, CONTACTE O ADMINISTRADOR', 200);
    }
}
// se o CONTROL não criou um redirecionamento, monta a estrutura base,
// importando os JAVASCRIPTS e CSS do Jquery/Bootstrap e outras
// bibliotecas de código disponíveis em repositórios
?>
<!DOCTYPE html>
    <head>
        <meta charset="UTF-8">
        <meta name="viewport" 
            content="width=device-width, initial-scale=1.0, shrink-to-fit=no">
        <meta name="google-site-verification" 
            content="lwhjBq1Newn4vJWEU1Lx_0zaKWPWd4GlgDgg8PpPgL8" />
        <title><?php echo SISTEMA; ?></title>
        <link rel="shortcut icon" href="favicon.png" />
        <link rel="stylesheet"
            href="https://fonts.googleapis.com/css2
            ?family=Inter:[email protected];400;700&display=swap"/>
        <link rel="stylesheet"
            href="https://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/4.4.1/css/
            bootstrap.min.css"
            integrity="sha256-L/W5Wfqfa0sdBNIKN9cG6QA5F2qx4qICmU2VgLruv9Y=" 
            crossorigin="anonymous" />
        <link rel="stylesheet"
            href="https://cdnjs.cloudflare.com/ajax/libs/datatables/1.10.19/css/
            dataTables.bootstrap4.min.css"
            integrity="sha256-F+DaKAClQut87heMIC6oThARMuWne8+WzxIDT7jXuPA=" 
            crossorigin="anonymous" />
        <link rel="stylesheet" 
            href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/5.12.1/css/
            all.min.css"
            integrity="sha256-mmgLkCYLUQbXn0B1SRqzHar6dCnv9oZFPEC1g1cwlkk=" 
            crossorigin="anonymous" />
        <link href="css/global.css" rel="stylesheet">
        <script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.5.1/
            jquery.min.js"
            integrity="sha512-bLT0Qm9VnAYZDflyKcBaQ2gg0hSYNQrJ8RilYldYQ1F
            xQYoCLtUjuuRuZo+fjqhx/qtq/1itJ0C2ejDxltZVFg==" 
            crossorigin="anonymous"></script>
        <script src="https://cdnjs.cloudflare.com/ajax/libs/
            twitter-bootstrap/4.4.1/js/bootstrap.min.js"
            integrity="sha256-WqU1JavFxSAMcLP2WIOI+GB2zWmShMI82mTpLDcqFUg=" 
            crossorigin="anonymous"></script>
        <script src="https://cdn.jsdelivr.net/npm/[email protected]"></script>
        <script src="https://cdnjs.cloudflare.com/ajax/libs/jquery.mask/1.14.16/
            jquery.mask.min.js"
            integrity="sha256-Kg2zTcFO9LXOc7IwcBx1YeUBJmekycsnTsq2RuFHSZU=" 
            crossorigin="anonymous"></script>
        <script src="https://cdnjs.cloudflare.com/ajax/libs/jquery-validate/1.19.1/
            jquery.validate.min.js"
            integrity="sha256-sPB0F50YUDK0otDnsfNHawYmA5M0pjjUf4TvRJkGFrI=" 
            crossorigin="anonymous"></script>
        <script type="text/javascript" src="js/main.js"></script>
        <script src="https://cdnjs.cloudflare.com/ajax/libs/datatables/1.10.19/js/
            jquery.dataTables.min.js"
            integrity="sha256-t5ZQTZsbQi8NxszC10CseKjJ5QeMw5NINtOXQrESGSU=" 
            crossorigin="anonymous"></script>
        <script src="https://cdnjs.cloudflare.com/ajax/libs/
            datatables/1.10.19/js/dataTables.bootstrap4.min.js"
            integrity="sha256-hJ44ymhBmRPJKIaKRf3DSX5uiFEZ9xB/qx8cNbJvIMU=" 
            crossorigin="anonymous"></script>
        <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/
            limonte-sweetalert2/7.33.1/sweetalert2.min.css" 
            integrity="sha512-LhZScx/m/WBAAHyiPnM+5hcsmCMjDDOgOqoT9wyIcs/
            QUPm6YxVNGZjQG5iP8dhWMWQAcUUTE3BkshtrlGbv2Q==" 
            crossorigin="anonymous" />
        <link rel="stylesheet" href="https://unpkg.com/swiper/swiper-bundle.css">
    </head>

    <body data-spy="scroll" data-target=".navbar" data-offset="170">
        <header>
        <div id="loader" style="display: block;">
            <!-- DIV que SOBREPOE A TELA com imagem de CARREGANDO para as chamadas -->
        </div>
        <script>
            //Cria o SPINNER para fazer a tela de LOADING antes das chamadas AJAX
            var spinner = $('#loader');
            spinner.hide();
       
            // cria a função para mostrar as mensagens de erro 
            // de usuário geradas no PHP
            var error_no = <?php echo $_SESSION['erro_no']; ?>;
            if(error_no==1){ sTitulo='SUCESSO !'; sIcon='success'; }
            else if(error_no==2){ sTitulo='ERRO !';  sIcon='error';}
            else if(error_no==3){ sTitulo='ATENÇÃO !';  sIcon='warning';}
            else if(error_no==4){ sTitulo='INFORMAÇÃO !'; sIcon='info'; }
            else if(error_no==5){ sTitulo='QUESTÃO !'; sIcon='question'; }
            else { error_no=0; sTitulo=''; }
            var sMens = '<?php echo $_SESSION['erro']; ?>';
                if (1==1) {
                    Swal.fire({
                        title: sTitulo,
                        html: sMens,
                        icon: sIcon,
                        confirmButtonColor: '#d33',
                        confirmButtonText: 'Fechar'
                    })
                }
            </script>
        </header>
        <section>
        <!-- AREA PRINCIPAL do site, com a VIEW chamada pelo CLIENTE -->
            <div class=main>
                <?php
                //INCLUI CONFORME A CHAMADA DO ROTEAMENTO
                if (file_exists(
                    __DIR__."_views/_".$_SESSION['control'].
                    '/_'.$_SESSION['view']."_view.php"
                )
                ) {
                    include_once __DIR__."_views/_".$_SESSION['control'].'/_'.
                                $_SESSION['view']."_view.php";
                } else {
                    if (AMBIENTE == 'DEVELOPER') {
                        _out("VIEW INEXISTENTE->/".$_SESSION['control'].'/_'.
                            $_SESSION['view']."_view.php", 200);
                    } else {
                        _out("FALHA NO PROCESSAMENTO DA RESPOSTA, CONTACTE ADMINISTRADOR", 200);
                    }
                }
                ?>
            </div>
        </section>
        <nav>
        <!-- AREA DESTINADA A UM MENU DE NAVEGAÇÃO, com os acessos do usuário -->
        </nav>
        <footer>
        <!-- AREA DE RODAPÉ, pode ser usada para incluir uma mensagem, ou dados do usuário -->
        </footer>
    </body>
</html>
<?php
    // Finaliza o script fechando as conexões e dando a saida de mensagens para o DEVELOPER
    //  fechando as conexoes de bancos de dados, sockets, e outras. A apresentando dados da
    //  request para que seja facilitado o rastreio de bugs ou possiveis pontos de falhas.
    require __DIR__."/_footer.php"; 
?>

O arquivo _defs.php é uma espécie de arquivo de configuração, que carrega os principais parâmetros estáticos, e de conexões ou outros acessos que precisem ser editados de acordo com a instalação ou dados do sistema, sendo um concentrador de configurações de credenciais entre outros, esses dados serão acrescentados de acordo com a necessidade do projeto, e novos dados serão incluídos nas próximas aulas:

<?php
/**
 * BRASAP FRAMEWORK ARQUIVO DE DEFINIÇÔES DO USUARIO (_DEFS)
 *  php version 7.4.3
 * 
 * @category PHP_SimplifiedFrameworkNoOOP
 * @package  BRASAP_DEFINITIONS
 * @author   Romeu Gomes de Sousa <[email protected]>
 * @license  GNU GPL 3.0 - Livre uso e Distribuição
 * @version  GIT:  
 * @link     https://brasap.com.br
 */

// Define as CONSTANTES DE PARAMETRIZAÇÃO
define("SISTEMA", 'ServJa - Portal de Serviços'); 
define("VERSAO", "Versão 1.0"); // VERSÃO DO SISTEMA
define(
    "COPYRIGHT", 
    "Copyright Romeu Gomes de Sousa - ".
    "Brasap Sistemas - 11/2020 - ".date('m/Y').' - '.
    "Livre Uso e Distribução, se citada a fonte."
);
define("URL", "https://servja.brasap.com.br"); //URL da RAIZ do SISTEMA
define("EMAIL", "[email protected]"); //Email do Servidor/Administrador
define("EMAIL_FROM", SISTEMA." <".EMAIL.">");
define("SERVERDB", "127.0.0.1");
define("DBNAME", "");
define("DBUSER", "");
define("DBPASSW", "");
define("SNAME", "SERVJA"); //nome do serviço ou api
define("USER", md5($_SERVER['REMOTE_ADDR'].$_SERVER['HTTP_USER_AGENT'])); //hash do ip/navegador do usuario
define("SSID", SNAME.USER); //sessao especifica do usuario para os cookies
define("AMBIENTE", "DEVELOPER"); //DEVELOPER, HOMOLOG, PRODUCTION

// Define as diretrizes de INICIALIZAÇÃO DO AMBIENTE DO SERVIDOR
ini_set("session.name", SSID);
date_default_timezone_set('America/Sao_Paulo');
$cookieParams['lifetime'] = 0;
$cookieParams['domain'] = URL;
$cookieParams['secure'] = true;
$cookieParams['httponly'] = true;
$cookieParams['samesite'] = "Lax";
session_set_cookie_params($cookieParams);
session_name(SSID);
if(AMBIENTE == 'DEVELOPER'){
    error_reporting(E_ALL);
    ini_set("display_startup_errors", true);
    ini_set("display_errors", true);
    ini_set("error_log",__DIR__."_ERROS_DEV.LOG");
} elseif (AMBIENTE == 'HOMOLOG') {
    error_reporting(E_ERROR | E_CORE_ERROR | E_COMPILE_ERROR | E_USER_ERROR);
    ini_set("display_startup_errors", true);
    ini_set("display_errors", true);
    ini_set("error_log",__DIR__."_ERROS_HOM.LOG");
} else {
   error_reporting(E_ERROR); 
   ini_set("display_startup_errors", false);
   ini_set("display_errors", false);
   ini_set("error_log",__DIR__."_ERROS_PROD.LOG");
}
ini_set("default_charset", "UTF-8");
ini_set("sendmail_from", EMAIL);
session_start();
?>

O arquivo _load.php contém as classes e funções do usuário, que podem ser objetos ou procedurais, que são carregadas de acordo com as necessidades do projeto específico, não vamos entrar em detalhes nelas neste momento, pois assim que o projeto for crescendo, novas rotinas serão acrescentadas a este arquivo:

<?php
/**
 * BRASAP FRAMEWORK AUTOLOAD para FUNÇÕES GENERICAS DE TODO O PROJETO
 *  - INSIRA OS REQUIRES/INCLUDES/USES/CLASSES CORRETOS PARA SEU USO AQUI
 *  php version 7.4.3
 * 
 * @category PHP_SimplifiedFrameworkNoOOP
 * @package  BRASAP_AUTOLOADING
 * @author   Romeu Gomes de Sousa <[email protected]>
 * @license  GNU GPL 3.0 - Livre uso e Distribuição
 * @version  GIT:  
 * @link     https://brasap.com.br
 */

require_once __DIR__.'/_framework/_base.php';
require_once __DIR__.'/_framework/_mysql.php';
?>

Esta é a base do sistema, ou seja, o seu esqueleto, os arquivos contidos nas pastas _framework são os responsáveis pelas funções genéricas de acordo com seu tipo, deixamos somente o necessário para este momento, e nas próximas aulas, vamos explicando e estendendo suas funcionalidades, vamos a cada um deles, na ordem que foram incluidos:

<?php
// _base.php
/**
 * BRASAP FRAMEWORK - BASE FUNCTIONS - CORE DO FRAMEWORK
 *  php version 7.4.3
 * 
 * @category BRASAP/FrameBase
 * @package  BRASAP
 * @author   Romeu Gomes de Sousa <[email protected]>
 * @license  GNU GPL 3.0 - Livre uso e Distribuição
 * @version  GIT:  
 * @link     https://brasap.com.br
 */

/**
 * Realiza a saída com retorno de código de erro http
 *  pode ser usada para saida html, json, xml, etc.
 *  faz o calculo de EXECTIME para todas as requisições
 * 
 * @param $_msg   = Mensagem de Erro 
 * @param $excode = Código de ERRO HTTP conforme tabela: 
 *                https://developer.mozilla.org/pt-BR/docs/Web/HTTP/Status
 * 
 * @return VOID - Gera um ERRO HTTP conforme especificado
 */
function _out($_msg, $excode = 200) 
{
    $_SESSION['rtStop'] = microtime(true);
    $time = $_SESSION['rtStop']-$_SESSION['rtStart'];
    $_SESSION['exec_time']="".round($time, '3')." - Segundos";
    $_SESSION['HTTP_ERRO']=$excode;
    $_SESSION['MENSAGEM']=$_msg;
    if (AMBIENTE == 'DEVELOPER') {
        http_response_code($excode);
        echo "<h3>$_msg</h3><pre><br>SESSION========================<br>";
        print_r($_SESSION);
        echo "<br>POST=========================<br>";
        print_r($_POST);
        echo "<br>GET=========================<br>";
        print_r($_GET);
        echo "<br>GET=========================<br>";
        print_r($_COOKIE);
        exit($excode);
    } else {
        echo "<center><h1>UM ERRO OCORREU!</h1><h2>".
             "UMA FALHA IMPEDIU A EXECUÇÃO DE SUA SOLICITAÇÃO, ".
             "A MENSAGEM RETORNADA PELO SISTEMA FOI:<br>$_msg</h2></center>";
        exit($excode);
    }
    return 0;
}

/**
 * Verifica se a SESSÃO está LOGADA com o perfil correto
 * 
 * @param $perfil = string - nome da sessão de login
 * 
 * @return BOOLEAN = true se logado com o perfil, 
 *                 false se não logado ou com perfil diferente
 */  
function logado($perfil = 'LOGON GENERICO') 
{
    if ($_SESSION['login']!="$perfil") {
        _out('PERFIL DE LOGIN ERRADO - REFAÇA SEU LOGIN', 200);
        return false;
    } else {
        $_SESSION['login']="$perfil";
        return true;
    }
}

/**
 * Converte uma String de Texto no padrão SLUG URL
 * 
 * @param $text = Texto que sera transformado em SLUG
 * 
 * @return STRING = Texto com os caracteres no formato SLUG para URL
 */
function slug($text)
{
    // replace não letras ou digitos por -
    $text = preg_replace('~[^\pL\d]+~u', '-', $text);
    // transliterate
    $text = iconv('utf-8', 'us-ascii//TRANSLIT', $text);
    // remove Caracteres Inválidos
    $text = preg_replace('~[^-\w]+~', '', $text);
    $text = trim($text, '-');
    // remove duplicidades de replace
    $text = preg_replace('~-+~', '-', $text);
    $text = strtolower($text); 
    if (empty($text)) {
        // retorna n-a nome vazio
        return 'n-a';
    }
    // retorna TEXTO em formato SLUG
    return $text; 
}
?>
<?php
// _mysql.php
/**
 * BRASAP FRAMEWORK MYSQL - FUNÇÔES ESPECÍFICAS DE ABSTRAÇÃO PARA ESTE DB
 *  php version 7.4.3
 * 
 * @category PHP_SimplifiedFrameworkNoOOP
 * @package  BRASAP
 * @author   Romeu Gomes de Sousa <[email protected]>
 * @license  GNU GPL 3.0 - Livre uso e Distribuição
 * @version  GIT:  
 * @link     https://brasap.com.br
 */

/**
 * Faz a conexão com o BANCO DE DADOS PDO::MYSQL
 * 
 * @return POINTER - Ponteiro para a conexão do BD
 */
function conectDb() 
{
    global $db;
    try {
        $dbhost=SERVERDB;
        $dbname=DBNAME;
        $dbuser=DBUSER;
        $dbpass=DBPASSW;
        $db = new PDO(
            "mysql:host=$dbhost;dbname=$dbname;charset=utf8", 
            $dbuser,
            $dbpass
        );
    } catch (PDOException $e) {
        _out("ERRO! Banco de Dados: " . $e->getMessage(), 503);
    }
    $r=SqlQuery("SET NAMES utf8");
    return $db;
}

/**
 * Executa uma QUERY SELECT com ou sem PREPARE
 * 
 * @param $sql = String - Query SQL a ser executada
 * @param $pr  = Array - Opcional, dos dados em PREPARE
 * 
 * @return POINTER = Ponteiro para os dados retornados
 *         FALSE   = Em caso de falha com a execução da query
 */
function sqlQuery($sql, array $pr = null) 
{
    global $db;
    $r=$db->prepare("$sql");
    if (!$r->execute($pr)) {
        $error= $r->errorInfo();
        if (AMBIENTE == 'DEVELOPER') {
            $erro="SQL ERRO:".$error[0].'-'.$error[1].'-'.$error[2];
        } else {
            $erro="SQL ERRO:".$error[1].'-'.$error[2];;
        }
        _out("$erro", 504);
        return false;
    };
    return $r;
}

/**
 * Captura osvalores salvos na estrutura, para campos ENUM, pode ser
 *  usada para preencher um select, com os dados da tabela, deixando 
 *  as regras de negócio diretamente no banco
 * 
 * @param $tbl   = TABELA que contém os dados
 * @param $colum = COLUNA nome da coluna com o valor ENUM
 * 
 * @return ARRAY = Array com todos os valores possíveis
 */
function getenumval($tbl, $colum)
{
    global $db;
    $r=SqlQuery(
        "SELECT SUBSTRING(COLUMN_TYPE,5) as v 
        FROM information_schema.COLUMNS WHERE TABLE_SCHEMA='".DBNAME."' 
        AND TABLE_NAME='$tbl' AND COLUMN_NAME='$colum'"
    );
    $l=$r->fetch(PDO::FETCH_ASSOC);
    $l=trim(trim($l['v'], "()"));
    $l=str_getcsv($l, ',', "'");
    foreach ($l as $k=>$v) {
        $m[$v]=$v;
    }
    asort($m);
    return $m;
}
  
?>

O arquivo _startup.php executa as funções necessárias para todo o sistema, como verificar se esta ou não logado e salvar o status se não tiver, gerar as estatísticas de acesso e uso, definir a o roteamento, conectar o DB se este for usado,

<?php 
/**
 * BRASAP FRAMEWORK START FILE
 *  php version 7.4.3
 * 
 * @category PHP_SimplifiedFrameworkNoOOP
 * @package  BRASAP_STARTUP_FILE (_startup)
 * @author   Romeu Gomes de Sousa <[email protected]>
 * @license  GNU GPL 3.0 - Livre uso e Distribuição
 * @version  GIT:  
 * @link     https://brasap.com.br
 */

//Se a autenticação não está feita, define explicitamante como falsa
if (!isset($_SESSION['login'])) {
    $_SESSION['login']=0;
}
// salva na sessão os dados de estatistica e acesso ao servidor
$_SESSION['server']=URL;
$_SESSION['SSID']=SSID;
$_SESSION['rtStart'] = microtime(true);

//Faz o ROUTE do CONTROL/VIEW/ACTION no array ROUTE
if (isset($_GET['route'])) {
    $route = $_GET['route'];
    $route = explode('/', $route);
    $route = filter_var_array($route, FILTER_SANITIZE_URL);
} else {
    $route[0]='0';
}
$_SESSION['route']=$route;
if ($route[0] == 0) {
    $_SESSION['control']='main';
    $_SESSION['view']=false;
    $_SESSION['action']=false; 
} else {
    $_SESSION['control']=$route[0];
}
// se foi incluido um modulo de banco_de dados, cria a conexão
if ( function_exists(conectDb) ){
    $db = conectDb(); 
} else {
    $db = false;
}
?>

Com isso, nosso esqueleto está pronto, e funcional, preparando-se para iniciar a execução dos nossos controles e views de acordo com os dados passados pela URL de chamada. Nosso controle principal é o main_control.php e ele usa a view main_main_view.php como a view em caso de chamada sem nenhum parametro, e vamos falar dessa view, e do sistema de menus/estruturas de navegação na próxima aula, juntamente com o sistema de login.