So I'm kinda new with php and I work on a project where I must use a Model View Controller structure. I've got an issue on my article page where people can post comments. When they post it, the script must reload the page with the newly posted comment but I've got this "Headers already sent" error popping up. I read pretty much all the existing topics on this issue (edit : including "how to fix headers already sent errors"), I tried a lot of things including setting "output_buffering = on" on my php.ini, my code is encoded on UTF-8 without BOM...
I found a solution to by-pass it, but I would have liked to know why I've got this issue and how to correct it a better way. The solution I found was to put a ob_start() and ob_get_contents() wrapping my template.
Here's my code for the article page :
<?php ob_start();
$title = htmlspecialchars($article['title']);
?>
<!-- Display de l'article -->
<article class="articleBox mx-auto border border-white m-3">
<h2 class="display-3 mb-4"><?=htmlspecialchars(ucfirst($article['title']));?></h2>
<div class="text-justify">
<p><?=nl2br(htmlspecialchars($article['content']));?></p>
<p class="text-right mt-5">Publié le <?=htmlspecialchars($article['date_posted']);?>, par
<?=htmlspecialchars($article['author']);?></p>
<?php if ($article['date_updated']) {
echo '<p class="text-right">Mis à jour le ' . htmlspecialchars($article['date_updated']) . '</p>';
}?>
</div>
</article>
<hr>
<!-- Display des commentaires -->
<section id="comments" class="d-flex flex-lg-row flex-column justify-content-around m-5">
<div id="getComments" class="col-12 col-lg-6">
<h3 class="h2">Commentaires</h3>
<?php
if ($comments->rowCount() > 0) {
while ($comment = $comments->fetch()) {?>
<div class="commentBox m-4">
<div>
<p><strong><?=htmlspecialchars($comment['author'])?></strong>, le
<?=htmlspecialchars($comment['date_posted'])?> : </p>
</div>
<p><?=nl2br(htmlspecialchars($comment['comment']))?></p>
<form method="POST" action="signalComment.php?id=<?=$comment['id']?>&postId=<?=$article['id']?>">
<?php if ($comment['signaled'] === 'yes') {
echo '<p class="signaled small text-left text-lg-right">Ce commentaire a été signalé.</p>'; }
else if($comment['signaled'] === 'ok') {
echo '<p class="signaled small text-left text-lg-right">Ce commentaire a été validé.</p>';}
else { echo '<input class="signalButton" type="submit" value="Signaler">';}?>
</form>
</div>
<?php
}
} else {?>
<h4 class="h3">Aucun commentaire</h4>
<?php
} ?>
</div>
<!-- Poster un commentaire -->
<div id="postComment" class="col-12 col-lg-6 mt-5 mt-lg-0">
<form class="box" method="POST" action="article.php?action=addComment&id=<?=$article['id']?>">
<h3 class="h2">Laisser un commentaire</h3>
<p class="text-left"><input maxlength="15" class="input mt-3" type="text" name="author" id="author"
placeholder="votre nom" required></p>
<textarea class="textarea m-4" name="comment" id="comment" cols="40" rows="5"
placeholder="votre commentaire" required></textarea><br>
<p><input type="submit" value="Envoyer"></p>
</form>
</div>
</section>
<?php
$content = ob_get_clean();
require 'template.php';
My code for the template (with the ob_start and ob_get_contents) :
<?php ob_start();?>
<!DOCTYPE html>
<html lang="fr">
<head>
<title>Jean Forteroche - <?=$title?></title>
<link rel="icon" type="image/png" href="public/images/logoJF.png">
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0, shrink-to-fit = no">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<!-- CSS Animate -->
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/animate.css/3.7.2/animate.min.css">
<!-- CSS Bootstrap -->
<link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.4.1/css/bootstrap.min.css"
integrity="sha384-Vkoo8x4CGsO3+Hhxv8T/Q5PaXtkKtu6ug5TOeNV6gBiFeWPGFN9MuhOf23Q9Ifjh" crossorigin="anonymous">
<!-- CSS -->
<link rel="stylesheet" href="public/css/style.css">
<!-- GOOGLE FONTS -->
<link href="https://fonts.googleapis.com/css?family=Dancing+Script&display=swap" rel="stylesheet">
</head>
<body>
<header>
<?php include 'header.php';?>
</header>
<main class="text-center mb-5">
<?=$content;?>
</main>
<footer>
<?php include 'footer.php';?>
</footer>
<!-- JS Bootstrap -->
<script src="//code.jquery.com/jquery-1.12.0.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/popper.js@1.16.0/dist/umd/popper.min.js"
integrity="sha384-Q6E9RHvbIyZFJoft+2mJbHaEWldlvI9IOYy5n3zV9zzTtmI3UksdQRVvoxMfooAo" crossorigin="anonymous">
</script>
<script src="https://stackpath.bootstrapcdn.com/bootstrap/4.4.1/js/bootstrap.min.js"
integrity="sha384-wfSDF2E50Y2D1uUdj0O3uMBJnjuUD4Ih7YwaYd1iqfktj0Uod8GCExl3Og8ifwB6" crossorigin="anonymous">
</script>
</body>
</html>
<?php ob_get_contents();
My function on my frontend controller :
public function addComment($postId, $author, $comment)
{
try {
if (isset($_POST['author']) && !empty($_POST['author']) && isset($_POST['comment']) && !empty($_POST['comment']))
{
$commentManager = new CommentManager;
$input = $commentManager->postComment($postId, $author, $comment);
header('Location: article.php?id='.$postId.'#comments');
}
else
throw new Exception('emptyInputs');
} catch(Exception $e) {
$this->error($e);
}
}
And here is the message error, saying the issue comes from the line 24, where I call my variable $content referring to my article page. When I try putting all my html on the same page, it says the error comes from the line where i call my variable $article['content']
Warning
: Cannot modify header information - headers already sent by (output started at /opt/lampp/htdocs/tests/projet4/view/frontend/template.php:24) in
/opt/lampp/htdocs/tests/projet4/controller/frontend/frontend.php
on line
123
Thanks for your help !