-2

I've been stuck with the following problem for some time.

I keep getting the following error:

Warning: Invalid argument supplied for foreach() in     
/home/content/50/10835750/html/dogdays/game/table.class.php on line 32

Warning: Cannot modify header information - headers already sent by (output started at    
/home/content/50/10835750/html/dogdays/game/table.class.php:32) in 
/home/content/50/10835750/html/dogdays/game/loadplayer.php on line 77
Redirecting to /game/locations/

My code is as follows:

<?php 
// First we execute our common code to connection to the database and start the session 
define('MyConst', TRUE);

include('database.class.php');
include('table.class.php'); 
include('user.class.php');
include('characters.class.php');
include('pc/player.class.php');
include('pc/human.class.php');
include('loginattempts.class.php');
include('timer.class.php'); 
include('functions.php'); 
include('loginf.php');


$dbo = database::getInstance();
$dbo -> connect("*****************", "***********", "*********", "********", 
array(PDO::MYSQL_ATTR_INIT_COMMAND => 'SET NAMES utf8')); 

secSessionStart();

$_SESSION['page'] = "loadplayer.php";

// At the top of the page we check to see whether the user is logged in or not 
if(empty($_SESSION['user'])) 
{ 
    // If they are not, we redirect them to the login page. 
    header("Location: login.php"); 

    // Remember that this die statement is absolutely critical.  Without it, 
    // people can view your members-only content without logging in. 
    die("Redirecting to login.php"); 
} 

// Everything below this point in the file is secured by the login system 

// We can display the user's username to them by reading it from the session array.  
Remember that because 
// a username is user submitted content we must use htmlentities on it before     
displaying it to the user. 
?>
<?php
//    if(empty($_SESSION['playercharacter'])) {
    $character_id = "";
    $queryString = $_SERVER['QUERY_STRING'];
    $queryString = explode("&", $queryString);
    if(strcmp(substr($queryString[0],0,2),"c=") == 0) {
        $character_id = substr($queryString[0],2);
    }

    $c = new characters();
    $c -> load($character_id);
    $playercharacterobject = new human($c, null);
    $_SESSION['playercharacter'] = $playercharacterobject;

    try {
        $stmt = $dbo->getConnection()->prepare("SELECT * FROM location WHERE 
location_id = :location_id");
        $query_params = array(':location_id'=>$playercharacterobject->location_id);       
        // Execute the prepared query.
        $result = $stmt->execute($query_params);
    }
    catch(PDOException $ex) { 
        // Note: On a production website, you should not output $ex->getMessage(). 
        // It may provide an attacker with helpful information about your code.  
        die("Failed to run query1: " . $ex->getMessage()); 
    }

    $rows = $stmt->fetch(PDO::FETCH_ASSOC);

    $_SESSION['currentlocation'] = $rows['url'];
    $validAccess = array("babelfloor.php");
    $_SESSION['validAccess'] = $validAccess;
    $_SESSION['prevlocation'] = "loadplayer.php";
//    }


//     echo $_SESSION['currentlocation'];
//     echo $rows['url']; 
    // THIS IS LINE 77. THE ONE THAT IS CAUSING PROBLEMS 
    header("Location: /game/locations/".$_SESSION['currentlocation']);
    die("Redirecting to /game/locations/".$_SESSION['currentlocation']);
//      header("Location: combat.php");
//      die("Redirecting to combat.php"); 
?>

and

<?php
/**
* @author Alvin Tung
* @copyright 2013
*/

if(!defined('MyConst')) {
    die('Direct access not premitted');
}

class table {
    protected $id = null;
    protected $table = null;

    function __construct() {

    }

    function bind($data) {
        foreach ($data as $key=>$value) {
            $this -> $key = $value;
        }
    }

    function load($id) {
        $this->id = $id;

        $dbo = database::getInstance();
        $sql = $this->buildQuery('load');
        $row = $dbo->query($sql, array(':'.$this->table.'_id'=> $id));

            // THIS IS LINE 32
        foreach ($row as $key=>$value) {
            if($key == "user_id()") {
                continue;
            }

            $this->$key = $value;
        }

    }

    // write database object contents to database
    function store() {
        $dbo = database::getInstance();

        $array = array();
        $classVars = get_object_vars($this);

        if($this->id =="") {
            foreach ($classVars as $key=>$value) {
                if ($key == "id" || $key == "table") {
                    continue;
                }

                $array[":{$key}"] = $value;
            }
        }
        else {
            $array[':'.$this->table.'_id'] = $this->id;
        }     

        $sql = $this -> buildQuery('store');

        $dbo -> query($sql, $array);   
    }

    function buildQuery($task) {
        $sql = "";

        if ($task == "store") {
            // if no id value has been store in this object yet,
            //  add new record to the database, else just update the record.
            if ($this->id == "") {
                $keys = "";
                $values = "";
                $classVars = get_class_vars(get_class($this));
                $sql .= "INSERT INTO {$this->table}";

                foreach ($classVars as $key=>$value) {
                    if ($key == "id" || $key == "table") {
                        continue;
                    }

                    $keys .= "$key,";
                    $values .= ":$key,";
                }

                // NOTE: all substr($keys, 0, -1) does is gets rid of the comma
                // at the on the last array element.
                $sql .= "(".substr($keys, 0, -1).") Values (".substr($values, 0,   

-1).")";

            }
            else {

                $classVars = get_class_vars(get_class($this));
                $sql .= "UPDATE {$this->table} SET ";

                foreach ($classVars as $key=>$value) {
                    if ($key == "id" || $key == "table") {
                        continue;
                    }

                    $sql .= "{$key} = '{$this->$key}',";

                }
                $sql = substr($sql, 0, -1)." WHERE {$this->table}_id = :{$this-

>table}_id";

            }         
        }
        elseif ($task == "load") {
            $sql = "SELECT * FROM {$this->table} WHERE {$this->table}_id = :

{$this->table}_id";
        }

        return $sql;      
    }
}



?>

I've tried adding ob_start() to the top of loadplayer.php as is suggested by most answers on here, but then it justs outputs a blank page. Your insights would be greatly appreciated.

user2361103
  • 97
  • 2
  • 12

1 Answers1

1

The error message Invalid argument supplied for foreach() indicates that foreach is given something that is not an array nor a Traversable object.

Given this piece of code:

$dbo = database::getInstance();
$sql = $this->buildQuery('load');
$row = $dbo->query($sql, array(':'.$this->table.'_id'=> $id));

// THIS IS LINE 32
foreach ($row as $key=>$value) {

it is clear that $row is not what you expect. Maybe the query contains invalid sql or the id does not exist in the database. You should do more error checking to properly handle those cases.

The message headers already sent is not really important here. If you resolve the first issue, the second one will also be gone.

Arjan
  • 9,784
  • 1
  • 31
  • 41