Related
So i built an application in mysql, and was having challenges updating records in the db. Everybody was more interested in telling me that i should just use PDO.
So rather than fight, I decided to start to learn PDO connection and query strings and the practices around using prep stmts.
Anyway in my practice and tutorials, I can pull and parse the information from my database with no challenges. but when it comes to updating or inserting a new record nothing is ever inserted and I can't find the reason why not.
originally I had a form post to the variables, but that didn't work
so i hardcoded the variables, but it still isn't working
i could use some help.... can anybody see what is wrong with this insert php script?
<?php
$user="111";
$pass="111";
$database="111";
$host="111";
$odb = new PDO("mysql:host=$host;dbname=$database", $user, $pass);
$event='Special Speaker';
$descript='We have special speakers comming on tuesday night';
$sp1='Speaker Mr.A';
$sp2='Speaker Mr.B';
$date='5-5-15';
$created = '5-5-15';
$id=7;
$stmt=$odb->Prepare("INSERT INTO events(ID,Event,Descript,Sp1,Sp2,Created,Date)
VALUES (:ID,:Event,:Descript,:Sp1,:Sp2,:Created,:Date");
$stmt->bindParam(':ID',$id);
$stmt->bindParam(':Event',$event);
$stmt->bindParam(':Descript',$descript);
$stmt->bindParam(':Sp1',$sp1);
$stmt->bindParam(':Sp2',$sp2);
$stmt->bindParam(':Created',$created);
$stmt->bindParam(':Date',$date);
$stmt->execute();
?>
You may have to specify that your ID is an int like so: $stmt->bindParam(':calories', $calories, PDO::PARAM_INT);
Your database may be preventing you from inserting IDs in that table if it's the Identity/Primary column and/or is auto-incrementing.
It'd be a good idea to enable PDO warnings or exceptions so that it can tell you what's wrong or what is failing. See here for more: http://php.net/manual/en/pdo.error-handling.php
I am modifying my code from using mysql_* to PDO. In my code I had mysql_real_escape_string(). What is the equivalent of this in PDO?
Well No, there is none!
Technically there is PDO::quote() but it is rarely ever used and is not the equivalent of mysql_real_escape_string()
That's right! If you are already using PDO the proper way as documented using prepared statements, then it will protect you from MySQL injection.
# Example:
Below is an example of a safe database query using prepared statements (pdo)
try {
// first connect to database with the PDO object.
$db = new \PDO("mysql:host=localhost;dbname=xxx;charset=utf8", "xxx", "xxx", [
PDO::ATTR_EMULATE_PREPARES => false,
PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION
]);
} catch(\PDOException $e){
// if connection fails, show PDO error.
echo "Error connecting to mysql: " . $e->getMessage();
}
And, now assuming the connection is established, you can execute your query like this.
if($_POST && isset($_POST['color'])){
// preparing a statement
$stmt = $db->prepare("SELECT id, name, color FROM Cars WHERE color = ?");
// execute/run the statement.
$stmt->execute(array($_POST['color']));
// fetch the result.
$cars = $stmt->fetchAll(\PDO::FETCH_ASSOC);
var_dump($cars);
}
Now, as you can probably tell, I haven't used anything to escape/sanitize the value of $_POST["color"]. And this code is secure from myql-injection thanks to PDO and the power of prepared statements.
It is worth noting that you should pass a charset=utf8 as attribute, in your DSN as seen above, for security reasons, and always enable
PDO to show errors in the form of exceptions.
PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION
so errors from you database queries won't reveal sensitive data like your directory structure, database username etc.
Last but not least, there are moments when you should not trust PDO 100%, and will be bound to take some extra measures to prevent sql injection, one of those cases is, if you are using an outdated versions of mysql [ mysql =< 5.3.6 ] as described in this answer
But, using prepared statements as shown above will always be safer, than using any of the functions that start with mysql_
Good reads
PDO Tutorial for MySQL Developers
There is none*! The object of PDO is that you don’t have to escape anything; you just send it as data. For example:
$query = $link->prepare('SELECT * FROM users WHERE username = :name LIMIT 1;');
$query->execute([':name' => $username]); # No need to escape it!
As opposed to:
$safe_username = mysql_real_escape_string($username);
mysql_query("SELECT * FROM users WHERE username = '$safe_username' LIMIT 1;");
* Well, there is one, as Michael Berkowski said! But there are better ways.
$v = '"'.mysql_real_escape_string($v).'"';
is the equivalent of $v = $this->db->quote($v);
be sure you have a PDO instance in $this->db so you can call the pdo method quote()
There is no need of mysql_real_escape_string in PDO.
PDO itself adjust special character in mysql query ,you only need to pass anonymous parameter and bind it run time.like this
Suppose you have user table with attribute name,email and password and you have to insert into this use prepare statement like this
you can pass name as => $name="Rajes'h ";
it should execute there is no need of equivalent of mysql_real_escape_string
$stmt="INSERT into user(name,email,password) VALUES(:name,:email,:password)";
try{
$pstmt=$dbh->prepare($stmt);//$dbh database handler for executing mysql query
$pstmt->bindParam(':name',$name,PDO::PARAM_STR);
$pstmt->bindParam(':email',$email,PDO::PARAM_STR);
$pstmt->bindParam(':password',$password,PDO::PARAM_STR);
$status=$pstmt->execute();
if($status){
//next line of code
}
}catch(PDOException $pdo){
echo $pdo->getMessage();
}
The simplest solution I've found for porting to PDO is the replacement for mysql_real_escape_string() given at https://www.php.net/manual/en/mysqli.real-escape-string.php#121402. This is by no means perfect, but it gets legacy code running with PDO quickly.
#samayo pointed out that PDO::quote() is similar but not equivalent to mysql_real_escape_string(), and I thought it might be preferred to a self-maintained escape function, but because quote() adds quotes around the string it is not a drop in replacement for mysql_real_escape_string(); using it would require more extensive changes.
In response to a lot of people's comments on here, but I can't comment directly yet (not reached 50 points), there ARE ACTUALLY needs to use the $dbh->quote($value) EVEN when using PDO and they are perfectly justifiable reasons...
If you are looping through many records building a "BULK INSERT" command, (I usually restart on 1000 records) due to exploiting InnoDb tables in MySQL/Maria Db. Creating individual insert commands using prepared statements is neat, but highly inefficient when doing bulk tasks!
PDO can't yet deal with dynamic IN(...) structures, so when you are building a list of IN strings from a list of user variables, YOU WILL NEED TO $dbh->quote($value) each value in the list!
So yes, there is a need for $dbh->quote($value) when using PDO and is probably WHY the command is available in the first place.
PS, you still don't need to put quotes around the command, the $dbh->quote($value) command also does that for you.
Out.
If to answer the original question, then this is the PDO equivalent for mysql_real_escape_string:
function my_real_escape_string($value, $connection) {
/*
// this fails on: value="hello'";
return trim ($connection->quote($value), "'");
*/
return substr($connection->quote($value), 1, -1);
}
btw, the mysqli equivalent is:
function my_real_escape_string($value, $connection) {
return mysqli_real_escape_string($connection, $value);
}
I'm working on automating the deployment of a piece of software I've written and need to be able to generate new mysql databases for new accounts. However, I'm having concerns when it comes to sanitizing the input.
I'm using PDO; however, apparently you can't use prepared statements with 'CREATE DATABASE'. So, I also tried using PDO::quote; however, then my newly created databases names are surrounded by single quotes (not the end of the world, but I'd still like to avoid that).
Is there any way to get this to work with prepared statements? If not, what can I do to protect myself as much as possible from sql injection attacks? My only other idea is to have a small whitelist of characters allowed.
Thanks!
you'll need to write a stored procedure to which you can then pass the sanitized input
(to use my example you'll need to change some variables like the database name and the correct user and pass and such, to make it run on your database of course)
example:
<?php
$dsn = 'mysql:dbname=scratch;host=127.0.0.1';
$user = 'root';
$password = '';
try {
$dbh = new PDO($dsn, $user, $password);
} catch (PDOException $e) {
echo 'Connection failed: ' . $e->getMessage();
}
$dbname = 'brand_new_db';
$statement = $dbh->prepare("CALL dbcreator(:db)");
$statement->bindParam(':db',$dbname);
if(!$statement->execute()){
print_r($statement->errorInfo());
}
else {
foreach( $dbh->query('SHOW DATABASES')->fetchAll() as $row){
print "$row[0]" . PHP_EOL;
}
}
stored procedure:
DELIMITER $$
DROP PROCEDURE IF EXISTS `scratch`.`dbcreator` $$
CREATE DEFINER=`root`#`localhost` PROCEDURE `dbcreator`(IN dbname VARCHAR(64))
BEGIN
SET #db = dbname;
SET #statement = CONCAT('CREATE DATABASE ',#db);
PREPARE prepared_statement FROM #statement;
EXECUTE prepared_statement;
END $$
DELIMITER ;
You create an SQL statement to PREPARE, in our case CREATE DATABASE <our database>; since the CREATE DATABASE statement will not work with a variable, and then you just EXECUTE it. Finally you do a CALL dbcreator('<dbname>') to execute the stored procedure. It's that CALL dbcreator(:dbname), that you can use and bind params to.
As you can see, this way you can still bind your params safely through pdo while creating the database. Still it might not be a bad idea to prefix all database you create with some short fixed string for easy lookup and discrimination. In the stored procedure dbname is limited to 64 characters since that's mysql's current limit
I have used tutorials, examples and looked at numerous other questions about my problem and I still can't get it to work, I am relatively new to PHP and do not have any understanding of PDO. I have changed my code to mysqli rather than mysql to get rid of the depreciated code my university gave me but they have been less than helpful during this situation.
If anyone could shed some light onto this issue for me I would be very grateful.
Below are my code samples:
<?php /*connect to the db */
$link=mysqli_connect("dbhost","user","pass");
mysqli_select_db("db",$link);
/*checking connection*/
if ($link->connect_errno)
throw new exception(sprintf("Could not connect: %s", $link->connect_error));
session_start();
$insert_query="
INSERT INTO testone_tbl (age,hours,flexibility,fastpaced,retailexp,
workedus,conviction,permit,education)
VALUES ('$age','$hours','$flexibility','$fastpaced','$retailexp','$workedus',
'$conviction','$permit','$education');
INSERT INTO testtwo_tbl
(contribute,insales,initiative,success,alternatives,targets,
newthings,custfeed,incdevelop,standards,confident,stretch,
opportunities,polite,ideas,deadline,supported,duties)
VALUES ('$contribute','$insales','$initiative',
'$success','$alternatives','$targets','$newthings',
'$custfeed','$incdevelop','$standards','$confident','$stretch',
'$opportunities','$polite','$ideas','$deadline','$supported','$duties')";
/*execute multi_query*/
mysqli_multi_query ($link, $insert_query);/*error1*/
/*close connection*/
if(!$link>connect_errno) $link->close(); /*error2*/
?>
The data is both from the form this is written in (the last form) and sessions from the previous forms. However I am also getting this error: Warning: mysqli_multi_query() expects parameter 1 to be mysqli and Warning: mysqli_close() expects parameter 1 to be mysqliand I have been stuck on this the past few days! Thank you in advance.
You should first check with your web host if they have enabled multi-SQL-queries.
Some web hosts only allow single-SQL queries to help prevent against injection attacks.
If, however, you want to multi-insert to the same table, you could do it like this:
INSERT INTO tbl_name (col1, col2)
VALUES ('?', '?'),
('?', '?'),
('?', '?'); # inserts 3 records to the same table in one query
Also, if you do have PDO available to you, use it!
With a PDO object, your queries will be safer by using prepared statements. Example:
$db = new PDO("mysql:host=$host;dbname=$dbname", $user, $pass);
$data = array($col1, $col2, $col3);
$sql = "INSERT INTO tbl_name (col1, col2, col3) VALUES ('?', '?', '?');";
$query = $db->prepare($sql); # prepares the sql statement
$query->execute($data); #binds the array of data to the ?
#question mark parameters, and executes.
If you create a database abstraction layer, you could change the database connection mode without having to rewrite your code which executes your queries.
Also, do you have a reason not to loop and query? Example:
$sql_array = array("INSERT INTO tbl_one(col1) VALUES '?';",
"INSERT INTO tbl_two(col3) VALUES '?';");
function performAll($sql_array) {
# execute all of the queries
}
It has occured to me that you may be using some function to access your database connection. Now that is not a problem, unless you actually try to access the database connection from within a function (in case you have not told us). Example:
$db = new PDO("...", $user, $pass);
$query = $db->prepare($sql); # works fine
function executeQuery($sql) {
$query = $db->prepare($sql); # error: $db is not defined
# within the scope of this function
...
}
To get around this, use the global keyword in PHP. Example:
$db = new PDO("...", $user, $pass);
function executeQuery($sql) {
global $db; # use $db in the global scope
$query = $db->prepare($sql); # works fine
...
}
From the warnings it is clear that $link is not a mysqli object. Either you did not connect, or at some point you reassigned $link to something else.
You also need to check your connection immediately after your connect. An intermediate action on the link (in this case, mysqli_select_db) will clear any errors that were set.
You should also not mix-and-match object-oriented and procedural style interfaces for mysqli. The object-oriented style is much clearer, but if it's too difficult to change the existing code then stick to the procedural style.
Connect like this instead:
$link = mysqli_connect("dbhost","user","pass", "db"); // no need for an extra db select
if (mysqli_connect_errno()) {
throw new Exception("Could not connect: ".mysqli_connect_error());
}
Also, I hope this isn't your real code, because it is wide open to mysql injection attacks. Consider dropping the use of multi-queries entirely and using prepared statements with placeholders.
here my code-
$things = serialize($_POST['things']);
echo $things;
require 'database.php';
$q = "INSERT INTO tblslider(src) values($things)";
mysql_query($q, $link);
if($result)
{
echo "Slider saved successfully.";
}
Output-
a:4:{i:0;s:10:"651603.jpg";i:1;s:11:"7184512.jpg";i:2;s:11:"3659637.jpg";i:3;s:10:"569839.jpg";}v
it means I am getting the record properly but why it it not getting saved in db??
You forgot quotes around $things:
$q = "INSERT INTO tblslider(src) values('" . mysql_real_escape_string($things) . "')";
The mysql_real_escape_string() is really the least you should ever do!
Also as #sanders mentions, you should always output your complete query (via print_r() or var_dump()) as a first step in debugging.
I prefer to build queries like this to enhance readability:
$q = sprintf(
'INSERT INTO tblslider(src) VALUES ("%s")',
mysql_real_escape_string($things)
);
That is, whenever I absolutely have to build and escape them myself. You should really have a look at PDO.
EDIT
Comments in this thread suggests that OP actually wants to insert 651603.jpg,7184512.jpg,3659637.jpg,569839.jpg into the database. In that case implode() could be used (provided that $_POST['things'] only contains items to insert!):
$q = sprintf(
'INSERT INTO tblslider(src) VALUES ("%s")',
mysql_real_escape_string(implode(',', $_POST['things']))
);
Note, that I'm using $_POST['things'] directly here. No serialize(). (I did, however, not realize this erro until just now.)
This question is quite old, but I feel like it's time for a little necromancy. The accepted answer by #jensgram is not wrong, but saying mysql_real_escape_string is the least you could do implies there is a much better solution. Well there is.
PHP Data Objects
PDOs. These bad boys provide an abstraction layer for your database access, so it works with a lot of other databases not just MySQL, and can improve performance when the same query is run many times. Nut this is not why you need them.
Security
Escaping stuff is hard. Either it is obscure how to do it in a specific context or you just forget to do it. The worst thing is that you will not get any errors from forgetting it, and just move on like nothing happened. And you just contributed to the sorry state internet security is in.
With using PDOs properly (e.g. no string concatenation) however will ensure that you will not mess up properly escaping stuff while building DB queries.
You will want to read this: (The only proper) PDO tutorial.
Basically you can prepare an sql statement BEFORE replacing ANY parameters in it. The SQL syntax will be fixed and cannot be broken by bad/no escaping or maliciously forged requests.
So how to do this
At first you need a connection, just like in the regular mysql driver.
$host = '127.0.0.1';
$db = 'test';
$user = 'root';
$pass = '';
$charset = 'utf8';
$dsn = "mysql:host=$host;dbname=$db;charset=$charset";
$opt = [
PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC,
PDO::ATTR_EMULATE_PREPARES => false,
];
$pdo = new PDO($dsn, $user, $pass, $opt);
As you can see there are settings, error modes, fetch modes. It worths reading what each setting does but for now just leave it as it is. At the end of it all, you have the $pdo variable you can use.
$query = "INSERT INTO tblslider(src) VALUES (?)";
$stmt = $pdo->prepare($query);
At this point we got our statement. Nothing came from external sources yet, it is an INSERT statement.
$things = serialize($_POST['things'])
$stmt->execute([ $things ]); //execute
There are other ways to bind the ?-s to parameters, also you can use named parameters too for clarity, but this suffices for now.
That's it: no fancy escaping but no possibility for SQL injection either.
Normally, I will serialize then base64_encode to eliminate surprises and "standardize" the input. For example:
$things = base64_encode(serialize($_POST['things']));
$insert_query = "INSERT INTO...";
Then, when you want to grab it, simply reverse the process.
$query_result = mysql_query("SELECT FROM ...");
$row = mysql_fetch_assoc($query_result);
$retrieved_value = unserialize(base64_decode($row['src']);
You are writing a string to the database, so don't forget to add quotes to your query:
$q = "INSERT INTO tblslider(src) values('$things')";
Also make sure to filter the string to avoid SQL-Injection Attacks.
place an var_dump($q) before mysql_query(...)
You can then examine your query.