Bonjour,

Je suis en train de suivre le tuto Gestion d'un espace membre en PHP j'arrive à la fin de la première heure la 54eme minutes pour être précis.

A ce stade nous créons la page login.php

On dois faire la page de connexion , mon problème surviens quand je recharge la page pour vérifier le mot de passe envoyé et le mot de passe hashé en base de donné. les infos sont bien affichées, mais j'obtiens aussi une erreur qui est la suivante :
Warning: session_start(): Cannot send session cache limiter - headers already sent (output started at /Users/Mushi/PHP_mySQL/Grafikart/inc/functions.php:4) in /Users/Mushi/PHP_mySQL/Grafikart/inc/header.php on line 4

Voici ma page login.php

if (!empty($_POST) && !empty($_POST['username']) && !empty($_POST['password'])) 
{
    require_once 'inc/db.php';
    require_once 'inc/functions.php';
    $req = $pdo->prepare('SELECT * FROM members WHERE username = :username OR email = :username');
    $req->execute(['username' =>$_POST['username']]);
    $user = $req->fetch();
    debug($_POST['password']);
    debug($user->password);
}
?>
<?php require 'inc/header.php'; ?>

<h1>Se connecter</h1>

<form action="" method="POST">

    <div class="form-group">
        <label for="">Pseudo ou email</label>
        <input type="text" name="username" class="form-control" >
    </div>

    <div class="form-group">
        <label for="">Mot de passe</label>
        <input type="password" name="password" class="form-control" >
    </div>

    <button type="submit" class="btn btn-primary">Se connecter</button>

</form>

<?php require 'inc/footer.php'; ?>````

et voici ma page header.php (Uniquement le debut puisque c'est de la que viens le problème)

<?php
if (session_status() == PHP_SESSION_NONE)
{
session_start();
}
?><!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1">
<!-- The above 3 meta tags must come first in the head; any other head content must come after these tags -->
<meta name="description" content="">
<meta name="author" content="">
<link rel="icon" href="../../favicon.ico">

<title>Mon espace membre 02</title>

<!-- Bootstrap core CSS -->
<link href="css/app.css" rel="stylesheet">

</head>


Dans la vidéo du tuto il n'y a pas ce problème. J'ai suprimé la partie précedent le <!DOCTYPE html> dans le header.php et quand je recharge la page je n'ai plus ce message d'erreur. Seulement je me dis que je ne devrais pas avoir à faire ça pour ne pas avoir l'erreur et je ne comprends pas d'ou elle viens .  J'aurais aimé avoir votre avis ou une piste qui me permettrais de regler ce problème.

Je m'excuse par avance ci mon message n'est pas bien formaté c'est la première fois que j'utilise le forum de Grafikart et le markdown que je ne connais pas du tout.

Mushi

9 réponses


Salut,

output started at /Users/Mushi/PHP_mySQL/Grafikart/inc/functions.php:4

Il y a quoi dans "...inc/functions.php" ?

Pour les balise "code" du markdown c'est : "3 fois le caractère backquote"
(3 backquotes pour "ouvrir" et, 3 backquotes pour "fermer", et entre les 2 tu mets du code)
backquote = ALTGR + 7

https://github.com/adam-p/markdown-here/wiki/Markdown-Cheatsheet

mushi
Auteur

Bonjour,

Dans functions.php j'ai le code suivant :

<?php
function debug($variable)
{
    echo '<pre>' .print_r($variable, true). '</pre>';
}

function str_random($lenght)
{
    $alphabet ="0123456789azertyuiopqsdfghjklmwxcvbnAZERTYUIOPQSDFGHJKLMWXCVBN";
    return substr(str_shuffle(str_repeat($alphabet, $lenght)), 0, $lenght);
}

function logged_only()
{
    if (session_status() == PHP_SESSION_NONE) 
    {
      session_start();
    }
    if (!isset($_SESSION['auth'])) 
    {
        $_SESSION['flash']['danger'] = "Vous n'avez pas le droit d'accéder à cette page !";
        header('location: login.php');
        exit();
    }
}

Ah,
je ne pensais pas qu'une balise <pre> empêcherait la SESSION de se lancer mais on dirait que c'est ça.

Au début on rentre dans le "if" :
if (!empty($_POST) && !empty($_POST['username']) && !empty($_POST['password']))

Dans le if, entre autres, on fait un "debug" :
debug($_POST['password']);

Le "debug" fait un echo d'une balise HTML.

On sort du "if",
et on inclu le "header"...
<?php require 'inc/header.php'; ?>

...qui essaie de lancer la SESSION :

if (session_status() == PHP_SESSION_NONE)
{
    session_start();
}

Mais comme on essaie de lancer la SESSION seulement APRES avoir affiché une balise HTML (la balise pre du debug),
on a l'erreur que tu as donné :
Warning: session_start(): Cannot send session cache limiter - headers already sent

Du coup,
enlève les 2 debug pour l'instant :

debug($_POST['password']);
debug($user->password);

ou si tu en as vraiment besoin,
essaie de mettre un "var_dump" à la place des "pre + printr".
Je ne sais pas si le "var_dump" va lui aussi empêcher la SESSION de se lancer ou pas.
Je sais que c'est moins facilement lisible mais bon...

Bonjour.
Tu devrais plutôt mettre un triple =, soit :

if (session_status() === PHP_SESSION_NONE) 

Salut Lartak,

bah ici ce n'est pas vraiment utile de vérifier le type.
La fonction et la constante viennent toutes les 2 de PHP, et ont été écrites pour aller ensemble.
On sait que le type correspondra.

A moins que je n'ai pas pensé à un truc ?
Pourquoi tu conseil le "triple =" ?

mushi
Auteur

Bonjour ,
SLK j'ai déjà enlever les debug mais cela na rien changé pour le moment. Je n'ai pas encore pu me remettre sur le code pour faire les autres modifs que tu ma sugerer je'esserais ça se soir.
Lartak, je tenterais aussi les "===" ce soir.
Merci pour vos réponse

j'ai tester comme ça et ça marche pas besoin de faire une fonction pour si peut !!

if(session_status() == PHP_SESSION_NONE){//on verifi et demarre les sessions
    session_start();   
}

Puis une fonction il faut l'appeler pour l'utiliser, moi je fait comme ça et toutes mes pages fonctionne en passant par l'index :

<?php
if(session_status() == PHP_SESSION_NONE){//on verifi et demarre les sessions
    session_start();   
}

define('ROOT', $_SERVER['DOCUMENT_ROOT']);
define('DS', DIRECTORY_SEPARATOR);

require_once 'lib'.DS.'cnxbdd.php';
require_once 'lib'.DS.'libs-includes.php';

$page = strtolower($_GET['page']);   

$themeForLayout = 'hardline';

if(isset($page) && !empty($page) && preg_match("/^[a-z0-9\-]+$/i",$page) && file_exists('modules'. DS . $page . '.php')){

    require 'modules'. DS .'func'. DS . $page.'.func.php'; //fonction de chaque pages

    ob_start();

    require 'modules'. DS . $page . '.php'; //inclusion des pages 

    $contentForLayout = ob_get_clean();

    require 'templates'. DS . $themeForLayout .'.php';

}else{
    redirect('home');
}

Voici ma page login si tu veut t'en inspiré avec protection par force brute si tu te trompe souvent de login tu est bloquer :

<?php
if(isset($_SESSION['auth'])){

    setFlash('<strong>Oh oh!</strong> ça ne va pas ! <strong> tu est déjà logger</strong>','Avertissement !','orange');
    redirect('account#flash');

}

if(!empty($_SESSION['login_time']) && $_SESSION['login_time'] < time()){
unset($_SESSION['login_fail']);
unset($_SESSION['login_time']);
}
if(!empty($_SESSION['login_fail']) && $_SESSION['login_fail'] >= 5){
$error = errors('Vous avez entré de mauvais identifiants 10 fois de suite il vous faut attendre '. date('H\hi',$_SESSION['login_time']) .' pour réessayer');
}

else if(isset($_POST['login'])){//si des valeurs sont poster
checkCsrf();//on vérifie tout de meme les failles csrf
$username = strip_tags(trim($_POST['username']));
$pass = trim($_POST['password']);
$req = $db->prepare('SELECT * FROM users WHERE (username = :username OR email = :username) AND activation >= 1 AND confirmed_at IS NOT NULL');
$req->execute(['username' => $username]);
$user = $req->fetch();
$current = isset($_GET['id']) && !empty($_GET['id']) ? WEBROOT . $_GET['page'] . '/' . intval($_GET['id']) : $_GET['page'] ;
if(empty($username)){

    setFlash('Le champs username est rester vide','Avertissement !','orange');
    redirect($current);

}if(empty($pass)){

    setFlash('Le champ password est rester vide','Avertissement !','orange');
    redirect($current);

}if(empty($error)){

    if($user->activation == 0){

        sleep(1);
        if(empty($_SESSION['login_fail'])){
            $_SESSION['login_fail'] = 1;
            $_SESSION['login_time'] = time()+ 60 * 10;
        }else{
            $_SESSION['login_fail']++;
        }
        setFlash('<strong>Oh oh!</strong> Formulaire incorect ! mauvais login <strong>ou votre compte n\'est pas actif</strong>','Avertissement !','orange');
        redirect($current.'#flash');

    }if(password_verify($_POST['password'], $user->password)){

        $db->prepare('UPDATE users SET lastconect = NOW() WHERE id = ?')->execute([$user->id]);

        $_SESSION['auth'] = $user;    

        if($_POST['remember']){
            $remember_token = str_random(500);
            $db->prepare('UPDATE users SET remember_token = ? WHERE id = ?')->execute([$remember_token, $user->id]);
            setcookie('remember', $user->id . '==' . $remember_token . sha1($user->id . 'ratonlaveurs' . $_SERVER['REMOTE_ADDR']), time() + 60 * 60 * 24 * 7);
        }
        setFlash('<strong>Salut !!</strong> vous êtes bien connecter <strong>bienvenue sur notre site</strong>','Success !');
        redirect('account#flash');

    }else{

        sleep(1);
        if(empty($_SESSION['login_fail'])){
            $_SESSION['login_fail'] = 1;
            $_SESSION['login_time'] = time()+ 60 * 10;
        }else{
            $_SESSION['login_fail']++;
        }
        setFlash('<strong>Oh oh!</strong> Formulaire incorect ! <strong>Identifiant non valide</strong>','Avertissement !','orange');
        redirect($current.'#flash');

    }
}

}

ça reste en chantier cela dit.

mushi
Auteur

Bonjour à tous et merci pour vos réponse dans l'état actuel presque tout fonctionne.

L'inscription

Pas de souci , lorsque je rentre les bonnes informations elles sont enregistrées et j'ai un message qui me dit que l'inscription c'est bien passé.

<?php
require_once 'inc/functions.php';
session_start();

if (!empty($_POST)) 
{
    $errors = array();

    require_once 'inc/db.php';

    if (empty($_POST['username']) || !preg_match('/^[a-zA-Z0-9_]+$/', $_POST['username'])) 
    {
        $errors['username'] = "Votre pseudo n'est pas valide";
    }
    else
    {
        $req = $pdo->prepare("SELECT id FROM members WHERE username= ?");
        $req->execute([$_POST['username']]);
        $user = $req->fetch();
        if($user)
        {
            $errors['usename'] = "Ce pseudo est déjà pris !";
        }
    }

    if (empty($_POST['email']) || !filter_var($_POST['email'], FILTER_VALIDATE_EMAIL)) 
    {
        $errors['email'] = "Votre email n'est pas valide";
    }
    else
    {
        $req = $pdo->prepare("SELECT id FROM members WHERE email= ?");
        $req->execute([$_POST['email']]);
        $user = $req->fetch();
        if($user)
        {
            $errors['email'] = "Cet mail est déjà utilisé pour un autre compte !";
        }
    }

    if (empty($_POST['password']) || $_POST['password'] != $_POST['password_confirm']) 
    {
        $errors['email'] = "Votre mot de passe n'est pas valide";
    }

    if (empty($errors)) 
    {
        $req = $pdo->prepare("INSERT INTO members SET username= ?, email= ?, password= ?, confirmation_token= ?");
        $password = password_hash($_POST['password'], PASSWORD_BCRYPT);
        $token = str_random(60);
        $req->execute([$_POST['username'], $_POST['email'], $password, $token]);
        $user_id = $pdo->lastInsertId();
        mail($_POST['email'], 'Confirmation de votre compte', " Afin de valider votre compte merci de cliquer sur ce lien\n\nlocalhost:8888/Grafikart/espace_membre_02/confirm.php?id=$user_id&token=$token");
        $_SESSION['flash']['success'] = 'Afin de valider votre compte un email de confirmation vous a été envoyé';
        header('location: login.php');
        exit();
    }
}
?>
<?php require 'inc/header.php'; ?>

<h1>S'inscrire</h1>

<?php if(!empty($errors)): ?> 
<div class="alert alert-danger">
    <p>Vous n'avez pas rempli le formulaire correctement</p>
    <ul>
        <?php foreach($errors as $error): ?>
        <li><?= $error; ?></li>
        <?php endforeach; ?>
    </ul>
</div>
<?php endif; ?>

<form action="" method="POST">

    <div class="form-group">
        <label for="">Pseudo</label>
        <input type="text" name="username" class="form-control" >
    </div>

    <div class="form-group">
        <label for="">Email</label>
        <input type="text" name="email" class="form-control" >
    </div>

    <div class="form-group">
        <label for="">Mot de passe</label>
        <input type="password" name="password" class="form-control" >
    </div>

    <div class="form-group">
        <label for="">Confirmez votre mot de passe</label>
        <input type="password" name="password_confirm" class="form-control" >
    </div>

    <button type="submit" class="btn btn-primary">M'inscrire</button>

</form>

<?php require 'inc/footer.php'; ?>

La validation

Elle se passe sans problème non plus, un message pour me dire que le compte est validé , un message si ne soumet le token une seconde fois .

<?php
$user_id = $_GET['id'];
$token = $_GET['token'];
require 'inc/db.php';
$req = $pdo->prepare('SELECT * FROM members WHERE id = ?');
$req->execute([$user_id]);
$user = $req->fetch();
session_start();

if($user && $user->confirmation_token == $token)
{
    $pdo->prepare('UPDATE members SET confirmation_token = NULL, confirmed_at = NOW() WHERE id = ?')->execute([$user_id]);
    $_SESSION['flash']['success'] = 'Votre compte a bien été validé';
    $_SESSION['auth'] = $user;
    header('location: account.php');
}
else
{
    $_SESSION['flash']['danger'] = "Ce token n'est plus valide";
    header('location: login.php');
}

La connexion

C'est la ou les choses se corsent un petit peu, si je rentre les bonnes informations il n'y a pas de souci et je tombe sur la page account.

En revanche la ou sa ne se passe pas comme sa devrait c'est si je rentre un un bon login et un mauvais mot de passe je reste sur la page de connexion mais je n'ais aucun message d'alerte.

Et si je rentre un mauvais login et le bon mot de passe je n'ai toujours pas de message d'alerte mais des jolies erreurs PHP.
la première :
Notice: Trying to get property of non-object in /Users/Mushi/PHP_mySQL/Grafikart/espace_membre_02/login.php on line 9

la seconde :
Warning: session_start(): Cannot send session cache limiter - headers already sent (output started at /Users/Mushi/PHP_mySQL/Grafikart/espace_membre_02/login.php:9) in /Users/Mushi/PHP_mySQL/Grafikart/espace_membre_02/inc/header.php on line 4

<?php
if (!empty($_POST) && !empty($_POST['username']) && !empty($_POST['password'])) 
{
    require_once 'inc/db.php';
    require_once 'inc/functions.php';
    $req = $pdo->prepare('SELECT * FROM members WHERE (username = :username OR email = :username) AND confirmed_at IS NOT NULL');
    $req->execute(['username' =>$_POST['username']]);
    $user = $req->fetch();
    if(password_verify($_POST['password'], $user->password))
    {
        session_start();
        $_SESSION['auth'] = $user;
        $_SESSION['flash']['success'] = 'Vous êtes maintenant connecté';
        header('location: account.php');
        exit();
    }
    else
    {
        $_SESSION['flash']['danger'] = 'Identifiant ou mot de passe incorrecte';
    }
}
?>
<?php require 'inc/header.php'; ?>

<h1>Se connecter</h1>

<form action="" method="POST">

    <div class="form-group">
        <label for="">Pseudo ou email</label>
        <input type="text" name="username" class="form-control" >
    </div>

    <div class="form-group">
        <label for="">Mot de passe</label>
        <input type="password" name="password" class="form-control" >
    </div>

    <button type="submit" class="btn btn-primary">Se connecter</button>

</form>

<?php require 'inc/footer.php'; ?>

"Et si je rentre un mauvais login et le bon mot de passe je n'ai toujours pas de message d'alerte mais des jolies erreurs PHP.
la première :
Notice: Trying to get property of non-object in /Users/Mushi/PHP_mySQL/Grafikart/espace_membre_02/login.php on line 9"

tu dois avoir ce message si tu entres un username qui n'existe pas dans ta base et c'est normal:
pas de username en base --> pas de résultat à ta requete de recherche et donc pas d'objet $user

Il faut que tu vérifies si ta recherche retourne un résultat.

PS: la deuxième erreur vient du fait qu'il y a eu l'affichage du message d'erreur avant le session_start()