i'veen following a tutorial about oop php and I was doing the C of the crud, where I have a user with its attributes. When i'm doing the insert into the bd it just save () or {()}, in the example the person uses
`
public function save(){
$sql = "INSERT INTO usuarios (nombre, apellidos, email, password,rol,) VALUES('{$this->getNombre()}',
'{$this->getApellidos()}','{ $this->getEmail()}','{$this->getPassword()}','user')";
$save = $this->db->query($sql);
$result=false;
if($save){
$result=true;
}
return $result;
}
`
But when I use it, I get only save {()} on the db. I tried erasing the {} from the getters, and saving the attributes in new variables and writting it in the query but I can't make it works.
Here it's my db
And the error I get
Thank you for your answers :)
To avoid sql injection you should use prepared statements. These come with PDO and are pretty simple to use. Have a look at the following example.
$sql = "
INSERT INTO
usuarios
(nombre, apellidos, email, password,role)
VALUES
(:nombre, :apellidos, :email, 'user')
";
$stmt = $this->db->prepare($sql);
$result = $stmt->execute([
'nombre' => $this->getNombre(),
'apellidos' => $this->getApellidos(),
'email' => $this->getEmail()
]);
return $result;
Further more you can wrap the execution of your sql query via PDO in a try/catch block. So if any exception occurs, you can catch it and see, what exactly went wrong.
try {
// execute your logic here
} catch (PDOException $e) {
var_dump($e, $this->db->errorInfo());
}
Hope this helps.
Beside that your SQL Syntax got an error. The last comma after rol. Further the error message says, that an entry () for the key uq_email already exists. This kind of exeptions you can catch with the above shown try/catch block.
Related
<?php
$sql = "insert into user (firstname, lastname) values (:firstname, :lastname)";
$arg = array("John", "Doe");
$stmt = pdo($sql, $arg);
$id = $pdo->lastInsertId();
print $id;
function pdo($sql, $args = NULL){
$dsn = "mysql:host=localhost;dbname=db;charset=utf8mb4";
try {
$pdo = new \PDO($dsn, "user", "123");
} catch (\PDOException $e) {
throw new \PDOException($e->getMessage(), (int)$e->getCode());
}
if (!$args){
return $pdo->query($sql);
}
$stmt = $pdo->prepare($sql);
$stmt->execute($args);
return $stmt;
}
?>
I use a wrapper to call database queries, this has always worked well.
Except for today when I need to get the last insert ID. The error is "Undefined variable pdo"
I see why there is an error message, but not sure what is the solution while at the same time keeping the wrapper function?
You might just want to have a function create the DB connection and let the application code use the PDO API directly. That would be simpler than trying to wrap all the functionality of the PDO API. It would get complicated to do that.
If you really need a wrapper around your PDO connection, then you may want to create a class with different methods operating on the same connection. The class could have a special insert method that returns the inserted ID as well as a fetch method to retrieve results.
I have some queries that have run perfectly up until now, but I wanted to wrap them in a transaction to decrease the likelihood of data corruption. After running the code, everything APPEARS to work (i.e. no exception is thrown), but the query is never committed to the database. I've looked at other questions on S.O. but I haven't found any that apply to my case.
Here's my code:
db::$pdo->beginTransaction(); // accesses PDO object method
try {
$sql = "INSERT INTO expenses SET date=:date, amount=:amount, accountId=:account; ";
$sql .= "UPDATE accounts SET balance = balance - :amount WHERE id = :account";
$s = db::$pdo->prepare($sql);
$s->bindValue(':date', $date);
$s->bindValue(':amount', $amount);
$s->bindValue(':account', $account);
$s->execute();
db::$pdo->commit();
echo 'success';
}
catch (PDOException $e) {
db::$pdo->rollback();
echo '<p>Failed: ' . $e->getMessage() . '</p>';
}
When I run the code, it outputs the success message, but like I said, nothing gets committed to the database.
Since it's relevant, I should also note that my PDO error mode is set to ERRMODE_EXCEPTION, so I don't think that's what's causing the problem. I'm running a MySQL database (InnoDB)
Any thoughts?
I am not completely sure how running multiple queries in a single query statement works (if it works) because I typically do transactions by running each query separately in a prepare/execute statement. The transaction will still queue up all the changes until commit/rollback as expected. According to this SO answer it appears to work, however the example is not binding values and so that might be another issue.
I would suggest just splitting up the queries into multiple prepare/bind/execute statements and it should work as expected.
The success message will allways be displayed because it's just there to echo.. if you want to show succes only after the execute you should use if statement.. for the not committing part it could be many things.. are you sure all values $date, $amount, $account are being supplied ? you can also try starting with the simple insert and if that works do the update..
$sql = 'INSERT INTO expenses (date, amount, account)
VALUES(:date, :amount, :account)';
$stmt = $this->pdo->prepare($sql);
$stmt->bindValue(':date', $);
$stmt->bindValue(':amount', $amount);
$stmt->bindValue(':account', $account);
if($stmt->execute()) {
db::$pdo->commit();
echo 'success';
}
not sure about the db::$pdo->commit(); part because I use some kind of OOP way, but hope this might help.
I think I had similar problem in one of the projects, please add another catch block just after the one you have so the code will look like:
catch (PDOException $e) {
db::$pdo->rollback();
echo '<p>Failed: ' . $e->getMessage() . '</p>';
}
catch (Exception $exc) {
db::$pdo->rollback();
echo '<p>Failed: ' . $exc->getMessage() . '</p>';
}
It will allow you to catch Exceptions of class other than PDOException, so you could ensure more.
UPDATE:
Please consider splitting two queries into 2 PDO statements llike this:
$sql = "INSERT INTO expenses SET date=:date, amount=:amount, accountId=:account; ";
$s = db::$pdo->prepare($sql);
$s->bindValue(':date', $date);
$s->bindValue(':amount', $amount);
$s->bindValue(':account', $account);
$s->execute();
$sql2 = "UPDATE accounts SET balance = balance - :amount WHERE id = :account;";
$s2 = db::$pdo->prepare($sql2);
$s2->bindValue(':amount', $amount);
$s2->bindValue(':account', $account);
$s2->execute();
I use this approach in my entire project with success so I hope it might help.
Don't use db::$pdo->commit();
Use
$sql = "INSERT INTO expenses SET date=:date, amount=:amount, accountId=:account;";
$sql .= "UPDATE accounts SET balance = balance - :amount WHERE id = :account;COMMIT;"; // change here
kind of silly ;(
basically I am trying to implement a function in one of my PHP classes that makes an entry into a junction table for a many to many relationship.
This is the method here:
public function setTags($value, $id){
global $db;
$tags = $value;
$query .= "DELETE FROM directorycolumntags
WHERE directorycolumn_id = $id; ";
foreach($tags as $tag){
$query .= "INSERT INTO directorycolumntags (directorycolumn_id, tag_id)
VALUES (".$id.",".$tag.");";
}
mysql_query($query);
}
The SQL is produces works fine, as I've echoed it and manually executed it via phpMyAdmin. However, If I leave it as above, the data is never inserted. Does anyone know why this might be happening?
This is the sql it is generating which works fine when I type it manually in:
DELETE FROM directorycolumntags WHERE directorycolumn_id = 178;
INSERT INTO directorycolumntags (directorycolumn_id, tag_id) VALUES (178,29);
INSERT INTO directorycolumntags (directorycolumn_id, tag_id) VALUES (178,30);
INSERT INTO directorycolumntags (directorycolumn_id, tag_id) VALUES (178,32);
The old, unsafe, deprecated mysql_* extension never supported multiple queries. You could, conceivably do this using the mysql replacement extension: mysqli_*, which has the mysqli_multi_query function.
Personally, I'd not use this approach, though. I'd do what most devs would do: use a prepared statement in a transaction to execute each query safely, and commit the results on success, or rollback on failure:
$db = new PDO(
'mysql:host=127.0.0.1;dbname=db;charset=utf8',
'user',
'pass',
array(
PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION
)
);
try
{
$db->beginTransaction();
$stmt = $db->prepare('DELETE FROM tbl WHERE field = :id');
$stmt->execute(array(':id' => $id));
$stmt = $db->prepare('INSERT INTO tbl (field1, field2) VALUES (:field1, :field2)');
foreach ($tags as $tag)
{
$stmt->execute(
array(
':field1' => $id,
':field2' => $tag
)
);
$stmt->closeCursor();//<-- optional for MySQL
}
$db->commit();
}
catch (PDOException $e)
{
$db->rollBack();
echo 'Something went wrong: ', $e->getMessage();
}
Going slightly off-topic: You really ought to consider using type-hints. From your code, it's clear that $values is expected to be an array. A type-hint can ensure that the value being passed is in fact an array. You should also get rid of that ugly global $db;, and instead pass the connection as an argument, too. That's why I'd strongly suggest you change your function's signature from:
public function setTags($value, $id){
To:
public function setTags(PDO $db, array $value, $id)
{
}
That way, debugging gets a lot easier:
$instance->setTags(123, 123);//in your current code will not fail immediately
$instance->setTags($db, [123], 123);//in my suggestion works but...
$instance->setTags([123], null, '');// fails with a message saying argument 1 instance of PDO expected
http://docs.php.net/mysql_query says:
mysql_query() sends a unique query (multiple queries are not supported) to the currently active database on the server that's associated with the specified link_identifier
If you can use mysqli perhaps this interest you: mysqli.multi-query
Executes one or multiple queries which are concatenated by a semicolon.
you can not run multiple quires using mysql_query, try to modify your function like this. It would be better if you use mysqli or pdo instead of mysql because soon it will deprecated and it would not work on newer version of php
public function setTags($value, $id){
global $db;
$tags = $value;
mysql_query("DELETE FROM directorycolumntags WHERE directorycolumn_id = $id");
foreach($tags as $tag){
mysql_query("INSERT into directorycolumntags (directorycolumn_id, tag_id) VALUES (".$id.",".$tag.")");
}
}
I am having a syntax error with an sql statement I am executing but for the life of me I can't find any error.
I have created my own database class with functionality to make prepared statements and execute them, I don't think there is a problem with my implementation as I have never had any issues with it before now. But, just in case there is a problem there I am going to show the code for that too.
Prepare:
public function prepare($index, $sql) {
if(isset(self::$PS[$index])){
$ermsg = "Index [$index] is already in use.";
throw new Exception($ermsg, 1);
}
try{
self::$PS[$index] = $this->dbh->prepare($sql);
}
catch(PDOException $e){
return false;
}
return true;
}
and execute:
public function execute($index, Array $param = array()) {
if(!isset(self::$PS[$index])){
$ermsg = "Index [$index] is unavailable.";
throw new Exception($ermsg, 1);
}
foreach($param as $key => $val){
if(is_int($key)) ++$key;
$type = $this->getValueType($val);
$bnd = self::$PS[$index]->bindValue($key, $val, $type);
if(!$bnd){
$ermsg = "Paramater '$key' in [$index] failed to bind";
throw new Exception($ermsg, 2);
}
}
try{
$bnd = self::$PS[$index]->execute();
}
catch(PDOException $e){
$ermsg = "PDO-Error while executing prepared statement [$index] ".$e->getMessage();
throw new Exception($ermsg, 3);
}
if($bnd === false){
$ermsg = "Result error in prepared statement [$index]";
throw new Exception($ermsg, 3);
}
return self::$PS[$index];
}
As I mentioned, I have never experienced issues using this so I don't think it's the problem, but who knows.
Now my implementation:
$sql = "INSERT INTO ratings (course_id, overall, design, condition, service, value, rated_by, date_rated)
VALUES (:course_id, :overall, :design, :condition, :service, :value, :rated_by, now()))";
DBH::getInstance()->prepare('rateit', $sql);
$stmt = DBH::getInstance()->execute('rateit', array(
":course_id"=>$course_id,
":overall"=>$overall,
":design"=>$design,
":condition"=>$condition,
":service"=>$service,
":value"=>$value,
":rated_by"=>$log_user_id
));
}
if($stmt) {
echo 'suc, Thanks! Your ratings have been added to the course.';
exit();
}else{
echo 'err, There was an error rating the course. Please try again later';
exit();
}
This is the exact syntax error message I receive:
Syntax error or access violation: 1064 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 'condition, service, value, rated_by, date_rated) VALUES (1, 5, 5, 5, 5, 3, '18',' at line 1'
If someone can spot my syntax error, or maybe find something else wrong that would be causing this that would be awesome. Thanks for any help.
Condition is a reserved word in MySQL. That could be it.
According to 9.2 Schema Object Names, to use reserved words as identifiers they must be quoted. Use backticks or, with enabled ANSI_QUOTES SQL mode, double quotation marks. Quoting is not necessary if the reserved word follows a period in a qualified name.
$sql = "INSERT INTO ratings (course_id, overall, design, condition, service, value, rated_by, date_rated)
VALUES (:course_id, :overall, :design, :condition, :service, :value, :rated_by, now()))";
Should be:
$sql = "INSERT INTO ratings (course_id, overall, design, `condition`, service, value, rated_by, date_rated)
VALUES (:course_id, :overall, :design, :condition, :service, :value, :rated_by, now())";
Condition is a reserved word in MySQL. You should always use backticks ("`") in `table` and `column` names to avoid errors like that. Also looks like you have an extra ) at the end of the sql query
List of Reserved Words
I am trying PDO transactions for the first time. The below code doesnt work. the email address we are trying to insert has a duplicate so it should fail. It does give me an error. but the first insert get inserted into the DB and it doesnt roll back. I know rollback work cuase if i move PDO::rollBack into the Try{ before commit, it does roll back. I think the problem is its not catching the error, therefore not calling PDO::rollBack. Any ideas?
try {
PDO::beginTransaction();
$sql = "INSERT INTO .`tblUsersIDvsAgencyID` (`id`, `agency_id`) VALUES (NULL, :agencyID)";
$STH = $this->prepare($sql);
$STH->bindParam(':agencyID', $AgencyUser['agency_id']);
$STH->execute();
$userID = parent::lastInsertId();
$sql = "INSERT INTO `tblUsersEmailAddress` (`id`, `user_id`, `email_address`, `primary`, `created_ts`, `email_verified`) VALUES (NULL , :userID , :EmailAddress , '1', CURRENT_TIMESTAMP , '0' )";
$STH = $this->prepare($sql);
$STH->bindParam(':userID', $userID);
$STH->bindParam(':EmailAddress', $email_address);
$STH->execute();
PDO::commit();
echo 'Data entered successfully<br />';
}
catch(PDOException $e)
{
/*** roll back the transaction if we fail ***/
PDO::rollBack();
echo "failed";
}
PDO::beginTransaction() is not a static method. From your question, it looks like you're extending the PDO class. I wouldn't do that as I doubt you're adding anything significant to the base class. Instead, you should the set the PDO connection as a class property.
For example
class ParentClass
{
/**
* #var PDO
*/
protected $dbh;
public function __construct(PDO $dbh)
{
$this->dbh = $dbh;
// Make sure PDO is set to throw exceptions
$this->dbh->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
}
}
class ChildClass extends ParentClass
{
public function insertStuff()
{
$this->dbh->beginTransaction();
try {
// do stuff
$this->dbh->commit();
} catch (PDOException $e) {
$this->dbh->rollBack();
throw $e;
}
}
}
I'm just going to start by quoting the docs:
Beware: Some MySQL table types (storage engines) do not support transactions. When writing transactional database code using a table type that does not support transactions, MySQL will pretend that a transaction was initiated successfully. In addition, any DDL queries issued will implicitly commit any pending transactions.
Your problem may be expected behavior. Additionally:
beginTransaction is not static. (I repeat Phil's statement that you should not be extending PDO).
Call $pdo->setAttribute( PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION );
You never call closeCursor on your statement (this will often cause problems). (Phil points out that it is not explicitly necessary in this case. It is still best practice though).
Using bindParam does not yield any benefit for the userID variable as you are using it (a locally defined variable which is not re-used).