I have 2 tables in the database, artists (username and password) and artistcard (contains info about the artist with one of the columns being artist_id to link to the artists table).
Now I want the users to be able to update the information displayed in the card:
Currently I get firstname, lastname, genre and location from the form that they can submit:
<?php if (isset($_POST['submit'])) { // Form has been submitted.
$genre = trim($_POST['genre']);
$location = trim($_POST['location']);
$firstname = trim($_POST['firstname']);
$lastname = trim($_POST['lastname']);
$artistcard = new Artistcard();
$artistcard->first_name = $firstname;
$artistcard->last_name=$lastname;
$artistcard->genre = $genre;
$artistcard->location = $location;
$artistcard->artist_id = $_SESSION['artist_id'];
$artistcard->update();
}
Now I want the update function to go through the fields where artist_id in the artistcard table matches id in the artist table (or session id). For this I have in the Artistcard class:
public function update() {
global $database;
$attributes = $this->sanitized_attributes();
$attribute_pairs = array();
foreach($attributes as $key => $value) {
$attribute_pairs[]= "{$key}='{$value}'";
}
// - UPDATE table SET key='value', key='value' WHERE condition
$sql = "UPDATE ".self::$table_name." SET ";
$sql .= join(", ", $attribute_pairs);
$sql .= " WHERE artist_id=". $database->escape_value($this->artist_id);
$database->query($sql);
return ($database->affected_rows() == 1) ? true : false;
}
which returns Database Query Failed. I'm guessing the SQL is not correct? I have an almost identical CREATE method, which works fine:
public function create(){
global $database;
$attributes = $this->sanitized_attributes();
$sql = "INSERT INTO ".self::$table_name." (";
$sql .= join(",",array_keys($attributes));
$sql .= ") VALUES ('";
$sql .= join("', '",array_values($attributes));
$sql .= "')";
if ($database->query($sql)) {
$this->id = $database->insert_id();
return true;} else {return false;}
}
Related
I'm fairly new to OOP in PHP. I'm trying to update the value of an item in an array that is generated by a loop in its parent class. In my code the class DatabaseObject creates an attributes array with all of the table field name and value pairs. The contents of the array are used to create a SQL query to write to the database. The issue that I'm trying to resolve is that I need to update the attributes['hashed_password'] item with an encrypted password from the child User class. I'm not quite sure how I would update that array item so that the hashed password is submitted to the database instead of what came through a form submission.
class DatabaseObject {
public function create(){
global $db;
static::$attributes = [];
foreach (static::$db_fields as $field) {
if(property_exists($this, $field)){
$attributes[$field] = $this->$field;
}
}
$sql = "INSERT INTO " . static::$table_name . " (";
$sql .= join(", ", array_keys($attributes));
$sql .= ") VALUES ('";
$sql .= join("', '", array_values($attributes));
$sql .= "')";
$result = mysqli_query($db, $sql)
}
}
class User extends DatabaseObject {
protected static $table_name="users";
protected static $db_fields = array("user_id", "username", "hashed_password", "email");
public $user_id;
public $username;
public $hashed_password;
public $email;
self::attributes['hashed_password'] = password_hash($this->attributes['hashed_password'], PASSWORD_BCRYPT);
}
Any help would be appreciated.
The solution that worked for me was just to override the create function in the User object and manually update the array with the hashed password, so the new User object became:
class User extends DatabaseObject {
public function create(){
global $db;
static::$attributes = [];
foreach (static::$db_fields as $field) {
if(property_exists($this, $field)){
$attributes[$field] = $this->$field;
}
}
$attributes['hashed_password'] = password_hash($attributes['hashed_password'], PASSWORD_BCRYPT);
$sql = "INSERT INTO " . static::$table_name . " (";
$sql .= join(", ", array_keys($attributes));
$sql .= ") VALUES ('";
$sql .= join("', '", array_values($attributes));
$sql .= "')";
$result = mysqli_query($db, $sql)
}
}
}
Not sure if that's the most efficient way to do it, but it worked.
I have this in my functions.php file
function getUserOrders($userId){
global $conn;
$query = "SELECT * ";
$query .= "FROM orders ";
$query .= "WHERE userid=" . $userId . " ";
$odrset = mysqli_query($conn, $query);
while ($odr = mysqli_fetch_assoc($odrset)){
return $odr;
}
}
What I neeed to do in my orders.php file is display specific fields and their values from the returned $odr array as this snippet suggests
$userId = sql_prep($_SESSION['userid']) ;
getUserOrders($userId);
echo $odr['title'].$odr['orderid'].'<br>'
I am only able to do it in the functions.php file...
function getUserOrders($userId){
global $conn;
$query = "SELECT * ";
$query .= "FROM orders ";
$query .= "WHERE userid=" . $userId . " ";
$odrset = mysqli_query($conn, $query);
confirm_query($odrset);
while ($odr = mysqli_fetch_assoc($odrset)){
echo $odr['title'].$odr['orderid'].'<br>';
}
}
..and calling it in my orders.php file like so:
$userId = sql_prep($_SESSION['userid']) ;
getUserOrders();
which is not good since i need to recycle the function somewhere else and display different fields and their values. So I need to have $odr returned as an array in my order.php
Store it as an array and then return the array.
function getUserOrders($userId){
global $conn;
$query =
"SELECT *
FROM orders
WHERE userid= ?";
$odrset = mysqli_prepare($conn, $query);
mysqli_stmt_bind_param($odrset, 'i', $userId);
mysqli_stmt_execute($odrset);
while ($odr = mysqli_fetch_assoc($odrset)){
$return[] = $odr;
}
return $return;
}
I've updated your mysqli connection to use a parameterized query with prepared statement. You can read more about these here, http://php.net/manual/en/mysqli.quickstart.prepared-statements.php. This is the preferred approach than escaping.
Later usage...
$orders = getUserOrders($_SESSION['userid']);
foreach($orders as $order) {
echo $order['title'] . $order['orderid'];
}
You may not need the sql_prep function with this approach, I'm not sure what that did. Your questions code didn't pass the userid to the function so I don't think that was your exact usage.
mysqli_fetch_assoc only returns one record at a time so you need to store the results inside an array and return the array from the function:
// functions.php
function getUserOrders($userId){
global $conn;
$query = "SELECT * ";
$query .= "FROM orders ";
$query .= "WHERE userid=" . $userId . " ";
$odrset = mysqli_query($conn, $query);
$results = array();
while ($odr = mysqli_fetch_assoc($odrset)){
$results[] = $odr;
}
return $results;
}
// in your orders file
$userid = sql_prep($_SESSION['userid']);
$orders = getUserOrders($userid);
foreach ($order as $orders) {
echo $order['title']. $order['orderid'] . '<br>';
}
I create a function to find all firstname and lastname in my database all I want if that data is already exist I just want to output, error message
my question is how to create a function to check if data is already exist?
this is my function to find all data of firstname and lastname.
function find_student_by_firstname($firstname){
global $con;
$safe_firstname = prep($firstname);
$sql = "SELECT * ";
$sql .= "FROM studeprofile ";
$sql .= "WHERE FirstName = '{$safe_firstname}' ";
$sql .= "LIMIT 1";
$student_set = mysqli_query($con, $sql);
confirm_query($student_set);
if($student = mysqli_fetch_assoc($student_set)){
return $student;
} else {
return null;
}
}
function find_student_by_lastname($lastname){
global $con;
$safe_lastname = prep($lastname);
$sql = "SELECT * ";
$sql .= "FROM studeprofile ";
$sql .= "WHERE LastName = '{$safe_lastname}' ";
$sql .= "LIMIT 1";
$student_set = mysqli_query($con, $sql);
confirm_query($student_set);
if($student = mysqli_fetch_assoc($student_set)){
return $student;
} else {
return null;
}
}
this is my current function to check if data is already exist.
function match_fistname_lastname($lastname, $firstname){
$student_firstname = find_student_by_firstname($lastname);
if($student_firstname){
find_student_by_lastname($lastname);
} else {
return false;
}
}
If you mean by "data is already exist" that a person is in the database that matches to firstname and lastname, you don't have to execute two queries.
Use the and in mysql like this:
function find_student($firstname, $lastname){
global $con;
$safe_firstname = prep($firstname);
$safe_lastname = prep($lastname);
$sql = "SELECT * ";
$sql .= "FROM studeprofile ";
$sql .= "WHERE FirstName = '{$safe_firstname}' and LastName = '{$safe_lastname}' ";
$sql .= "LIMIT 1";
$student_set = mysqli_query($con, $sql);
confirm_query($student_set);
if($student = mysqli_fetch_assoc($student_set)){
return $student;
} else {
return null;
}
}
I am using the code below to duplicate a event record in my database, problem is I am trying to also duplicate any child records (i.e. event services). I need it to copy all "event services" from the eventservices table as well as update the eventid during copy to the newly copied id record. Any help would be appreciated. Thanks.
Note: The eventservices table has a eventid field which matches the id of the event.
$table = 'events';
$id_field = 'id';
$id = $_GET['eventid'];
DuplicateMySQLRecord($table, $id_field, $id);
function DuplicateMySQLRecord($table, $id_field, $id) {
include_once 'db_connect.php';
// load the original record into an array
$result = mysql_query("SELECT * FROM {$table} WHERE {$id_field}={$id}");
$original_record = mysql_fetch_assoc($result);
// insert the new record and get the new auto_increment id
mysql_query("INSERT INTO {$table} (`{$id_field}`) VALUES (NULL)");
$newid = mysql_insert_id();
// generate the query to update the new record with the previous values
$query = "UPDATE {$table} SET ";
foreach ($original_record as $key => $value) {
if ($key != $id_field) {
$query .= '`'.$key.'` = "'.str_replace('"','\"',$value).'", ';
}
}
$query = substr($query,0,strlen($query)-2); # lop off the extra trailing comma
$query .= " WHERE {$id_field}={$newid}";
mysql_query($query);
// return the new id
return $newid;
}
Please use below code.I have not compile this code so test before use.
<?php
include_once 'db_connect.php';
$table = 'events';
$id_field = 'id';
$id = $_GET['eventid'];
DuplicateMySQLRecord($table, $id_field, $id);
function DuplicateMySQLRecord($table, $id_field, $id) {
// load the original record into an array
$result = mysql_query("SELECT * FROM {$table} WHERE {$id_field}={$id}");
$original_record = mysql_fetch_assoc($result);
// insert the new record and get the new auto_increment id
mysql_query("INSERT INTO {$table} (`{$id_field}`) VALUES (NULL)");
$newid = mysql_insert_id();
// generate the query to update the new record with the previous values
$query = "UPDATE {$table} SET ";
foreach ($original_record as $key => $value) {
if ($key != $id_field) {
$query .= '`'.$key.'` = "'.str_replace('"','\"',$value).'", ';
}
}
$query = substr($query,0,strlen($query)-2); # lop off the extra trailing comma
$query .= " WHERE {$id_field}={$newid}";
mysql_query($query);
if($newid) {
$oldid = $id;
copychilds($table, 'eventid', $oldid,$newid);
}
// return the new id
return $newid;
}
function copychilds($table, $id_field, $oldid,$newcopiedid) {
$result = mysql_query("SELECT * FROM {$table} WHERE id={$oldid}");
while($original_child_record = mysql_fetch_assoc($result){
// insert the new record and get the new auto_increment id
mysql_query("INSERT INTO {$table} (`id`) VALUES (NULL)");
$newid = mysql_insert_id();
// generate the query to update the new record with the previous values
$query = "UPDATE {$table} SET ";
foreach ($original_record as $key => $value) {
if ($key != 'id') {
$query .= '`'.$key.'` = "'.str_replace('"','\"',$value).'", ';
}
}
$query .= '`'.$id_field.'` = "'.str_replace('"','\"',$newcopiedid).'", ';
$query = substr($query,0,strlen($query)-2); # lop off the extra trailing comma
$query .= " WHERE id={$newid}";
mysql_query($query);
}
}
?>
Ok, I have all of this working with a few tweaks.
Below is my function, everything is working great, however, it only gets the first record and there may be multiple children. Any help appreciated.
function copychilds1($table, $id_field, $oldid,$newcopiedid, $updatedid) {
include_once '../inc/db_connect.php';
// load the original record into an array
$result = mysql_query("SELECT * FROM {$table} WHERE {$id_field}={$oldid}");
$original_record = mysql_fetch_assoc($result);
// insert the new record and get the new auto_increment id
mysql_query("INSERT INTO {$table} (`{$id_field}`) VALUES (NULL)");
$newid = mysql_insert_id();
// generate the query to update the new record with the previous values
$query = "UPDATE {$table} SET ";
foreach ($original_record as $key => $value) {
if ($key != 'id') {
$query .= '`'.$key.'` = "'.str_replace('"','\"',$value).'", ';
}
}
$query = substr($query,0,strlen($query)-2); # lop off the extra trailing comma
$query .= " WHERE id={$newid}";
mysql_query($query);
$finalquery = "UPDATE eventservices SET eventid = {$updatedid} WHERE id = {$newid}";
mysql_query($finalquery);
// return the new id
return $newid;
}
The code----
public function create(){
global $database;
//this code works perfectly to insert the new user into my database.
$sql = "INSERT INTO users (";
$sql .= "username, password, first_name, last_name";
$sql .= ") VALUES ('";
$sql .= $database->escape_value($this->username) ."', '";
$sql .= $database->escape_value($this->password) ."', '";
$sql .= $database->escape_value($this->first_name) ."', '";
$sql .= $database->escape_value($this->last_name) ."')";
if($database->query($sql)){
$this->id = $database->insert_id();
return true;
}else{
return false;
}
public function create()
{
global $database;
//this code is to be universal for other database types but it is not working.
$attributes = $this->attributes();
$sql = "INSERT INTO ".self::$table_name." (";
$sql .= join(", ", array_keys($attributes));
$sql .= ") VALUES ('";
$sql .= join("', '", array_values($attributes));
$sql .= "')";
if ($database->query($sql)) {
$this->id = $database->insert_id();
return true;
} else {
return false;
}
}
the problem - suppose to be generalizing the script so it can be used in any database structure. Its not working in my wamp.
I think there may be an issue with magic quote . Kindly use addslash php function for array_values($attributes)
This is not a programming error from your end the problem here is that MySQL is not interpreting this action as valid due to its SQL_MODE being in STRICT mode. You can either choose to edit your MySQL settings or add this code to your database class:
private function open_connection() {
$this->connection = mysqli_connect(DB_SERVER,DB_USER,DB_PASSWORD,DB_NAME);
if (!$this->connection) {
# code...
die("Connection to database failed" . mysqli_errno($this->connection));
}else{
/// this is the part you should take note of i changed the sql mode here using this code
mysqli_query($this->connection, "SET GLOBAL sql_mode = ''");
}
Your problem might be that you are using join("', '", array_values($attributes)) into the values you are trying to insert. But i guess, your column types aren't all strings, so you are creating something like :
INSERT INTO mytable(id,column1)
VALUES('id','mycolumn1')
Problem is probably that your id column's type is int, that might be why you have Incorrect integer value.
So you should have something like :
INSERT INTO mytable(id,column1)
VALUES(1,'mycolumn1')
Just guessing here, hope that helps.
I run the same issue. I wanted to post reply if anyone goes through the same problem. I think you were following lynda.com tutorial. As DCoder mentioned, id is auto increment value, and there is no way knowing what the value is, and moreover, join function made each property values-column values strings, in your case you get empty ""string. But id field is an int.
Your first create function, the one without join, worked because the id field is left out.
Now to fix the second create function after the line $attributes = $this->attributes(); add the following code
if($attributes["id"]==""){
array_shift($attributes);
}
after the line $attributes = $this->attributes();
Your attributes holds a list of properties; I am also making assumption that your code is the same as the tutorial I come across. So you check if the id is empty. If it is empty, you do an array_shift. This remove the first attribute, that is id, and in the process the new attributes array will have no id, and then when you apply the join it will be the same as your first create function. This will fix the issue. But I still would like to know how the instructor pass the tutorial without any issue. Great instructor and great tutorial for OOP--I am talking about the lynda.com tutorial.
You could elaborate your question more to get more response or the right answer. Since I run the same issue made it easier for me.
To let MySql generate sequence numbers for an AUTO_INCREMENT field you have some options:
explicitly assign NULL;
explicitly assign 0
public function create() {
global $database;
// USE '0' for your auto_increment not null filed if your filed need to sanitize.
$this->id = 0;
$attributes = $this->sanitized_attributes();
$sql = "INSERT INTO ".self::$table_name." (";
$sql .= join(", ", array_keys($attributes));
$sql .= ") VALUES ('";
$sql .= join("', '", array_values($attributes));
$sql .= "')";
if($database->query($sql)) {
$this->id = $database->insert_id();
return true;
} else {
return false;
}
}
This is how I figured to solve this problem
public function create(){
global $database;
$attributes = $this->sanitized_attributes();
$keys = array_keys($attributes);
$values = array_values($attributes);
$id = array_shift($values);
$id = (int) $id;
$sql = "INSERT INTO ".static::$table_name." (";
$sql .= join(", ", $keys);
$sql .= ") VALUES ($id,'";
$sql .= join("', '", $values);
$sql .= "')";
if($database->query($sql)) {
$this->id = $database->insert_id();
return true;
} else {
return false;
}
}