-2

I am a self taught CS student and I am working on a job listing website. I am not working on the backend page on the site where the user can add or remove any job from the website. Every jobs has different properties and I created 3 mySQL tables to store them. One of the table is keywords and has 2 columns job_id which is a foreign key from the job_table and keyword. So a job can have multiple keywords.

how the backend looks like

database

So everytime I am adding a new keyword, a new li is generated. Right now the array is located at the input level name="keywords[]" but the size is always equal to zero. However, when I am checking the number of li items directly on the Google Chrome console, it is correct. I am struggling with this problems for days, If someone can help me to fix it it should be nice.

add-jobs.php

<form id="new-listing" action="add-database.php" method="POST">
    </p>
        <div class="add">
            <label for="keywords">Keywords : </label>     
            <input type="text" class="keywords" name="keywords[]" value=""/>   
            <button class="add-keyword">Add</button>               
        </div>
            <ul class="list-keywords">
                //Here goes new where the user click on the button .add-keyword <li></li>
            </ul>
    <p>
</form>

add-database.php

<?php
    require("../config/db.php");
    require("add-jobs.php");

    $link = mysqli_connect("localhost","root","","benoit"); 
    $keywords = $_POST["keywords"];

    mysqli_query($link,"INSERT INTO keywords (`keywords`)
    VALUES ('$keywords')") 
    or die(mysqli_error($link));      
    ?>

add-jobs.js

const keywords = document.querySelector(".keywords");
const addKeyword = document.querySelector(".add-keyword");
const listKeywords = document.querySelector(".list-keywords");    

const generateTemplate = (word, location) => {
 const html = `
    <li class="individualKeyword"><span>${word}</span>
    <i class="far fa-times-circle delete"></i>
    </li>` ;

 location.innerHTML += html;
};

addKeyword.addEventListener("click", (e)=>{
    e.preventDefault();
    const word = keywords.value.trim();
    console.log(word);
    keywords.value = "";
    generateTemplate(word, listKeywords);
});


listKeywords.addEventListener("click", e =>{
    if(e.target.classList.contains("delete")){
        e.target.parentElement.remove();
   };

}); });

I also know the code is not secured yet but I wanna learn the basics first and then protect it against SQL injections.

1 Answers1

1

Firstly, if you are only submitting one keyword at a time in your form, you don't need to make the name of the input an arrayed name, so use name="keyword" instead of name="keyword[]" since that will generate an array.

<form id="new-listing" action="add-database.php" method="POST">
    <div class="add">
        <label for="keywords">Keywords : </label>
        <input type="text" class="keywords" name="keywords" value=""/>
        <button class="add-keyword">Add</button>               
    </div>
    <ul class="list-keywords">
        <li></li>
    </ul>
</form>

For the backend, I would recommend either using the object version of mysqli or switching to PDO. Either are more intuitive than the functional version of mysqli. In my opinion PDO is better but since you are using mysqli, I will show that instead:

<?php
require("add-jobs.php");
$con = new mysqli("localhost","root","","benoit");
// It's wise to check that this is being sent
if(!empty($_POST["keywords"])) {
    // Trim the keywords to make sure all the front and back spaces are out
    // Remove any possible HTML as well
    $keywords = strip_tags(trim($_POST["keywords"]));
    if(empty($keywords))
        throw new \Exception("Keyword can not be empty.");
    // Prepare the sql
    $query = $con->prepare("INSERT INTO keywords (`keywords`) VALUES (?)");
    // Bind the keyword parameter
    $query->bind_param('s', $keywords);
    // Execute the query
    $query->execute();
    // Release
    $query->close();
}

For multiple keywords, keep keywords[]:

<form id="new-listing" action="add-database.php" method="POST">
    <div class="add">
        <label for="keywords">Keywords : </label>
        <input type="text" class="keywords" name="keywords[]" value="" />
        <input type="text" class="keywords" name="keywords[]" value="" />
        <input type="text" class="keywords" name="keywords[]" value="" />
        <button class="add-keyword">Add</button>               
    </div>
    <ul class="list-keywords">
        <li></li>
    </ul>
</form>

Backend would be:

<?php
require("add-jobs.php");
$con = new mysqli("localhost","root","","benoit");
// It's wise to check that this is being sent
if(!empty($_POST["keywords"])) {
    // Loop through the array and remove spaces and html
    $keywords = array_filter(array_map(function($v){
        return strip_tags(trim($v));
    }, $_POST['keywords']));
    if(empty($keywords))
        throw new \Exception("Keyword can not be empty.");
    // Prepare the sql
    $query = $con->prepare("INSERT INTO keywords (`keywords`) VALUES (".implode('), (', array_fill(0, count($keywords), '?')).")");
    // Bind the keyword parameter
    $query->bind_param(implode('', array_fill(0, count($keywords), 's')), ...$keywords);
    // Execute the query
    $query->execute();
    // Release
    $query->close();
}
Rasclatt
  • 12,498
  • 3
  • 25
  • 33