Undefined Index Errors with CRUD Application

I’m trying to code a PHP Web Application using the CRUD method. I’ve gotten pretty far, but I can’t seem to tell the code to read my current records from the database. I get the following errors every time I load the webpage:

Notice : Undefined index: id in C:\xampp\htdocs\ccrp\index.php on line 105
Notice : Undefined index: name in C:\xampp\htdocs\ccrp\index.php on line 106
Notice : Undefined index: residential_address in C:\xampp\htdocs\ccrp\index.php on line 107
Notice : Undefined index: mailing_address in C:\xampp\htdocs\ccrp\index.php on line 108
Notice : Undefined index: precinct in C:\xampp\htdocs\ccrp\index.php on line 109
Notice : Undefined index: age in C:\xampp\htdocs\ccrp\index.php on line 110
Notice : Undefined index: ethnicity in C:\xampp\htdocs\ccrp\index.php on line 111
Notice : Undefined index: gender in C:\xampp\htdocs\ccrp\index.php on line 112
Notice : Undefined index: party in C:\xampp\htdocs\ccrp\index.php on line 113
Notice : Undefined index: race in C:\xampp\htdocs\ccrp\index.php on line 114
Notice : Undefined index: phone in C:\xampp\htdocs\ccrp\index.php on line 115

My code is spanned across 4 different files that are linked together to form the application: database (in the classes folder), member (also in the classes folder), index (in the root folder of the project, and form (also in the root folder of the project).

I apologize in advance if this is a duplicate question, but I have been working on this for weeks and I can’t seem to get anywhere. Also, I’m running xampp in case anyone is wondering.

Here is the link to my files if anyone can look through them and tell me what to fix: https://filetransfer.io/data-package/cMxRb7wd

The reason for the undefined index errors are because you are using SELECT * in the query and the column names in your database table definition don’t match the letter-case you are using in the php code. If you had listed out the columns in the query, which you should always do, using lower-case names, the php code would have matched what is being SELECTed and it would have worked.

You need to be consistent throughout your design in what you are naming something. I recommend that you rename the columns in your database table to be all lower-case and that you list out the columns in the SELECT term in the query.

Incorrect. Undefined Index errors come from referencing variables or indexes when they aren’t created. You can’t reference an index or a variable if you have never created it in the first place. It doesn’t make sense. That’s like saying “Hey, make me a pizza, but I won’t tell you what kind of pizza I want you to make.” You really can’t make the pizza if you don’t know what kind of pizza it’s going to be. That’s what Undefined Index errors are.

@jmyrtle
Please post the code on this forum. No one wants to download a file on the internet.

<?php
// Database Connection File - 'database.php
class Database {
    // Connection variables
    private $host = "localhost";
    private $dbName = "ccrp_db";
    private $username = "root";
    private $password = "";

    public $conn;

    // Method return security connection
    public function dbConnection() {
        $this->conn = null;
        try {
            $this->conn = new PDO("mysql:host=" . $this->host . ";dbname=" . $this->dbName, $this->username, $this->password, array(
                PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
                PDO::MYSQL_ATTR_INIT_COMMAND => "SET NAMES utf8"
            ));
        } catch (PDOException $exception) {
            echo "Connection error: " . $exception->getMessage();
        }
        return $this->conn;
    }
}

?>

<?php
// Member Class file - member.php
require_once 'database.php';

class Member {
    private $conn;

    // Constructor
    public function __construct(){
      $database = new Database();
      $db = $database->dbConnection();
      $this->conn = $db;
    }


    // Execute queries SQL
    public function runQuery($sql){
      $stmt = $this->conn->prepare($sql);
      return $stmt;
    }

    // Insert
    public function insert($name, $residential_address, $mailing_address, $precinct, $age, $ethnicity, $gender, $party, $race, $phone){
      try{
        $stmt = $this->conn->prepare("INSERT INTO members (name, residential_address, mailing_address, precinct, age, ethnicity, gender, party, race, phone) VALUES(:name, :residential_address, :mailing_address, :precinct, :age, :ethnicity, :gender, :party, :race, :phone)");
        $stmt->bindparam(":name", $name);
        $stmt->bindparam(":residential_address", $residential_address);
		$stmt->bindparam(":mailing_address", $mailing_address);
		$stmt->bindparam(":precinct", $precinct);
		$stmt->bindparam(":age", $age);
		$stmt->bindparam(":ethnicity", $ethnicity);
		$stmt->bindparam(":gender", $gender);
		$stmt->bindparam(":party", $party);
		$stmt->bindparam(":race", $race);
		$stmt->bindparam(":phone", $phone);
        $stmt->execute();
        return $stmt;
      }catch(PDOException $e){
        echo $e->getMessage();
      }
    }


    // Update
	    public function update($name, $residential_address, $mailing_address, $precinct, $age, $ethnicity, $gender, $party, $race, $phone, $id){
      try{
        $stmt = $this->conn->prepare("UPDATE members SET name = :name, residential_address = :residential_address, mailing_address = :mailing_address, precinct = :precinct, age = :age, ethnicity = :ethnicity, gender = :gender, party = :party, race = :race, phone = :phone WHERE id = :id");
        $stmt->bindparam(":name", $name);
        $stmt->bindparam(":residential_address", $residential_address);
		$stmt->bindparam(":mailing_address", $mailing_address);
		$stmt->bindparam(":precinct", $precinct);
		$stmt->bindparam(":age", $age);
		$stmt->bindparam(":ethnicity", $ethnicity);
		$stmt->bindparam(":gender", $gender);
		$stmt->bindparam(":party", $party);
		$stmt->bindparam(":race", $race);
		$stmt->bindparam(":phone", $phone);
		$stmt->bindparam(":phone", $id);
        $stmt->execute();
        return $stmt;
      }catch(PDOException $e){
        echo $e->getMessage();
      }
    }

    // Delete
	    public function delete($id){
      try{
        $stmt = $this->conn->prepare("DELETE FROM members WHERE id = :id");
		$stmt->bindparam(":phone", $id);
        $stmt->execute();
        return $stmt;
      }catch(PDOException $e){
        echo $e->getMessage();
      }
    }

    // Redirect URL method
	public function redirect($url){
		header("Location: $url");
	}
}
?>

<?php
// Form to Add New Members - form.php
// Show PHP errors
ini_set('display_errors',1);
ini_set('display_startup_erros',1);
error_reporting(E_ALL);

require_once 'classes/member.php';

$objMember = new Member();
// GET
if(isset($_GET['edit_id'])){
	$id = $_GET['edit_id'];
	$stmt = $objMember->runQuery("SELECT * FROM members WHERE id=:id");
	$stmt->execute(array(":id" => $id));
	$rowMember = $stmt-fetch(PDO::FETCH_ASSOC);
}else{
	$id = null;
	$rowMember = null;
}

// POST
if(isset($_POST['btn_save'])){
	$name = strip_tags($_POST['name']);
	$residential_address = strip_tags($_POST['residential_address']);
	$mailing_address = strip_tags($_POST['mailing_address']);
	$precinct = strip_tags($_POST['precinct']);
	$age = strip_tags($_POST['age']);
	$ethnicity = strip_tags($_POST['ethnicity']);
	$gender = strip_tags($_POST['gender']);
	$party = strip_tags($_POST['party']);
	$race = strip_tags($_POST['race']);
	$phone = strip_tags($_POST['phone']);
	try {
		if($id !=null){
			if($objMember->update($name, $residential_address, $mailing_address, $precinct, $age, $ethnicity, $gender, $party, $race, $phone)){
				$objMember->redirect('index.php?updated');
			}
		}else{
			if($objMember->insert($name, $residential_address, $mailing_address, $precinct, $age, $ethnicity, $gender, $party, $race, $phone)){
				$objMember->redirect('index.php?inserted');
			}else{
				$ocjMember->redirect('index.php?error');
			}
		}
	}catch(PDOException $e){
		echo $e->getMessage();
	}
}


?>
<!doctype html>
<html lang="en">
    <head>
        <!-- Head metas, css, and title -->
        <?php require_once 'includes/head.php'; ?>
    </head>
    <body>
        <!-- Header banner -->
        <?php require_once 'includes/header.php'; ?>
        <div class="container-fluid">
            <div class="row">
                <!-- Sidebar menu -->
                <?php require_once 'includes/sidebar.php'; ?>
                <main role="main" class="col-md-9 ml-sm-auto col-lg-10 px-4">
                <h1 style="margin-top:10px">Add/Edit Members</h1>  
				<!-- <p>Required fields are in * </p>--> 
				<form method="post">
					<div class="form-group">
						<label for="id">ID</label>
						<input class="form-control" type="number" name="id" id="id" value="<?php print($rowMember['id']); ?>" readonly>
					</div>
					<div class="form-group">
						<label for="name">Name</label>
						<input class="form-control" type="text" name="name" id="name" placeholder="Last, First Middle" value="<?php print($rowMember['name']); ?>"  maxlength="40">
					</div>
					<div class="form-group">
						<label for="residential_address">Residential Address</label>
						<input class="form-control" type="text" name="residential_address" id="residential_address" value="<?php print($rowMember['residential_address']); ?>" maxlength="50">
					</div>
					<div class="form-group">
						<label for="mailing_address">Mailing Address</label>
						<input class="form-control" type="text" name="mailing_address" id="mailing_address" value="<?php print($rowMember['mailing_address']); ?>" maxlength="65">
					</div>
					<div class="form-group">
						<label for="precinct">Precinct</label>
						<input class="form-control" type="text" name="precinct" id="precinct" placeholder="##-##" value="<?php print($rowMember['precinct']); ?>" maxlength="5">
					</div>
					<div class="form-group">
						<label for="age">Age</label>
						<input class="form-control" type="number" name="age" id="age" placeholder="##" value="<?php print($rowMember['age']); ?>" maxlength="2">
					</div>
					<div class="form-group">
						<label for="ethnicity">Ethnicity</label>
						<input class="form-control" type="text" name="ethnicity" id="ethnicity" placeholder="NL" value="<?php print($rowMember['ethnicity']); ?>" maxlength="2">
					</div>
					<div class="form-group">
						<label for="gender">Gender</label>
						<input class="form-control" type="text" name="gender" id="gender" placeholder="M" value="<?php print($rowMember['gender']); ?>" maxlength="1">
					</div>
					<div class="form-group">
						<label for="party">Party</label>
						<input class="form-control" type="text" name="party" id="party" placeholder="REP" value="<?php print($rowMember['party']); ?>" maxlength="3">
					</div>
					<div class="form-group">
						<label for="race">Race</label>
						<input class="form-control" type="text" name="race" id="race" placeholder="W" value="<?php print($rowMember['race']); ?>" maxlength="1">
					</div>
					<div class="form-group">
						<label for="phone">Phone Number</label>
						<input class="form-control" type="text" name="phone" id="phone" placeholder="###-###-#####" value="<?php print($rowMember['phone']); ?>" maxlength="12">
					</div>	
					<input class="btn btn-primary mb-2" type="submit" name="btn_save" value="Submit">																																																	
				</form>
                </main>
            </div>
        </div>
        <!-- Footer scripts, and functions -->
        <?php require_once 'includes/footer.php'; ?>
    </body>
</html>

<?php
// Website Homepage (where I'm having issues) - index.php
// Show PHP errors
ini_set('display_errors',1);
ini_set('display_startup_erros',1);
error_reporting(E_ALL);

require_once 'classes/member.php';

$objMember = new Member();

// GET
if(isset($_GET['delete_id'])){
  $id = $_GET['delete_id'];
  try{
    if($id != null){
      if($objMember->delete($id)){
        $objMember->redirect('index.php?deleted');
      }
    }else{
      var_dump($id);
    }
  }catch(PDOException $e){
    echo $e->getMessage();
  }
}

?>
<!doctype html>
<html lang="en">
    <head>
        <!-- Head metas, css, and title -->
        <?php require_once 'includes/head.php'; ?>
    </head>
    <body>
        <!-- Header banner -->
        <?php require_once 'includes/header.php'; ?>
        <div class="container-fluid">
            <div class="row">
                <!-- Sidebar menu -->
                <?php require_once 'includes/sidebar.php'; ?>
                <main role="main" class="col-md-9 ml-sm-auto col-lg-10 px-4">
                    <h1 style="margin-top: 10px">Members List</h1>
                    <?php
                      if(isset($_GET['updated'])){
                        echo '<div class="alert alert-info alert-dismissable fade show" role="alert">
                        <strong>User!<trong> Updated with success.
                          <button type="button" class="close" data-dismiss="alert" aria-label="Close">
                            <span aria-hidden="true"> &times; </span>
                          </button>
                        </div>';
                      }else if(isset($_GET['deleted'])){
                        echo '<div class="alert alert-info alert-dismissable fade show" role="alert">
                        <strong>User!<trong> Deleted with success.
                          <button type="button" class="close" data-dismiss="alert" aria-label="Close">
                            <span aria-hidden="true"> &times; </span>
                          </button>
                        </div>';
                      }else if(isset($_GET['inserted'])){
                        echo '<div class="alert alert-info alert-dismissable fade show" role="alert">
                        <strong>User!<trong> Inserted with success.
                          <button type="button" class="close" data-dismiss="alert" aria-label="Close">
                            <span aria-hidden="true"> &times; </span>
                          </button>
                        </div>';
                      }else if(isset($_GET['error'])){
                        echo '<div class="alert alert-info alert-dismissable fade show" role="alert">
                        <strong>DB Error!<trong> Something went wrong with your action. Try again!
                          <button type="button" class="close" data-dismiss="alert" aria-label="Close">
                            <span aria-hidden="true"> &times; </span>
                          </button>
                        </div>';
                      }
                    ?>
						<div class="table-responsive">
							<table class="table table-striped table-sm">
								<thead>
									<tr>
										<th>ID</th>
										<th>Name</th>
										<th>Residential Address</th>
										<th>Mailing Address</th>
										<th>Precinct</th>
										<th>Age</th>
										<th>Ethnicity</th>
										<th>Gender</th>
										<th>Party</th>
										<th>Race</th>
										<th>Phone Number</th>
										<th></th>
										<th></th>
									</tr>
								</thead>
								<?php
								$query = "SELECT * FROM members LIMIT 25";
								$stmt = $objMember->runQuery($query);
								$stmt->execute();
								?>
								<tbody>
									<?php if($stmt->rowCount() > 0){
										while($rowMember = $stmt->fetch(PDO::FETCH_ASSOC)){
									?>
									<tr>
										<td><?php print($rowMember['id']); ?></td>
										<td><?php print($rowMember['name']); ?></td>
										<td><?php print($rowMember['residential_address']); ?></td>
										<td><?php print($rowMember['mailing_address']); ?></td>
										<td><?php print($rowMember['precinct']); ?></td>
										<td><?php print($rowMember['age']); ?></td>
										<td><?php print($rowMember['ethnicity']); ?></td>
										<td><?php print($rowMember['gender']); ?></td>
										<td><?php print($rowMember['party']); ?></td>
										<td><?php print($rowMember['race']); ?></td>
										<td><?php print($rowMember['phone']); ?></td>
										<td><a href="form.php?edit_id=<?php print($rowMember['id']); ?>"><span>Edit</span></a></td>
										<td><a href="form.php?edit_id=<?php print($rowMember['id']); ?>"><span data-feather="trash"></span></a></td>
									</tr>
								</tbody>
								<?php } } ?>
							</table>
						</div>
                </main>
            </div>
        </div>
        <!-- Footer scripts, and functions -->
        <?php require_once 'includes/footer.php'; ?>

        <!-- Custom scripts -->
        <script>
            // JQuery confirmation
            $('.confirmation').on('click', function () {
                return confirm('Are you sure you want to delete this member?');
            });
        </script>
    </body>
</html>

This whole section won’t work because your button has a value of Submit, but you’re trying to look for btn_save. I suggest actually using

if($_SERVER['REQUEST_METHOD'] == 'POST')

Instead of relying on the button. Also, you’re missing a > here

So you’ll get an error here too. Your form may also need an action attribute.

And while we’re picking at it:

$stmt = $this->conn->prepare("DELETE FROM members WHERE id = :id");
$stmt->bindparam(":phone", $id);

This will fail, too:

$stmt = $this->conn->prepare("UPDATE members SET name = :name, 
     residential_address = :residential_address, 
     mailing_address = :mailing_address, 
     precinct = :precinct, age = :age, 
     ethnicity = :ethnicity, gender = :gender, 
     party = :party, race = :race, phone = :phone WHERE id = :id");

as you don’t provide a value for :id.

1 Like

@spaceshiptrooper @droopsnoot

I still don’t get it. How does this explain why I’m seeing undefined indexes across my homepage? I found this method from a guy on YouTube, downloaded his files and edited the code to match what I need. Yet somehow, my homepage shows undefined index errors. Where in my code should I define my column names to get the data and how do I do it?

Also, @spaceshiptrooper, btn_save is the button’s name, not the value, so why would that throwback an error?

@droopsnoot, If I didn’t provide a value for :id, then how does everything else have a value? It has to look up the values to everything else using the value from the ID column. That’s how (I thought) it was written.

Here are the YouTube videos that I am following: https://www.youtube.com/playlist?list=PLS1QulWo1RIagiNF9X4B_mkJYzjCbx6GI

These are the results I’m expecting, but I also want to add pagination (as I have more than 3 records) and add an edit link rather than clicking on the person’s name.

Someone posted a correct reply as to why you are getting the undefined index errors. If you use print_r($rowMember); inside the while(){} loop, you will see that the letter-case of the indexes in the fetched data doesn’t match the index names you are using in the php code.

The current isset() logic is functional, unless you end up using ajax at some point to submit the form.

You have at least two places in the code where you are binding the $id variable to the named place-holder :phone. The place-holder name should be :id.

This code is filled with bad programming practices. I stopped writing my previous reply after the cause of the index errors, because it would have taken too much to list everything that’s wrong with the code and even the database table design (one of my favorites - a person’s age changes once a year, on their birthday, unless they are dead. You should store the date of birth, then calculate the age when needed.)

@mabismad

Thanks for breaking down my previous response. I changed the table column letter-case and it cleared the undefined index errors; so now I can see my data in the application from the database.

I have a large amount of records in this table. How can I add pagination in this code rather than loading all of the records at the same time? The tutorial did not go over this, so I’d be coding my pagination from scratch.

There are countless pagination examples posted on the web. You basically have two similar queries. The 1st one gets a COUNT(*) of the number of rows matching the table, any join conditions, and any where/having clauses. The result from this query is used to calculate the total number of pages. The total number of pages is used to limit the requested page number and to produce the pagination links. The 2nd query gets the records that correspond to the requested page number, by calculating the row offset from the requested page and the number of items per page, and adding a LIMIT clause to the base query.

Before you do this, I recommend that you move the database specific code from inside your html document to right before the start of the html document, then fetch the data from the query into a php variable. This variable would be tested/looped over at the correct place in the html document.

OP, DO NOT use this code for anything other than learning. If you use it in production on the Internet anyone in the world could easily delete your entire database.

The code is generally OK as a starting point to learn but there are quite a few problems with it. I would encourage you to learn what things are actually doing and what they mean. When you can recognize ten or more issues on your own with this code you will be well on your way to being a master coder.

Check out this PDO Tutorial
https://phpdelusions.net/pdo

1 Like

It’s not supposed to throw back an error. I never said it did. I said that it won’t work because it’s a logical problem. It’s a lot better to not rely on the button and just on the request type. The whole isset check on the button is an amateur hack that’s been used for years. You’re better off doing it the correct way which is what I showed you.

Seeing that you figured out what was causing your problem, I’d suggest looking at how the overall application should run. Like @benanamen said, it’s pretty dangerous to allow anyone to delete records without being authorized.

@spaceshiptrooper I think I understand a bit more now. I’ve made the change as shown below:

// POST
if($_SERVER['REQUEST_METHOD'] == 'POST'){
	$name = strip_tags($_POST['name']);
	$residential_address = strip_tags($_POST['residential_address']);
	$mailing_address = strip_tags($_POST['mailing_address']);
	$precinct = strip_tags($_POST['precinct']);
	$age = strip_tags($_POST['age']);
	$ethnicity = strip_tags($_POST['ethnicity']);
	$gender = strip_tags($_POST['gender']);
	$party = strip_tags($_POST['party']);
	$race = strip_tags($_POST['race']);
	$phone = strip_tags($_POST['phone']);
	try {
		if($id !=null){
			if($objMember->update($name, $residential_address, $mailing_address, $precinct, $age, $ethnicity, $gender, $party, $race, $phone)){
				$objMember->redirect('index.php?updated');
			}
		}else{
			if($objMember->insert($name, $residential_address, $mailing_address, $precinct, $age, $ethnicity, $gender, $party, $race, $phone)){
				$objMember->redirect('index.php?inserted');
			}else{
				$objMember->redirect('index.php?error');
			}
		}
	}catch(PDOException $e){
		echo $e->getMessage();
	}
}

Just to clarify, I am building this on a local machine while I am developing the application. However, in the future, this will end up being used as a real application as 4 computers will be accessing this database at the same time.

Also, I removed the delete column entirely (for now) as I will need to figure out a way to authenticate the delete and edit processes. I will look into how to do this when the time comes.

1 Like

That line

if($objMember->update($name, $residential_address, $mailing_address, 
     $precinct, $age, $ethnicity, $gender, $party, $race, $phone)){

might give you a problem because:

public function update($name, $residential_address, $mailing_address, 
     $precinct, $age, $ethnicity, $gender, $party, $race, $phone, $id){
1 Like