I've always found myself creating two separate php files/scripts for adding a certain data and editing this data. These files weren't that much different, so I figured there should be a way how to make them into one file.
Here I'll present a very simple example to illustrate my point:
add.php:
<?php
$title = $_POST['title']; // ignore the unescaped data, this is a simple example
$text = $_POST['text'];
mysqli_query($connection,
"INSERT INTO `articles` (`title`, `text`) VALUES ('$title', '$text')");
echo'
<form>
<input type="text" name="title" value="'.$_POST['title'].'" />
<input type="text" name="text" value="'.$_POST['text'].'" />
<input type="submit" value="Add" />
</form>
';
?>
edit.php:
<?php
$id = $_GET['id'];
$title = $_POST['title']; // ignore the unescaped data, this is a simple example
$text = $_POST['text'];
// save data
mysqli_query($connection,
"UPDATE `articles` SET `title` = '$title', `text` = '$text'
WHERE `id` = $id");
// get current data
$q = mysqli_query($connection,"SELECT * FROM `articles` WHERE `id` = $id");
$d = mysqli_fetch_array($q);
$title = $d['title'];
$text = $d['text'];
echo'
<form>
<input type="text" name="title" value="'.$title.'" />
<input type="text" name="text" value="'.$text.'" />
<input type="submit" value="Add" />
</form>
';
?>
As you can see, the add and edit forms/codes are very similar, except that:
add inserts the data, while edit updates it
add inserts $_POST values into the form (if there's an error, so that the submitted data remains in the form, while edit inserts the current database values into the form (after the save is complete and the page refreshes, so that the form has the current db values)
Can these two somehow be merged into one file/code, so that if I want to add/change the form values, I don't need to edit two files separately, but will change the form only once?
You can use a INSERT ON DUPLICATE KEY UPDATE which roughly gave you :
<?php
$id = $_GET['id'];
$title = $text = '';
if ($_POST)
{
$title = $_POST['title'];
$text = $_POST['text'];
// save data
$query = "INSERT INTO `articles` (`id`, `title`, `text`)
VALUES ('$id', '$title', '$text')
ON DUPLICATE KEYS UPDATE title = title, text = text"
mysqli_query($connection, $query);
}
else if ($id)
{
// get current data
$q = mysqli_query($connection, "SELECT * FROM `articles` WHERE `id` = $id");
$d = mysqli_fetch_array($q);
$title = $d['title'];
$text = $d['text'];
}
echo '
<form>
<input type="text" name="title" value="'.$title.'" />
<input type="text" name="text" value="'.$text.'" />
<input type="submit" value="Add" />
</form>';
If it's a POST and no $id present : a new row is inserted just like an INSERT.
If it's a POST and an $id is present : if $id already exist in the table than the row is updated otherwise it's an INSERT.
If you only have an $id : show the form with existing data in it.
If it's not a POST and $id isn't populated : show an empty form.
You could use a combination of GET and POST parameters do achieve what you want. Use the GET parameters to distinguish between edit and add, i.e. /post?action=add or /post?action=edit. Based on the value of $_GET['action'] you'd know whether to render an empty form to add a post or to populate the form in with data from the DB. Then you could have a hidden field in your form, which you'd fill in with the value of $_GET['action'] and so you'd be able to know whether to INSERT or UPDATE when processing the form after submitting it.
It might be worth though to start using some framework, i.e. CakePHP, CodeIgniter, Zend Framework, etc.
I tend to make an interface for inserting and updating data which has only one method for inserting and updating. The key point for that to work is the user form that is being submitted must contain the id of the row being updated.
public method save( Object obj )
if obj.id is in database
query = "update table set attrA = obj.a, attrB = obj.b where id=obj.id"
else if obj.id < 1
query = "insert into table (a,b,c) values (obj.a,obj.b,obj.c)"
This implies that when you create a new object to be submitted, it must have id initialized to 0 or -1 (1 is the first key row for a table with int primary keys). Likewise, a form in a html file must have an <input type=hidden value=row.id name=DBID> that is populated either with a default value (null, 0, -1) or a valid id of the object being edited.
Essentially this means that the user may update arbitrary rows in the table, but granted they have authenticated themselves, this should not be a problem. Also, it is usually enough to know that the id > 0 to to an INSERT, and UPDATE otherwise. It is not necessary to verify that the id being submitted is in the database table, because when you insert you do not set the id, but rather let the DB auto-increment the primary key.
update
wow so many silly typos after only 3 beers. I hope this is readable
Here's an idea how it should look like using OOP (in my opinion).
Let's assume you have some class that represents form element called FormElement.
Then you have some generic form that should support what? Let's assume MVC:
displaying itself
adding elements
setting default values
parsing request values
getting values
validating values
So you'll build yourself an interface like
interface IForm {
public function Display();
public function AddElement( FormElement $element);
public function SetValues( array);
public function FetchPostValues();
public function GetValues();
public function Validate();
}
Then, what's common for both those forms (let's say that you want to prohibit change of email)? Everything except FetchPostValues()
So you'll build a class with one pure virtual method which will do everything that is similar:
abstract class FormArticle implements IForm {
// All methods implemented except FetchPostValues
abstract public function FetchPostValues();
}
And then just build two small classes that will define how to fetch post data:
class FormArticleEdit extends FormArticle {
public function FetchPostValues(){
if( isset( $_POST['email'])){
throw new Exception('What are you trying to achieve?');
}
// ...
}
}
And one more tip (two actually):
Implement abstract class like FormAbstract that will provide all generic methods like AddElement(), Display(). This will save you copying of those general methods every time, but will still provide you with ability to start from scratch (when using database or so directly to cache items).
Rather use framework that already has model for reusing forms (Zend is my personal favorite).
Related
I am currently constructing a component in Joomla and I have to get the values of the form field that user submitted. After that, I have to insert the values into database. The problem is that I just able to insert the $inventory_id but I can't get the value of the form field. Thank you.
<?php
$input = JFactory::getApplication()->input;
$formData = new JRegistry($input->get('jform', '', 'array'));
$name = $formData->get('inventory_name', 'test');
$leadtime = $formData->get('leadtime', null);
$max_lead = $formData->get('max_lead', null);
$daily_usage = $formData->get('daily_usage', null);
$max_usage = $formData->get('max_usage', null);
//formula to calculate reorder point
$lead_time_demand = $leadtime * $daily_usage;
$safety_stock = ($max_usage * $max_lead) - ($daily_usage * $leadtime);
$reorder_point = $lead_time_demand + $safety_stock;
if (empty($this->item->id)){ //For new added item
$inventory_id = $row['AUTO_INCREMENT'];
$sql_new = "INSERT INTO wer_reorder_point_list (inventory_id, inventory_name, reorder_point)
VALUES ('$inventory_id', '$name', '$reorder_point');";
mysqli_query($con,$sql_new);
}
?>
You never declare $row in this code, so what is $inventory_id = $row['AUTO_INCREMENT']; supposed to do?
If your database is configured to autoincrement inventory_id, then you don't need that column in the insert statement. So you could do this:
$sql_new = "INSERT INTO wer_reorder_point_list (inventory_name, reorder_point)
VALUES ('$name', '$reorder_point');";
and it will automatically fill that column with the next integer.
By the way, you should also use prepared statements, especially since you have user input, which could be a security problem.
You don't insert an autoincremented id directly using the form data, you let the database take care of that. If you tried to insert it you could easily end up with a race condition given that in a web application such as Joomla there could be many users attempting to insert new lines with the same id at the same time. This is why your form does not contain an inventory_id value.
If you want to pass a hidden ( from the user) value to the POST you need to include a hidden field with that value in your form. However, as stated in the first paragraph, you would not use that for a unique ID.
I have a problem with default value for $_POST[];
So i have a html form with textboxes and the informations is sent to a php script. The php script has a sql query that is being sent to my database. But if my textbox in html form is empty the query doesnt have a value. So i want to set my post to a default value 0 so it returns a value atleast.
So here is an example of html form (This is not my actuall script. Just an example.
<form action="testscript.php" method="POST">
<input type="id" name="ID"/>
<input type="text" name="test"/>
<input type="submit" value="Send"/>
</form>
Ok so this script will send both id and test textboxes will always have a number value. And it sends the information to testscript.php
Here is testscript.php example
$conn = mysqli_connect('host', 'dbuser', 'dbpass', 'dbname');
$id = $_POST['id'];
$test = $_POST['test'];
$sql = "INSERT INTO test_table (id, test) VALUES ($id, $test)";
if (mysqli_query($conn, $query)) {
echo "Success";
} else {
echo "Failed" . mysqli_error($conn);
}
Alright so now if i submit my html form to php script without inserting any text to the textboxes the query will look like this
INSERT INTO test_table (id, test) VALUES ( , )
But the query should be like this
INSERT INTO test_table (id, test) VALUES (0, 0)
So. I know i can use value attribute in the html tag but then the value will be visible in the textbox and i dont want that.
And i know i can do an if statment to make a default value like this
if (isset($_POST['test'])) {
$test = $_POST['test'];
} else {
$test = 0;
}
But now the problem is that i would have to do that if statment for every textbox and my html form have more than 100 textboxes. So i dont want to make an if statment for every textbox because then my script will be way to big and it will take hours.
So is there any way to set a default value for all the textboxes without using if statment in php or value attribute in html form?
I know it seems like a pain but you MUST check that all inputs are valid. You can simplify the amount of code by using a ternary operator like this.
$id = isset($_POST['id']) ? $_POST['id'] : 0;
$test = isset($_POST['test']) ? $_POST['test'] : 0;
....
And no, it won't take hours even with hundreds of them.
To make this slightly less painful to code you can use the power of looping with PHP's variable variables
The most painful part will be creating an array with all your field names
$fields = array('id', 'test', 'extra', 'more', ..., 'one_hundred');
Then loop through that array creating variable names and at the same time escaping the strings - if they are there - otherwise set a value of 0 (zero). You might want/need to set this to "" (empty string)
foreach($fields as $field_name)
{
${$field_name} = isset($_POST[$field_name]) ? mysqli_real_escape_string($conn, $_POST[$field_name]) : 0;
}
You now have the variables $id, $test, $extra, $more, ...., $one_hundred available for your use.
If your checkboxes have unique names, then you'll need to check them on the server side to see if they actually have values in them one by one by using the ternary
isset($_POST["test"]) ? $_POST["test"] : 0
However, if your checkboxes are in array form:
<input type="checkbox" name="courses[]" value="1">
<input type="checkbox" name="courses[]" value="2 >
Then you could do the following:
foreach($_POST['courses'] as $course) {
echo $course; // etc etc etc
}
You can also set database defaults.
Another note, your code is prone to SQL injection. Although the question you have might simply be an example, you might just keep in mind there are better and safer ways of querying a database see PDO connections.
You can easily use null check and define your default value like this :
$name = $_POST['name'] ?? 'John';
in my case the default value is John if the name is not defined. It gives the same result like this :
$name = isset($_POST["name"]) ? $_POST["name"] : 'John';
I'm trying to update a table of dishes with a new entry and cross reference it to an existing table of ingredients. For each dish added, the user is required to assign existing ingredients and the volume required on multiple lines. On submission, the Dish should be entered into the table 'Dishes' and the assigned ingredients should be entered into the 'DishIng' linked tabled.
My tables are set like this:
Table: "Dishes" Columns: DishID, DishName, Serves, etc...
Table: "DishIng" Columns: DishID, IngID, Volume
Table: "Ingredients" Columns: IngID, IngName, Packsize etc...
HTML:
DishID:
Name:
Catagory :
Serving:
SRP:
Method :
Source :
IngID:
Volume:
<li>IngID: <input type="text" name="IngID"></li>
<li>Volume: <input type="text" name="Volume"></li>
<li>IngID: <input type="text" name="IngID"></li>
<li>Volume: <input type="text" name="Volume"></li>
</ul>
<input type="submit">
</form>
Any suggestions for dymanically adding a row of ingredients in HTML would be very welcome.
PHP:
<?php
require_once('db_connect.php');
$DishID = mysqli_real_escape_string($con, $_POST['DishID']);
$DishName = mysqli_real_escape_string($con, $_POST['DishName']);
$DishCatID = mysqli_real_escape_string($con, $_POST['DishCatID']);
$Serving = mysqli_real_escape_string($con, $_POST['Serving']);
$SRP = mysqli_real_escape_string($con, $_POST['SRP']);
$Method = mysqli_real_escape_string($con, $_POST['Method']);
$SourceID = mysqli_real_escape_string($con, $_POST['SourceID']);
$IngID = mysqli_real_escape_string($con, $_POST['IngID']);
$Volume = mysqli_real_escape_string($con, $_POST['Volume']);
$array = array('$DishID', '$IngID', '$Volume');
$sql="INSERT INTO Dishes (DishID, DishName, DishCatID, Serving, SRP, Method, SourceID)
VALUES ('$DishID', '$DishName', '$DishCatID', '$Serving', '$SRP', '$Method', '$SourceID')";
$sql2 = "INSERT INTO DishIng (DishID, IngID, Volume) VALUES ('$DishID', '$IngID', '$Volume')";
$it = new ArrayIterator ( $array );
$cit = new CachingIterator ( $it );
foreach ($cit as $value)
{
$sql2 .= "('".$cit->key()."','" .$cit->current()."')";
if( $cit->hasNext() )
{
$sql2 .= ",";
}
}
if (!mysqli_query($con,$sql)) {
die('Error: ' . mysqli_error($con));
}
echo "1 record added";
if (!mysqli_query($con,$sql2)) {
die('Error: ' . mysqli_error($con));
}
echo "records added";
require_once('db_disconnect.php');
php?>
Currently on submit, it only updates the 'Dishes' table and gives me this message: '1 record addedError: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near '('0','$DishID'),('1','$IngID'),('2','$Volume')' at line 1'
A high level of how you do this (although there are plenty of ways, this is just one with straight DB/PHP/HTML):
Your php will create a form to input the dish fields from the user.
Your php will then pull all of the ingredients from the ingredient table for that dish
Your php will iterate through the results returned from that query and for each result will:
Create a checkbox type input for the ingredient, and
Create a Text field type input for the ingredient and.
Create a Hidden field with the IngID
Once the user submits the form:
Your php will insert the to the dish table based on the dish fields on the form submitted.
Your php will iterate through the ingredients fields from the form submission and with each one will:
Determine if that ingredients checkbox is checked. If it is it will:
Insert into the DishIng table using the Hidden IngID field and the Volume field
Essentially, there is are two FOR loops. One to loop through the initial list of ingredients to make your form, and a second to loop through the form that is submitted. Each ingredient with a check mark will need it's own SQL INSERT statement to be added into the DishIng table.
How to iterate through SQL results in php: Iterate through Mysql Rows in PHP
How to iterate through Form fields in php: PHP loop through array of HTML textboxes
Because you are taking in user input and sticking it into a MySQL insert query, you'll also want to make sure you sanitize the inputs before submitting the query so you avoid some evil-doer from pulling some SQL injection and killing your DB.
Lastly: This is a pretty vague question so I anticipate it will be downvoted, and my response is also pretty vague. I only wrote it because it touches on an overall idea that is pretty common and is difficult to ask in a succinct way if you are just getting started with web development. You will probably get stuck quite a few times while writing this. Try narrowing down your problem to a single issue and take that issue/question to stackoverflow. You can also hit up Google, since everything you will need to do here has been written about on forums, blogs, wikis, and Q&A sites by a gajillion other folks.
Hi does anyone knows how to avoid/stop duplicate insertion for php and html? Whenever I refresh, the same data repeats which is not what I want. Is there anything that I can change from here? I heard that adding UNIQUE INDEX can avoid/stop it. Maybe it works, but I place it wrongly which makes it unable to work. Any help? Thanks in advance!!! Will really appreciate it!
<?php
session_start();
include("Validation.php");
$connect=mysqli_connect("localhost","root","","jailbird");
if(mysqli_error($connect))
{
die("Could not connect.");
}
if(isset($_POST["insert_click"]))
{
//Bookingid is auto increment, therefore no need
//$Bookingid=$_POST["BookingID"];
$Prisonerid=$_SESSION['Prisonerid'];
$Visiting_method=$_POST["VisitingMethod"];
$Visiting_location=$_POST["VisitingLocation"];
$Date=$_POST["Date"];
$Time=$_POST["Time"];
$query=$connect->prepare("insert into Booking(PrisonerID, VisitingMethod, VisitingLocation, Date, Time) values (?,?,?,?,?)");
$query->bind_param('sssss', $Prisonerid, $Visiting_method, $Visiting_location, $Date, $Time);
$query->execute();
}
$query=$connect->prepare("select * from booking WHERE Prisonerid=?");
$query->bind_param('s',$_SESSION['Prisonerid']);
$query->execute();
$query->bind_result($Bookingid, $Prisonerid, $Visiting_method, $Visiting_location, $Date, $Time);
while($query->fetch())
{
echo "<tr>";
//echo "<td width=60>".$Bookingid."</td>";
echo "<td>$Prisonerid</td>";
echo "<td>$Visiting_method</td>";
echo "<td>$Visiting_location</td>";
echo "<td>$Date</td>";
echo "<td>$Time</td>";
echo "</tr>";
}
?>
Here is a small class I wrote (not tested)
<?php
class FormID {
private $lastFormID = "";
private $newFormID = "";
function __construct(){
$this->lastFormID = $_SESSION['__frmid__'];
$_SESSION['__frmid__'] = uniqid('sm');
$this->newFormID = $_SESSION['__frmid__'];
}
public function isFormDataValid(){
return (isset($_POST['__frmid__']) && $_POST['__frmid__']==$this->lastFormID);
}
public function FromIDHTML(){
return "<input type=\"hidden\" name=\"__frmid__\" value=\"{$this->newFormID}\"/>";
}
}
?>
You can use it like this
<?php
$frmid = new FormID();
if ($frmid->isFormDataValid()){
//do your insert here
}
?>
<form method="post">
<?php echo $frmid->FromIDHTML(); ?>
<input .... />
</form>
Edit: Here is how to use this in your code
change
if(isset($_POST["insert_click"]))
{
to
$frmid = new FormID();
if(isset($_POST["insert_click"]) && $frmid->isFormDataValid())
{
And in the file where you generate the HTML form do something like this
<form method="post">
<?php $frmid = new FormID(); echo $frmid->FromIDHTML(); ?>
<!--Below is your form with all the fields -->
<input type="text" name="VisitingMethod" />
</form>
Note i have just added one line in the form <?php $frmid = new FormID(); echo $frmid->FromIDHTML(); ?>
let me know if you have any problems.
You can make the PrisonerID a primary key in your MySql table that way no duplicates will be allowed.
Like you've already said, you need to add a UNIQUE constraint to a field in your table you know can't have two values. When you say maybe it works it means to haven't you really tried that method. And we can't help unless you give more details about how you tried that and what went wrong.
For the UNIQUE constraint to work, you need to choose which fields in your table uniquely represent each row.
For example, let's assume the PrisonerId uniquely represent each row. Then when your create the table you need to add the UNIQUE contraint to the PrisonerId field as follows:
CREATE TABLE `Booking` (
`PrisonerId` int(10) NOT NULL,
`VisitingMethod` varchar(100) NOT NULL,
# Put other fields here #
UNIQUE KEY `uc_PrisonerId` (`PrisonerId`)
) ENGINE=InnoDB;
You run that query when creating the table, or you can ALTER the table to add the new contraint or use phpMyAdmin/MySQL Workbench or whatever else method you prefer and when you insert a new record MySQL will make sure it respects the new constraint.
Also, note that you can still insert duplicate can't insert duplicate rows but can silence error messages if you want using the IGNORE keyword in your query. See insert documentation
The other approach, and expensive, would be to check if the new records aren't in the database yet. If they are, don't insert them, else do.
Finally consider redirecting from the form handler (the url in the action of the form) after the form submission. See here
I'm just curious and was wondering how you guys handle it if you want to use the same html form and as far as possible the same php code to create and update an item.
Example:
On one page you can create a database entry with name, email address and age.
On a different(?) page you see the form fields filled with your data and you can edit and save it.
I have my ways to accomplish this using pretty much the same code - but I'm hoping to learn something here. So how would you handle this task?
Thanks & Cheers, sprain
Pretty easily - if an ID of an existing item (which the user is authorised to edit) is supplied in the query string, then it's an edit operation.
If no ID is supplied in the query string, it's a create operation.
The fields are pre-populated based on the existing values from the database if it's an edit operation, or based on default values or empty strings if it's a create operation.
The way I see it is that reusing identical markup for form between create/edit works for some cases, but not for all. I find that forms -- though they may map to the same database table -- are really defined by their context. For example, if you had a 'users' table, you might have a 'create' form with username, email, password, but after that user exists you want them to retain their identity on their site, so the username field would not appear in an 'edit' context. I'm classically a PHP developer, but I have come to appreciate the approach that Django takes, where you create a model (table) that defines the basic validation for each field and you can create as many forms as you that build off of, or modify/extend from that definition. If you're writing from scratch, you'll probably find it practical to make your validation methods very portable and/or find ways to make your form fields context-sensitive.
That's the way I always do it now. Are you using an MVC system at all? I use one controller with two different actions (urls = person/new + person/edit/xxxx_id).
the code is then something like:
function new()
errors = []
if (get)
data = blank_record()
elseif (post)
data = posted_data
if (create(data))
redirect_to_listing()
else
errors = describe_errors
show_form(data, errors)
function edit()
errors = []
if (get)
data = get_from_db(id)
elseif (post)
data = posted_data
if (save())
redirect_to_listing()
else
errors = describe_errors
show_form(data, errors)
Note that once it gets to the form there's always an object called data that the form can render, it may be blank, from the db, or posted data. Either way it should always be the same format.
The reason I split new and edit is that I find that often enough they are actually quite different in their behaviours and the load and save steps.
I guess this is not the right answer but it might be interesting for you anyway.
There is an orm project called doctrine:
http://www.doctrine-project.org/projects/orm/1.2/docs/en
// User Id might be an existing id, an wrong id, or even empty:
$user_id = 4;
$user_id = null;
// Fetch the user from the database if possible
$user = Doctrine::getTable('Model_User')->find($user_id);
// If there was no record create a new one
if ( $user === false )
$user = new Model_User();
// Change some data
$user->title = $newValue;
// Perform an update or an insert:
$user->save();
As you see you don't have to care about sql.
Doctrine does that for you and your code becomes easier to read and to debug.
Yes, that's the only acceptable solution.
Here is a little example of CRUD application which store the input form in a template:
<?
mysql_connect();
mysql_select_db("new");
$table = "test";
if($_SERVER['REQUEST_METHOD']=='POST') { //form handler part:
$name = mysql_real_escape_string($_POST['name']);
if ($id = intval($_POST['id'])) {
$query="UPDATE $table SET name='$name' WHERE id=$id";
} else {
$query="INSERT INTO $table SET name='$name'";
}
mysql_query($query) or trigger_error(mysql_error()." in ".$query);
header("Location: http://".$_SERVER['HTTP_HOST'].$_SERVER['PHP_SELF']);
exit;
}
if (!isset($_GET['id'])) { //listing part:
$LIST=array();
$query="SELECT * FROM $table";
$res=mysql_query($query);
while($row=mysql_fetch_assoc($res)) $LIST[]=$row;
include 'list.php';
} else { // form displaying part:
if ($id=intval($_GET['id'])) {
$query="SELECT * FROM $table WHERE id=$id";
$res=mysql_query($query);
$row=mysql_fetch_assoc($res);
foreach ($row as $k => $v) $row[$k]=htmlspecialchars($v);
} else {
$row['name']='';
$row['id']=0;
}
include 'form.php';
}
?>
form.php
<form method="POST">
<input type="text" name="name" value="<?=$row['name']?>"><br>
<input type="hidden" name="id" value="<?=$row['id']?>">
<input type="submit"><br>
Return to the list
</form>
list.php
Add item
<? foreach ($LIST as $row): ?>
<li><?=$row['name']?>
<? endforeach ?>
Of course, some fancy form constructor, like HTML_QuickForm2 coud be used instead of plain HTML template - you know its constant programmer's hunger not to repeat himself, even in naming an HTML field, field value and error key :)
But personally I prefer plain HTML.