Jump to content

F***ing Header errors


3raser

Recommended Posts

I'm sorry for the absurd title, but I'm very ticked off right now. I spent the last few weeks rewriting my software. All development took place on localhost which doesn't seem to report header errors and works just fine. But I will now have to, after moving the stuff to a live version, change ALL of my work.

 

But can someone PLEASE tell me there is an easier way than changing all of my work. This is one example. As you can see, after successfully creating the reply - it attempts to redirect the user but of course a header error is outputted instead.

 

<?php
require('../structure/base.php');
require('../includes/config.php');
require('../structure/database.php');
require('../structure/forum.php');
require('../structure/forum.thread.php');
require('../structure/user.php');

$database = new database($db_host, $db_name, $db_user, $db_password);
$base = new base($database);
$user = new user($database);
$forum = new forum($database);
$thread_obj = new thread($database);

//make sure the user is logged in and the required data is set
if(!$user->isLoggedIn() || !ctype_digit($_REQUEST['forum']) || !ctype_digit($_REQUEST['id'])) $base->redirect('index.php');

//set some variables that are used a lot throughout the page
$username = $user->getUsername($_COOKIE['user'], 2);
$rank = $user->getRank($username);
$f = $_REQUEST['forum'];
$thread = $_REQUEST['id'];

//make sure they are posting in a forum where they have permission
if($user->checkMute($username) || !$thread_obj->canView($thread, $username, $rank) || !$thread_obj->canReply($thread, $rank)) $base->redirect('index.php');

//floodlimit time
$flood_limit = $database->processQuery("SELECT `floodlimit` FROM `config` LIMIT 1", array(), true);

//get the user's last post (time)
$last_post = $database->processQuery("SELECT `lastpost` FROM `users` WHERE `username` = ? LIMIT 1", array($username), true);
?>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html xmlns:IE>
<head>
<meta http-equiv="Expires" content="0">
<meta http-equiv="Pragma" content="no-cache">
<meta http-equiv="Cache-Control" content="no-cache">
<meta name="MSSmartTagsPreventParsing" content="TRUE">
<title><?php echo $data['wb_title']; ?></title>
<link href="../css/basic-3.css" rel="stylesheet" type="text/css" media="all" />
<link href="../css/forum-3.css" rel="stylesheet" type="text/css" media="all" />
<link href="../css/forummsg-1.css" rel="stylesheet" type="text/css" media="all" />
<!--[if IE 8]>
<link rel="stylesheet" type="text/css" href="../css/forummsg-ie-1.css" />
<![endif]-->
<script src="../js/v_thread_1.js"></script>
<script src="../js/v_thread_2.js"></script>
<?php include('../includes/google_analytics.html'); ?>
</head>
<body>
<div id="body">
	<?php $forum->getNavBar($username, $rank); ?>
                <br /><br />

	<div style="text-align: center; background: none;">
		<div id="infopane">
			<div class="about">

				<ul class="flat">
					<li><a href="viewthread.php?forum=<?php echo $f; ?>&id=<?php echo $thread; ?>">Return to thread</a></li>
				</ul>

			</div>
		</div>
                        <?php
                            //make sure the user doesn't have an existing mute
                        
                            if(isset($_POST['message']))
                            {
                                //if they clicked cancel instead of "reply"
                                if(isset($_POST['cancel'])) $base->redirect('viewthread.php?forum='. $f.'&id='. $thread);
                                
                                //make sure the title and message meet the standards
                                if(strlen($_POST['message']) > 2000 && $rank < 3)
                                {
                                    echo '<div class="frame e">Your post can\'t be larger than 2000 characters.</div>';
                                }
                                elseif((time()-$last_post[0]['lastpost']) < $flood_limit[0]['floodlimit'] && $rank < 4)
                                {
                                    echo '<div class="frame e">You\'re attempting to post too soon.</div>';
                                }
                                else
                                {
                                    //auto-hiding?
                                    $data = $database->processQuery("SELECT `autohiding` FROM `threads` WHERE `id` = ?", array($thread), true);
                                    $status = ($data[0]['autohiding'] == 1) ? 1 : 0;
                                    
                                    //insert post
                                    $database->processQuery("INSERT INTO `posts` VALUES (null, ?, ?, ?, NOW(), ?, '', ?, ?)", array($username, nl2br($_POST['message']), $thread, $status, $_SERVER['REMOTE_ADDR'], time()), false);
                                    
                                    $creation_id = $database->getInsertId();
                                    
                                    //update thread
                                    $database->processQuery("UPDATE `threads` SET `lastposter` = ?, `lastpost` = NOW() WHERE `id` = ?", array($username, $thread), false);
                                    
                                    //update their last post field
                                    $database->processQuery("UPDATE `users` SET `lastpost` = ?", array(time()), false);
                                    
                                    //send them to the thread they posted on
                                    $base->redirect('viewthread.php?forum='. $f .'&id='. $thread.'&goto='. $creation_id);
                                }
                            }
                            else
                            {
                                $chars = ($rank > 2) ? $chars = null : $chars = 2000; 
                                
                                if(isset($_GET['quote']) && isset($_GET['qt']) && $rank > 3)
                                {
                                    $quote = ($_GET['qt'] == 1) ? $database->processQuery("SELECT `content`,`username` FROM `posts` WHERE `id` = ?", array($_GET['quote']), true) : $database->processQuery("SELECT `content`,`username` FROM `threads` WHERE `id` = ?", array($_GET['quote']), true);
                                    
                                    $text = $base->remBr('[quote='. $quote[0]['username'] .']'. $quote[0]['content'] .'[/quote]');
                                }
                                ?>
                    
                                <div id="nocontrols" class="phold"></div>
                                <div id="command">
                                <form method="post" action="reply.php">
                                <input type="hidden" name="id" value="<?php echo $thread; ?>">
                                <input type="hidden" name="forum" value="<?php echo $f; ?>">
                                <table>
                                <tr>
                                        <td class="commandtwo" colspan="2">You have <span id="charlimit_count_b">30</span> characters <span id="charlimit_info_b" style="display: none">remaining</span> for your title.</td>
                                </tr>
                                <tr>
                                        <td class="commandtwo" colspan="2">
                                        <textarea id="charlimit_text_a" name="message" rows="20" cols="60"><?php echo $text; ?></textarea><br />
                                        You have <span id="charlimit_count_a"><?php echo $chars; ?></span> characters <span id="charlimit_info_a" style="display: none">remaining</span> for your message.</td>
                                </tr>
                                <tr>
                                <td class="commandtwo" colspan="2"><br />
                                        <input type="submit" name="add" value="Add reply" />    
                                        <!--<input type="submit" name="preview" value="Preview" />    -->
                                        <input type="submit" name="cancel" value="Cancel" />    
                                </td>
                                </tr>
                                </table>
                                </form>
                                </div>
                                
                                
		<div id="smileylegend">
			<span class="title">Smileys: </span><br>
			<span id="smilytxt" style="display: hidden;">Click to add a smiley to your message (will overwrite selected text).</span><br />     
			<span onclick="addsmiley('')"><IMG class=sm0 alt="" title="" src="../img/forum/smileys/smile.gif"> </span>     
			<span onclick="addsmiley('')"><IMG class=sm1 alt="" title="" src="../img/forum/smileys/wink.gif"> </span>     
			<span onclick="addsmiley('')"><IMG class=sm2 alt="" title="" src="../img/forum/smileys/tongue.gif"> </span>     
			<span onclick="addsmiley('')"><IMG class=sm3 alt="" title="" src="../img/forum/smileys/sad.gif"> </span>     
			<span onclick="addsmiley(':|')"><IMG class=sm4 alt=":|" title=":|" src="../img/forum/smileys/nosmile.gif"> :|</span>     
			<span onclick="addsmiley('O_o')"><IMG class=sm5 alt="O_o" title="O_o" src="../img/forum/smileys/o.O.gif"> O_o</span>     
			<span onclick="addsmiley('')"><IMG class=sm6 alt="" title="" src="../img/forum/smileys/bigsmile.gif"> </span>     
			<span onclick="addsmiley('^^')"><IMG class=sm7 alt="^^" title="^^" src="../img/forum/smileys/^^.gif"> ^^</span>     
			<span onclick="addsmiley('')"><IMG class=sm8 alt="" title="" src="../img/forum/smileys/shocked.gif"> </span>     
			<span onclick="addsmiley(':@')"><IMG class=sm9 alt=":@" title=":@" src="../img/forum/smileys/angry.gif"> :@</span>     
		</div>
                                <?php
                            }
                            ?>
		<br />
			<div class="tandc"><?php echo $data['wb_foot']; ?></div>
	</div>

</div>
</body>

 

Please tell me there is a way around this besides moving all the code to the top and making the file sloppy.

Link to comment
Share on other sites

I haven't looked at your code in depth, but is there any feasible way to get this:

 

<?php
                            //make sure the user doesn't have an existing mute
                        
                            if(isset($_POST['message']))
                            {
                                //if they clicked cancel instead of "reply"
                                if(isset($_POST['cancel'])) $base->redirect('viewthread.php?forum='. $f.'&id='. $thread);
                                
                                //make sure the title and message meet the standards
                                if(strlen($_POST['message']) > 2000 && $rank < 3)
                                {
                                    echo '<div class="frame e">Your post can\'t be larger than 2000 characters.</div>';
                                }
                                elseif((time()-$last_post[0]['lastpost']) < $flood_limit[0]['floodlimit'] && $rank < 4)
                                {
                                    echo '<div class="frame e">You\'re attempting to post too soon.</div>';
                                }
                                else
                                {
                                    //auto-hiding?
                                    $data = $database->processQuery("SELECT `autohiding` FROM `threads` WHERE `id` = ?", array($thread), true);
                                    $status = ($data[0]['autohiding'] == 1) ? 1 : 0;
                                    
                                    //insert post
                                    $database->processQuery("INSERT INTO `posts` VALUES (null, ?, ?, ?, NOW(), ?, '', ?, ?)", array($username, nl2br($_POST['message']), $thread, $status, $_SERVER['REMOTE_ADDR'], time()), false);
                                    
                                    $creation_id = $database->getInsertId();
                                    
                                    //update thread
                                    $database->processQuery("UPDATE `threads` SET `lastposter` = ?, `lastpost` = NOW() WHERE `id` = ?", array($username, $thread), false);
                                    
                                    //update their last post field
                                    $database->processQuery("UPDATE `users` SET `lastpost` = ?", array(time()), false);
                                    
                                    //send them to the thread they posted on
                                    $base->redirect('viewthread.php?forum='. $f .'&id='. $thread.'&goto='. $creation_id);
                                }
                            }
                            else
                            {
                                $chars = ($rank > 2) ? $chars = null : $chars = 2000; 
                                
                                if(isset($_GET['quote']) && isset($_GET['qt']) && $rank > 3)
                                {
                                    $quote = ($_GET['qt'] == 1) ? $database->processQuery("SELECT `content`,`username` FROM `posts` WHERE `id` = ?", array($_GET['quote']), true) : $database->processQuery("SELECT `content`,`username` FROM `threads` WHERE `id` = ?", array($_GET['quote']), true);
                                    
                                    $text = $base->remBr('[quote='. $quote[0]['username'] .']'. $quote[0]['content'] .'[/quote]');
                                }
                                ?>

 

Above the HTML code, set any echos to a variable instead of echoing them out right away, then place an echo into the current location of that code. Basically treating the variable as a vehicle to transport the results of all that PHP to the correct location after it's generated.

Link to comment
Share on other sites

Assuming this:

 

$base->redirect('viewthread.php?forum='. $f .'&id='. $thread.'&goto='. $creation_id);

 

sends a location header, it makes absolutely no sense to have it placed after output has been sent to the browser.

Link to comment
Share on other sites

Simple fix:

 

<?php
require('../structure/base.php');
require('../includes/config.php');
require('../structure/database.php');
require('../structure/forum.php');
require('../structure/forum.thread.php');
require('../structure/user.php');

// Begin an output buffer
ob_start();

$database = new database($db_host, $db_name, $db_user, $db_password);

 

Then at the end:

 

</body>
<?php
// Flush the output buffer
ob_end_flush();
?>

Link to comment
Share on other sites

Using output buffering because your redirects are designed wrong will only slow down the perceived performance of your website.

 

Redirects and any other header() calls must be the first thing your script does.  You cannot echo anything, even HTML tags, before a header redirect.

 

 

Link to comment
Share on other sites

^hack

In the way I proposed it, maybe.  I say "maybe" because given his "flat" code style, there's definitely a better solution than what I proposed.  However, output buffering in general is not a hack.  Many leading templating systems use it.

 

Among other things, output buffering:

  • allows pre-render and post-render functionality to write HTTP headers
  • allows output to be compressed, cached, or otherwise manipulated in php
  • provides a manner of asynchronous output that doesn't require writing to a variable (and thus enables more intuitive templating).

 

While not the best solution to his problem, it's definitely the simplest.  It also opens up a new chapter of knowledge for him to explore.

Link to comment
Share on other sites

Hmmm, I have been converting most of my code above the HTML and echoing out results with a variable. But it makes the code so much uglier.

 

As you can see, with the original code I posted - it now looks 10x uglier.

 

<?php
require('../structure/base.php');
require('../includes/config.php');
require('../structure/database.php');
require('../structure/forum.php');
require('../structure/forum.thread.php');
require('../structure/user.php');

$database = new database($db_host, $db_name, $db_user, $db_password);
$base = new base($database);
$user = new user($database);
$forum = new forum($database);
$thread_obj = new thread($database);

//make sure the user is logged in and the required data is set
if(!$user->isLoggedIn() || !ctype_digit($_REQUEST['forum']) || !ctype_digit($_REQUEST['id'])) $base->redirect('index.php');

//set some variables that are used a lot throughout the page
$username = $user->getUsername($_COOKIE['user'], 2);
$rank = $user->getRank($username);
$f = $_REQUEST['forum'];
$thread = $_REQUEST['id'];

//make sure they are posting in a forum where they have permission
if($user->checkMute($username) || !$thread_obj->canView($thread, $username, $rank) || !$thread_obj->canReply($thread, $rank)) $base->redirect('index.php');

//floodlimit time
$flood_limit = $database->processQuery("SELECT `floodlimit` FROM `config` LIMIT 1", array(), true);

//get the user's last post (time)
$last_post = $database->processQuery("SELECT `lastpost` FROM `users` WHERE `username` = ? LIMIT 1", array($username), true);

//make sure the user doesn't have an existing mute
if(isset($_POST['message']))
{
//if they clicked cancel instead of "reply"
if(isset($_POST['cancel'])) $base->redirect('viewthread.php?forum='. $f.'&id='. $thread);

//make sure the title and message meet the standards
if(strlen($_POST['message']) > 2000 && $rank < 3)
{
	$content = '<div class="frame e">Your post can\'t be larger than 2000 characters.</div>';
}
elseif((time()-$last_post[0]['lastpost']) < $flood_limit[0]['floodlimit'] && $rank < 4)
{
	$content = '<div class="frame e">You\'re attempting to post too soon.</div>';
}
else
{
	//auto-hiding?
	$data = $database->processQuery("SELECT `autohiding` FROM `threads` WHERE `id` = ?", array($thread), true);
	$status = ($data[0]['autohiding'] == 1) ? 1 : 0;

	//insert post
	$database->processQuery("INSERT INTO `posts` VALUES (null, ?, ?, ?, NOW(), ?, '', ?, ?)", array($username, nl2br($_POST['message']), $thread, $status, $_SERVER['REMOTE_ADDR'], time()), false);

	$creation_id = $database->getInsertId();

	//update thread
	$database->processQuery("UPDATE `threads` SET `lastposter` = ?, `lastpost` = NOW() WHERE `id` = ?", array($username, $thread), false);

	//update their last post field
	$database->processQuery("UPDATE `users` SET `lastpost` = ?", array(time()), false);

	//send them to the thread they posted on
	$base->redirect('viewthread.php?forum='. $f .'&id='. $thread.'&goto='. $creation_id);
}
}
else
{
$chars = ($rank > 2) ? $chars = null : $chars = 2000; 

if(isset($_GET['quote']) && isset($_GET['qt']) && $rank > 3)
{
	$quote = ($_GET['qt'] == 1) ? $database->processQuery("SELECT `content`,`username` FROM `posts` WHERE `id` = ?", array($_GET['quote']), true) : $database->processQuery("SELECT `content`,`username` FROM `threads` WHERE `id` = ?", array($_GET['quote']), true);

	$text = $base->remBr('[quote='. $quote[0]['username'] .']'. $quote[0]['content'] .'[/quote]');
}
        
        $content = '                    
        <div id="nocontrols" class="phold"></div>
        <div id="command">
        <form method="post" action="reply.php">
        <input type="hidden" name="id" value="'. $thread .'">
        <input type="hidden" name="forum" value="'. $f .'">
        <table>
        <tr>
                        <td class="commandtwo" colspan="2">You have <span id="charlimit_count_b">30</span> characters <span id="charlimit_info_b" style="display: none">remaining</span> for your title.</td>
        </tr>
        <tr>
                        <td class="commandtwo" colspan="2">
                        <textarea id="charlimit_text_a" name="message" rows="20" cols="60">'. $text .'</textarea><br />
                        You have <span id="charlimit_count_a">'. $chars .'</span> characters <span id="charlimit_info_a" style="display: none">remaining</span> for your message.</td>
        </tr>
        <tr>
        <td class="commandtwo" colspan="2"><br />
                        <input type="submit" name="add" value="Add reply" />    
                        <!--<input type="submit" name="preview" value="Preview" />    -->
                        <input type="submit" name="cancel" value="Cancel" />    
        </td>
        </tr>
        </table>
        </form>
        </div>


        <div id="smileylegend">
        <span class="title">Smileys: </span><br>
        <span id="smilytxt" style="display: hidden;">Click to add a smiley to your message (will overwrite selected text).</span><br />     
        <span onclick="addsmiley(\'\')"><IMG class=sm0 alt="" title="" src="../img/forum/smileys/smile.gif"> </span>     
        <span onclick="addsmiley(\'\')"><IMG class=sm1 alt="" title="" src="../img/forum/smileys/wink.gif"> </span>     
        <span onclick="addsmiley(\'\')"><IMG class=sm2 alt="" title="" src="../img/forum/smileys/tongue.gif"> </span>     
        <span onclick="addsmiley(\'\')"><IMG class=sm3 alt="" title="" src="../img/forum/smileys/sad.gif"> </span>     
        <span onclick="addsmiley(\':|\')"><IMG class=sm4 alt=":|" title=":|" src="../img/forum/smileys/nosmile.gif"> :|</span>     
        <span onclick="addsmiley(\'O_o\')"><IMG class=sm5 alt="O_o" title="O_o" src="../img/forum/smileys/o.O.gif"> O_o</span>     
        <span onclick="addsmiley(\'\')"><IMG class=sm6 alt="" title="" src="../img/forum/smileys/bigsmile.gif"> </span>     
        <span onclick="addsmiley(\'^^\')"><IMG class=sm7 alt="^^" title="^^" src="../img/forum/smileys/^^.gif"> ^^</span>     
        <span onclick="addsmiley(\'\')"><IMG class=sm8 alt="" title="" src="../img/forum/smileys/shocked.gif"> </span>     
        <span onclick="addsmiley(\':@\')"><IMG class=sm9 alt=":@" title=":@" src="../img/forum/smileys/angry.gif"> :@</span>     
        </div>';
}
?>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html xmlns:IE>
<head>
<meta http-equiv="Expires" content="0">
<meta http-equiv="Pragma" content="no-cache">
<meta http-equiv="Cache-Control" content="no-cache">
<meta name="MSSmartTagsPreventParsing" content="TRUE">
<title><?php echo $data['wb_title']; ?></title>
<link href="../css/basic-3.css" rel="stylesheet" type="text/css" media="all" />
<link href="../css/forum-3.css" rel="stylesheet" type="text/css" media="all" />
<link href="../css/forummsg-1.css" rel="stylesheet" type="text/css" media="all" />
<!--[if IE 8]>
<link rel="stylesheet" type="text/css" href="../css/forummsg-ie-1.css" />
<![endif]-->
<script src="../js/v_thread_1.js"></script>
<script src="../js/v_thread_2.js"></script>
<?php include('../includes/google_analytics.html'); ?>
</head>
<body>
<div id="body">
	<?php $forum->getNavBar($username, $rank); ?>
                <br /><br />

	<div style="text-align: center; background: none;">
		<div id="infopane">
			<div class="about">

				<ul class="flat">
					<li><a href="viewthread.php?forum=<?php echo $f; ?>&id=<?php echo $thread; ?>">Return to thread</a></li>
				</ul>

			</div>
		</div>
                        <?php echo $content; ?>
		<br />
			<div class="tandc"><?php echo $data['wb_foot']; ?></div>
	</div>

</div>
</body>

 

And how bad would the page be slowed down with ob_start();

Link to comment
Share on other sites

Not sure what you consider "ugly", but the whole thing is a hot mess from where I stand.

 

You have no separation of business logic from presentation logic, and no functions (much less classes) simplifying chunks of code, and there's too much "what is my user trying to do" guesswork going on. 

 

You need to learn how HTTP URIs are intended to work.  A URI implies a resource.  Its request method implies an action on that resource. 

 

If you're not using REST, you then need to extend your resources with URI-based actions, e.g.:

 

/user/view/1 - view user #1

/user/edit/1 (GET) - form to edit user #1

/user/edit/1 (POST) - save the results from editing user #1

/user/register (GET) - register a new user

/user/register (POST) - process registration

/user/login (GET) - login form

/user/login (POST) - process login

 

/thread/view/123 - view thread #123

/thread/create (GET) - form to create a new thread

/thread/create (POST) - create the thread  and redirect user to /thread/view/124

  (note... the "cancel" button should not post to /thread/create... it should link them to /forum/view/123 or similar)

/thread/delete/123 (GET) - admin delete form: "are you sure?"

/thread/delete/123 (POST) - process the deletion and redirect user (to /forum/view/123)

/thread/edit/123 (GET) - edit form

/thread/edit/123 (POST) - process the edit and redirect user (to /thread/view/123)

/thread/split/123 (GET) - admin's "split thread" form

/thread/split/123 (POST) - split the thread and redirect user

 

One resource & HTTP method per action.

 

Then you should split your GET & POST requests into separate "methods" as follows:

 

 

/thread/split.php (as an example)

 

if ($_SERVER["REQUEST_METHOD"] == "POST") {
    require_once("split_post.php");
} else {
    require_once("split_get.php");
}

 

Of course, better than that would be to have some router code with htaccess pushing all requests to /index.php.

 

That way, you can have one "master" script that figures out what people want to do based on URI and HTTP Request Method, and directs traffic to the appropriate PHP script.

 

 

Link to comment
Share on other sites

This thread is more than a year old. Please don't revive it unless you have something important to add.

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Guest
Reply to this topic...

×   Pasted as rich text.   Restore formatting

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

×
×
  • Create New...

Important Information

We have placed cookies on your device to help make this website better. You can adjust your cookie settings, otherwise we'll assume you're okay to continue.