-2

So I am making a webpage where users login using facebook. If the user is already logged in the page redirects to another page. But recently I encountered the famous http headers already sent error. Now usually I know how to solve this, but I just cant find the error in my files. Here are the pages:

Full error:

Warning: session_start() [function.session-start]: Cannot send session cache limiter - headers already sent (output started at /home/streetst/public_html/scripts/fb/fbaccess.php:1) in /home/streetst/public_html/scripts/fb/src/facebook.php on line 49

Index.php

<?php include 'scripts/fb/fbaccess.php'; ?>
<!DOCTYPE HTML>
<html>
    <head>
        <title>Streetstash - Streetwear, Accessories & Skateboarding, samlet på et sted</title>
        <link rel="stylesheet" type="text/css" href="stylesheet.css">
        <script src="//ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js" ></script>

        <meta name='description' content='Alle dine yndlings butikker, tøj, accessories og skateboarding samlet på et sted.' />
        <meta charset="utf-8">

        <?php if($_GET['welcome']=='no'){?>
            <script language="javascript">
                window.location.href = "scripts/log_user.php"
            </headersalreadscript>
        <?php } ?>

        <script>
            $(document).ready(function() {
                $('h1.title').fadeIn(1500);
                $('h3.subtitle').delay(1500).fadeIn(2000);

                setTimeout(function() {
                    $('html, body').animate({ 
                        scrollTop: $('div.sub-body').offset().top 
                    }, 2000);
                }, 4000);
            });
        </script>
    </head>

    <body>
        <div class='content'>
            <div class='head'>
            </div>
            <div class='body'>
                <h1 class='title'>Streetstash</h1><br>
                <h3 class='subtitle'>Streetwear, Accessories & Skateboarding</h3>
                <div class='sub-body'>
                    <div class='title'><h2 class='title'>Streetstash</h2><br><h3 class='subsubtitle'>Streetwear, Accessories & Skateboarding</h3></div>
                    <div class='table'>
                        <div class='table_left'>
                            <h2>Hvad er det?</h2>
                            <p>Streetstash er en ny måde at handle tøj, accessories og skateboarding varer på internettet.<br><br>Streetstash samler alle de butikker du normalt handler på over internettet på et sted og tilbyder en platform, hvor du nemt og hurtigt kan finde de bedste tilbud på dine favorit varer.</p>
                        </div>
                        <div class='table_right'>
                            <h2>Tilmeld</h2>
                            <p>Støt projektet, tilmeld dig forud og modtag nyheder, opdateringer og vær klar til at shoppe de fedeste varer så snart vi åbner.</p><br>
                            <?php
                                if($user_info == null){
                                    echo '<a href="'.$loginUrl.'"><img src="resources/img/fb_button.png"></a>';
                                }else{
                                    echo '<p class="success">Tak for tilmeldingen '.$user_info['first_name'].'!</p>';
                                }
                            ?>
                        </div>
                    </div>
                    <div class='vertline'>
                    </div>
                </div>
            </div>
        </div>
    </body>
</html>

/scripts/log_user.php

<?php
    include 'fb/fbaccess.php';
    include 'db_connect.php';

    $check_query = mysql_query('SELECT * FROM users WHERE user_id = '.$user_info['id'].'');
    $check_user_existence = mysql_num_rows($check_query);
    echo $check_user_existence;
    if($check_user_existence == 1){
        echo 'User already exists';
    }else{
        mysql_query("INSERT INTO users (id, first_name, last_name, user_id, email) VALUES (NULL, '$user_info[first_name]', '$user_info[last_name]', '$user_info[id]', '$user_info[email]')") or die(mysql_error);
    }

    echo "
        <script type='text/javascript'>
        <!--
            window.location = '../../index.php'
        //-->
        </script>
    ";
?>

/scripts/fb/fbaccess.php

<?php
//Application Configurations
$app_id     = "265869100216640";
$app_secret = "47a0c95c974f6bab011824549e196bd2";
$site_url   = "http://streetstash.dk/index.php?welcome=no";

try{
    include_once "src/facebook.php";
}catch(Exception $e){
    error_log($e);
}

// Create our application instance
$facebook = new Facebook(array(
    'appId'     => $app_id,
    'secret'    => $app_secret,
    ));

// Get User ID
$user = $facebook->getUser();
// We may or may not have this data based
// on whether the user is logged in.
// If we have a $user id here, it means we know
// the user is logged into
// Facebook, but we don’t know if the access token is valid. An access
// token is invalid if the user logged out of Facebook.

if($user){
//==================== Single query method ======================================
    try{
        // Proceed knowing you have a logged in user who's authenticated.
        $user_profile = $facebook->api('/me');
    }catch(FacebookApiException $e){
        error_log($e);
        $user = NULL;
    }
//==================== Single query method ends =================================
}

if($user){
    // Get logout URL
    $logoutUrl = $facebook->getLogoutUrl();
}else{
    // Get login URL
    $loginUrl = $facebook->getLoginUrl(array(
        'scope'     => 'email, publish_stream, publish_actions, read_friendlists, user_location',
        'redirect_uri'  => $site_url,
        ));
}

if($user){
    // Proceed knowing you have a logged in user who has a valid session.

//========= Batch requests over the Facebook Graph API using the PHP-SDK ========
    // Save your method calls into an array
    $queries = array(
        array('method' => 'GET', 'relative_url' => '/'.$user),
        array('method' => 'GET', 'relative_url' => '/'.$user.'/friends'),
        );

    // POST your queries to the batch endpoint on the graph.
    try{
        $batchResponse = $facebook->api('?batch='.json_encode($queries), 'POST');
    }catch(Exception $o){
        error_log($o);
    }

    //Return values are indexed in order of the original array, content is in ['body'] as a JSON
    //string. Decode for use as a PHP array.
    $user_info      = json_decode($batchResponse[0]['body'], TRUE);
    $friends_list   = json_decode($batchResponse[1]['body'], TRUE);
//========= Batch requests over the Facebook Graph API using the PHP-SDK ends =====
}
?>

/scripts/fb/src/facebook.php

<?php
/**
 * Copyright 2011 Facebook, Inc.
 *
 * Licensed under the Apache License, Version 2.0 (the "License"); you may
 * not use this file except in compliance with the License. You may obtain
 * a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
 * License for the specific language governing permissions and limitations
 * under the License.
 */

require_once "base_facebook.php";

/**
 * Extends the BaseFacebook class with the intent of using
 * PHP sessions to store user ids and access tokens.
 */
class Facebook extends BaseFacebook
{
  const FBSS_COOKIE_NAME = 'fbss';

  // We can set this to a high number because the main session
  // expiration will trump this.
  const FBSS_COOKIE_EXPIRE = 31556926; // 1 year

  // Stores the shared session ID if one is set.
  protected $sharedSessionID;

  /**
   * Identical to the parent constructor, except that
   * we start a PHP session to store the user ID and
   * access token if during the course of execution
   * we discover them.
   *
   * @param Array $config the application configuration. Additionally
   * accepts "sharedSession" as a boolean to turn on a secondary
   * cookie for environments with a shared session (that is, your app
   * shares the domain with other apps).
   * @see BaseFacebook::__construct in facebook.php
   */
  public function __construct($config) {
    if (!session_id()) {
      session_start();
    }
    parent::__construct($config);
    if (!empty($config['sharedSession'])) {
      $this->initSharedSession();
    }
  }

  protected static $kSupportedKeys =
    array('state', 'code', 'access_token', 'user_id');

  protected function initSharedSession() {
    $cookie_name = $this->getSharedSessionCookieName();
    if (isset($_COOKIE[$cookie_name])) {
      $data = $this->parseSignedRequest($_COOKIE[$cookie_name]);
      if ($data && !empty($data['domain']) &&
          self::isAllowedDomain($this->getHttpHost(), $data['domain'])) {
        // good case
        $this->sharedSessionID = $data['id'];
        return;
      }
      // ignoring potentially unreachable data
    }
    // evil/corrupt/missing case
    $base_domain = $this->getBaseDomain();
    $this->sharedSessionID = md5(uniqid(mt_rand(), true));
    $cookie_value = $this->makeSignedRequest(
      array(
        'domain' => $base_domain,
        'id' => $this->sharedSessionID,
      )
    );
    $_COOKIE[$cookie_name] = $cookie_value;
    if (!headers_sent()) {
      $expire = time() + self::FBSS_COOKIE_EXPIRE;
      setcookie($cookie_name, $cookie_value, $expire, '/', '.'.$base_domain);
    } else {
      // @codeCoverageIgnoreStart
      self::errorLog(
        'Shared session ID cookie could not be set! You must ensure you '.
        'create the Facebook instance before headers have been sent. This '.
        'will cause authentication issues after the first request.'
      );
      // @codeCoverageIgnoreEnd
    }
  }

  /**
   * Provides the implementations of the inherited abstract
   * methods.  The implementation uses PHP sessions to maintain
   * a store for authorization codes, user ids, CSRF states, and
   * access tokens.
   */
  protected function setPersistentData($key, $value) {
    if (!in_array($key, self::$kSupportedKeys)) {
      self::errorLog('Unsupported key passed to setPersistentData.');
      return;
    }

    $session_var_name = $this->constructSessionVariableName($key);
    $_SESSION[$session_var_name] = $value;
  }

  protected function getPersistentData($key, $default = false) {
    if (!in_array($key, self::$kSupportedKeys)) {
      self::errorLog('Unsupported key passed to getPersistentData.');
      return $default;
    }

    $session_var_name = $this->constructSessionVariableName($key);
    return isset($_SESSION[$session_var_name]) ?
      $_SESSION[$session_var_name] : $default;
  }

  protected function clearPersistentData($key) {
    if (!in_array($key, self::$kSupportedKeys)) {
      self::errorLog('Unsupported key passed to clearPersistentData.');
      return;
    }

    $session_var_name = $this->constructSessionVariableName($key);
    unset($_SESSION[$session_var_name]);
  }

  protected function clearAllPersistentData() {
    foreach (self::$kSupportedKeys as $key) {
      $this->clearPersistentData($key);
    }
    if ($this->sharedSessionID) {
      $this->deleteSharedSessionCookie();
    }
  }

  protected function deleteSharedSessionCookie() {
    $cookie_name = $this->getSharedSessionCookieName();
    unset($_COOKIE[$cookie_name]);
    $base_domain = $this->getBaseDomain();
    setcookie($cookie_name, '', 1, '/', '.'.$base_domain);
  }

  protected function getSharedSessionCookieName() {
    return self::FBSS_COOKIE_NAME . '_' . $this->getAppId();
  }

  protected function constructSessionVariableName($key) {
    $parts = array('fb', $this->getAppId(), $key);
    if ($this->sharedSessionID) {
      array_unshift($parts, $this->sharedSessionID);
    }
    return implode('_', $parts);
  }
}

Really need to guidance with this one!

  • 4
    Congrats! You just asked The Most Popular question on Stack Overflow! – Your Common Sense Apr 08 '13 at 10:40
  • 1
    Small tip: to avoid all the copy & paste it may be easier to pack all these files up and provide a download for easier viewing. – Coreus Apr 08 '13 at 10:49
  • possible duplicate of [Headers already sent by PHP](http://stackoverflow.com/questions/8028957/headers-already-sent-by-php) – Jocelyn Apr 08 '13 at 12:07

1 Answers1

1

Try turning on Output Buffering using ob_start()

haim770
  • 48,394
  • 7
  • 105
  • 133
  • Okay. Sorry for noob question, where should I put this? – Thobias Nordgaard Apr 08 '13 at 11:19
  • Preferably at the top of your main PHP file, or at least before your first `echo`. – haim770 Apr 08 '13 at 11:21
  • Did as you asked, errors gone. What effect does this have on my script? – Thobias Nordgaard Apr 08 '13 at 11:24
  • There shouldn't be any adverse effect unless you relied on explicit Output Flushing somewhere on your code. If you don't know what i'm talking about then you're probably good to go. Also keep in mind that many popular PHP framework are turning Output Buffering on by default then you should consider it as good practice. See here: http://stackoverflow.com/questions/2832010/what-is-output-buffering – haim770 Apr 08 '13 at 11:26