Solucionado (ver solução)
Solucionado
(ver solução)
7
respostas

Problemas com Sessão em PHP - Integração com Java Script

Olá

Estou desenvolvendo um projeto pessoal usando os conhecimentos dos cursos realizados na Alura e deste curso sobre requisições assincronas.

Atualmente na parte do projeto que estou desenvolvendo estou buscando a aplicação dos conteúdos de requisições assíncronas com Java Script integrando com PHP que tenho já desenvolvido para tratar dos acessos ao banco de dados.

Estou enfrentando um problema que não consegui ainda encontrar algum material que me esclareça a dúvida.

Vou postar os códigos JS para caso alguém possa me auxiliar a entender o que está acontecendo com uma classe que uso para manipular os dados de sessão que utilizo.

Estou usando uma função assíncrona para enviar dados para uma classe php através de POST, que é um dos métodos que aprendemos no curso.

Esta classe PHP recebe os dados por POST para tratar, porém antes de realizar a transação no PHP quero validar se o usuário está logado e se é admin, então para estas validações no PHP tenho usado uma SESSION.

Acontece que ao enviar os dados por post na requisição assíncrona a sessão os métodos que uso para recuperar dados da sessão estão retornando dados vazios.

Meu objetivo é validar se o usuário está logado. Optei por validar no PHP pois posso no futuro precisar usar eta mesma classe para outra função e então garanto que sempre será validado, não sei se esta minha abordagem está correta.

Preciso de auxílio para entender melhor as requisições POST, pois estou lendo alguns conteúdos e já percebi que como é uma requisição assíncrona faz com que a sessão não seja lida e precisareia enviara os dados de credenciais na requisição e etc.

Se possível me auxiliarem a melhorar meu entendimento nestas funções pois como mencionei, inclusive em outros posts de dúvidas meus que estou com um projeto pessoal em andamento a cada curso que faço tenho melhorado o projeto aplicando os aprendizados.

Meu projeto usa o PHP para intregração com o banco de dados e estes dados tenho manipulado nas páginas usando o java script fazendo estas requisições para as classes PHP.

Os dados que envio por POST estão sendo traados no PHP, da sequinte maneira, sendo que o código será executado somente se o usuário da sessão estiver logado, então recupero os dados da sessão com uma classe que tenho que faz isso e que já funciona em outras partes do projeto, porém até então somente com manipulações PHP pois agora que estou integrando o Java Script.

            $json = file_get_contents('php://input');
            $data = json_decode($json, true);
            
            $destino = $data['destino'];
            $assunto = $data['assunto'];
            $mensagem = $data['mensagem'];

Desde já agradeço.

Segue o código da minha requisição:

async function enviaEmail(destino, assunto, mensagem){

try{
    const api = await fetch("https://viverespirita.com.br/artigo-compartilha", {
    method: "POST",
    credentials: 'include',
    headers: {
        "Content-type": "application/json"
    },
    body: JSON.stringify({
        destino: destino,
        assunto: assunto,
        mensagem: mensagem
    })
});


const apiConvertida = await api.json();

if (apiConvertida[0]){
    console.log(apiConvertida);
    window.alert("Artigo compartilhado com sucesso.");
}else{
    window.alert("Artigo não compartilhado.Verifique com o administrador.");
}

//return apiConvertida;

}catch (e) {
    console.log(`Erro na função JS enviaEmail: ${e}.`);
}

}

7 respostas

Olá, Ricardo, tudo bem?

Primeiramente, parabéns pelo seu projeto pessoal e pela dedicação em aplicar os conhecimentos adquiridos.

Pelo que entendi, você está usando uma função assíncrona em JavaScript para enviar dados para uma classe PHP por meio de uma requisição POST. No PHP, você precisa validar se o usuário está logado e se é um administrador, e para isso, está utilizando uma sessão. No entanto, ao enviar os dados via requisição assíncrona, os métodos que você usa para recuperar dados da sessão estão retornando valores vazios.

O problema que você está enfrentando é comum quando se trata de requisições assíncronas em JavaScript. Quando você faz uma requisição assíncrona usando fetch com credentials: 'include', os dados da sessão não são enviados automaticamente pelo navegador. Isso acontece porque as requisições assíncronas não compartilham as mesmas informações de cookies da sessão, o que faz com que a autenticação no PHP seja perdida durante a requisição.

Para resolver esse problema, você precisa garantir que os dados da sessão sejam enviados junto com a requisição assíncrona. Para fazer isso, você pode adicionar um cabeçalho personalizado à sua requisição contendo os dados da sessão necessários para a validação no PHP.

Em seu código JavaScript, você pode adicionar o cabeçalho personalizado da seguinte forma:

async function enviaEmail(destino, assunto, mensagem) {
  try {
    const api = await fetch("https://viverespirita.com.br/artigo-compartilha", {
      method: "POST",
      credentials: 'include',
      headers: {
        "Content-type": "application/json",
        "X-Requested-With": "XMLHttpRequest", // Cabeçalho personalizado com o valor "XMLHttpRequest"
      },
      body: JSON.stringify({
        destino: destino,
        assunto: assunto,
        mensagem: mensagem
      })
    });

    // Resto do código...
  } catch (e) {
    console.log(`Erro na função JS enviaEmail: ${e}.`);
  }
}

No PHP, é necessário verificar se o cabeçalho personalizado "X-Requested-With" está presente na requisição e, em caso afirmativo, realizar o tratamento adequado para validar a sessão. Você pode fazer isso da seguinte maneira:

if (isset($_SERVER['HTTP_X_REQUESTED_WITH']) && $_SERVER['HTTP_X_REQUESTED_WITH'] === 'XMLHttpRequest') {
  session_start(); // Iniciar a sessão apenas se a requisição for assíncrona

  // Resto do código de validação da sessão...
}

Dessa forma, você garante que a sessão será inicializada apenas quando a requisição for assíncrona, permitindo que os métodos para recuperar os dados da sessão funcionem corretamente.

Além disso, é importante ressaltar que sua abordagem de validar a sessão no PHP é correta. Ao fazer a validação no servidor, você garante a segurança da sua aplicação, pois as verificações de acesso e permissões são feitas no backend, onde não podem ser facilmente manipuladas pelo usuário.

Para aprimorar ainda mais seu entendimento sobre requisições POST assíncronas e integração entre JavaScript e PHP, recomendo que estude conceitos de RESTful APIs, AJAX e como o JavaScript se comunica com o servidor de forma assíncrona.

Espero que essas informações tenham sido úteis para solucionar o problema que você estava enfrentando. Infelizmente somente o que posso fazer é lhe auxiliar com dicas, como o projeto é pessoal eu não tenho como ir mais afundo, mas se tiver mais dúvidas ou precisar de mais auxílio, não hesite em perguntar. Desejo-lhe sucesso em seu projeto!

Espero que tenha te ajudado, abraços e bons estudos!

Renan, fico muito grato com tua ajuda, pois é com o auxílio que estou tendo que estou conseguindo avançar com meus conhecimentos, Vou colar meus códigos aqui para que você consiga analisar melhor e me auxiliar a entender o que ainda pode estar dando errado, pois mesmo com as alterações que você mencionou não está dando certo.

async function enviaEmail(destino, assunto, mensagem){
    try{
        const api = await fetch("https://viverespirita.com.br/artigo-compartilha", {
        method: "POST",
        credentials: 'include',
        headers: {
            "Content-type": "application/json",
            "X-Requested-With": "XMLHttpRequest", // Cabeçalho personalizado com o valor "XMLHttpRequest"
        },
        body: JSON.stringify({
            destino: destino,
            assunto: assunto,
            mensagem: mensagem
        })
    });
    
    const apiConvertida = await api.json();
    if (apiConvertida[0]){
        console.log(apiConvertida);
        window.alert("Artigo compartilhado com sucesso.");
    }else{
        window.alert("Artigo não compartilhado.Verifique com o administrador.");
    }

    }catch (e) {
        console.log(`Erro na função JS enviaEmail: ${e}.`);
    }

}

Código PHP

public function processaRequisicao(): void {

    $msg = new Mensagens(); 
    if (isset($_SERVER['HTTP_X_REQUESTED_WITH']) && $_SERVER['HTTP_X_REQUESTED_WITH'] === 'XMLHttpRequest'){
        session_start(); // Iniciar a sessão apenas se a requisição for assíncrona
        $sessaoController = new SessaoController();
        error_log('Testando controller-artigo-compartilha-email...'.$sessaoController->recuperaUserSessao());
        echo $sessaoController->recuperaUserSessao();
    }
    

No ponto acima quando eu instacio a SessaoController já deveria conseguir pegar os dados já gravados previamente na sessão no momento do login, com base neste dado de usuário logado eu continuo o código manipulando os dados se o usuário for admin e estiver logado, porém o UserSessao está vindo vazio.

... Resto do código...

Uma informação sobre minha classe de sessão.

Quando o usuário se loga no sistema eu faço a manipulação da sessão, então ao se logar eu instancio a classe SessaoController e nela eu definos os dados do usuário que está se logando, Trecho do código no controller de login: $sessaoController->defineUserSessao($usuario->recuperaUsuario()); $sessaoController->defineNomeUserSessao($usuario->recuperaNome()); $sessaoController->defineFotoUserSessao($usuario->recuperaFoto()); $sessaoController->defineDadosSessao();

reproduzo abaixo minha classe de controller de sessão,

class SessaoController
{
private string $user;
private string $nome;
private string $foto;

public function __construct()
{
    
    if (session_status() === PHP_SESSION_NONE) {
        session_start();
        //Inicializa as variáveis como vazias.
        $this->nome = '';
        $this->user='';
        $this->foto='';
    }
}


public function defineUserSessao(string $user): void
{   
    $this->user=$user;
}

public function defineNomeUserSessao(string $nome): void
{   
    $this->nome=$nome;

}

public function defineFotoUserSessao(string $foto): void
{   
    $this->foto=$foto;   

}

public function defineDadosSessao():void
{        
    $_SESSION['user']=$this->user;
    $_SESSION['nome']=$this->nome;
    $_SESSION['foto']=$this->foto;

}

public function recuperaUserSessao()
{
    
    if (!empty($_SESSION['user'])){
        return $_SESSION['user'];
    }
        return '';
    
}
solução!

Olá, Ricardo! Tudo bem por aí?

Após uma análise do seu código e considerando que você já seguiu as dicas mencionadas anteriormente, ainda podemos explorar algumas abordagens para solucionar o problema da sessão vazia na requisição assíncrona.

Primeiramente, verifique se a função session_start() está sendo chamada corretamente em todas as páginas que precisam acessar os dados da sessão. É importante que ela seja invocada antes de qualquer outra operação relacionada à sessão. Além disso, confirme se não há chamadas duplicadas para session_start() em seu código, pois isso pode gerar conflitos.

Outro ponto importante é garantir a consistência entre o nome da sessão definido na classe SessaoController e o nome utilizado para recuperar os dados da sessão no PHP. Verifique se eles estão exatamente iguais em ambas as situações.

Além disso, certifique-se de que os dados da sessão estão sendo armazenados corretamente durante o processo de login. Verifique se a função defineDadosSessao() é chamada após definir os dados do usuário no momento do login.

Para aprimorar ainda mais seus conhecimentos, sugiro explorar recursos adicionais para depurar e compreender o comportamento do código. Utilize ferramentas de desenvolvedor do navegador, como o console do Google Chrome, para verificar as requisições feitas pelo JavaScript, seus cabeçalhos e respostas, o que pode ajudá-lo a entender melhor a interação entre o Front-end (JavaScript) e o Back-end(PHP).

Outra ideia interessante é fazer uso de logs no PHP para registrar informações relevantes sobre o fluxo do código e depurar possíveis problemas. A função error_log() pode ser utilizada para imprimir informações úteis, como variáveis e mensagens de erro, no arquivo de log do servidor.

Lembre-se de que o processo de aprendizado envolve desafios, e enfrentar esses desafios é o que nos torna mais experientes e habilidosos. Às vezes, encontrar a solução para um problema pode levar tempo e esforço, mas cada obstáculo superado é uma oportunidade de crescimento.

Continue buscando recursos, tutoriais e documentações que possam ajudá-lo a compreender mais sobre requisições assíncronas, comunicação entre JavaScript e PHP e manipulação de sessões. A prática constante é a chave para aprimorar suas habilidades.

Esperamos que você consiga resolver o problema com a sessão e que isso lhe motive a enfrentar novos desafios em seu projeto. Lembre-se sempre de buscar o equilíbrio entre a pesquisa autônoma e o auxílio quando necessário. Estamos aqui para ajudá-lo no que for possível, mas também é valioso aprender a encontrar soluções por conta própria.

Para informações mais detalhadas e conceitos aprofundados, você pode consultar a documentação oficial do PHP sobre sessões aqui, e para requisições assíncronas em JavaScript, pode explorar mais sobre a API fetch() aqui e o uso do objeto XMLHttpRequest aqui.

Se surgirem novas dúvidas ou precisar de ajuda em algum problema específico, relacionado ao curso ou seu projeto, não hesite em perguntar. Estou torcendo pelo seu sucesso e crescimento contínuo em sua jornada de desenvolvimento!

Abraços e bons estudos!

Olá Renan

Hoje consegui depurar melhor o código implementando mais logs usando error_log no PHP e pude ver o status e dados das variáveis de sessão desde o login até o ponto que estou tendo problema.

Constatei que até o ponto antes de eu buscar o compartilhamento com a função assíncrona a sessão possui um ID. Quando executo o Java Script verifico no navegador pelo log que o ID da sessão muda, então é por isso que ao tentar recuperar os dados do usuário da sessão já não consigo mais pois quando a classe que compartilha o artigo é executada está dano start em uma nova sessão com o ID diferente igual aos dados da sessão que constato nos cookies do navegador.

Agora com base nesta constatação irei aprofundar os estudos nos links que me passou para entender melhor o que está ocorrendo e como corrigir.

Com certeza é um bom desafio ir construindo soluções para estes problemas, mas é muito gratificante, pois com o andamento dos cursos que tenho feito eu estou conseguindo implementar gradativamente minhas ideias e melhorar meu site aos poucos.

Quando eu conseguir solucionar eu te passo como resolvi para você me dar um feedback se é uma boa solução. Para mim é importante saber se estou no caminho pois não trabalho na área de desenvolvimento, porém quero seguir com os cursos e com meu primeiro projeto usando sempre boas práticas e soluções adequadas.

Muito obrigado.

Olá Ricardo, tudo ok contigo?

Fico feliz em saber que você conseguiu realizar uma depuração mais detalhada no código e identificar o problema com a sessão.

Agora que você tem uma melhor compreensão do que está acontecendo, o próximo passo é buscar soluções para garantir a consistência da sessão durante as requisições assíncronas. Os links que passei sobre sessões em PHP e requisições assíncronas em JavaScript podem ser bastante úteis para aprofundar seus conhecimentos e encontrar formas adequadas de lidar com esse problema.

Ao resolver esse desafio e implementar as correções, estarei ansioso para saber como você o fez.

Desejo-lhe sucesso contínuo em sua jornada de desenvolvimento e em seu projeto pessoal. Você está no caminho certo e estou certo de que suas habilidades e conhecimentos só irão melhorar a cada passo dado.

Grande abraço e bons estudos!

Olá Renan!

Os materiais que me passou foram de grande ajuda pois estou me aprofundando nos conceitos e entendendo melhor o funcionamento das sessãoes e também das requisições com JS. Continuarei estudando para aprofundar e entender cada vez mais.

Ao depurar o código e ir entendo o fluxo das requisições constatei a mudança do id da sessão e com as leituras entendi que o sistema por segurança só deixa acessíveis os dados da sessão para o mesmo domínio.

Ao realizar o fetch pra o POST eu não estava colocando o www na frente do endereço que estava chamando, porém ao acessar a página estou usando o www. Após eu detalhar bem os dados das ferramentas de desenvolvedor do navegador consegui perceber isso e ajustei e funcionou.

O legal de eu ter apanhado um pouco para achar o erro é que consegui aprofundar um pouco meu olhar para estes detalhes.

Agora vou seguir desenvolvendo meu projeto e agora partirei para outro curso da minha trilha de aprendizagem.

Se eu tiver dúvidas vou pedir ajuda.

Fico muito grato pelo apio.

Grande abraço.

Olá Ricardo! Eaí?

Fico muito contente em saber que os materiais que passei foram úteis e que você está se aprofundando nos conceitos das sessões e requisições assíncronas em JavaScript. É ótimo ver o seu empenho em entender o funcionamento e solucionar os desafios que surgem ao longo do desenvolvimento do seu projeto pessoal.

Parabéns também por identificar a mudança que você deveria realizar. A persistência e a dedicação em aprimorar seu olhar para detalhes são qualidades importantes de um desenvolvedor, e tenho certeza de que essas habilidades serão valiosas em seus futuros projetos.

A cada desafio enfrentado e superado, você está ganhando mais experiência e conhecimento, o que é essencial para seguir avançando em sua trilha de aprendizagem. Continue aplicando as boas práticas e soluções adequadas em seus projetos, pois essa abordagem o ajudará a construir sistemas mais robustos e seguros.

Fico à disposição para ajudá-lo caso surjam novas dúvidas ou se precisar de auxílio em algum outro ponto do seu projeto ou estudo. Lembre-se de que a comunidade de desenvolvedores está aqui para se apoiar mutuamente e aprender juntos.

Continue investindo em seu desenvolvimento e aproveite ao máximo os cursos em sua jornada de aprendizado. Estou certo de que você alcançará excelentes resultados em seu projeto e em sua trajetória na área de desenvolvimento.

Grande abraço e sucesso em tudo o que você fizer! Estarei torcendo por suas conquistas.

Abraços e bons estudos.