I'm still in the progress of learning PDO fully, but I was kind of surprised when I checked this evening if it worked to SQL Inject the URL parameter, and to my surprise, it did work. So I started thinking; the posted values are supposed to be sanitized automatically using PDO - prepared statements, which means there must be something wrong with my SQL query, am I right?
I'm having a page that needs a GET variable in order to gather corresponding data from my database with that ID. I have created a function that includes preparing the query, and as well as executing it to simplify the coding process. The code I have written now looks like:
$request = $_GET['movie'];
$sql = "SELECT * FROM `movies` WHERE `url` = '$request'";
$db = new database;
$db->setDBC();
$process = $db->executeQuery($sql);
$cmd = $process->fetch(PDO::FETCH_NUM);
$title = $cmd[1];
And the PDO Exception I get is:
Fatal error: Uncaught exception 'PDOException' with message 'SQLSTATE[42000]: 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 ''21-31282 ''' at line 1' in C:\xampp\htdocs\filmvote\include\databaseClass.php:33 Stack trace: #0 C:\xampp\htdocs\filmvote\include\databaseClass.php(33): PDOStatement->execute() #1 C:\xampp\htdocs\filmvote\recension.php(9): databaseManagement->executeQuery('SELECT * FROM `...') #2 {main} thrown in C:\xampp\htdocs\filmvote\include\databaseClass.php on line 33
You get this kind of error when adding ' or 1-1 to the URL. What can I do about this? Really grateful for help.
the posted values are supposed to be sanitized automatically using PDO
Nope. Only if you use actual prepared statements like so:
$stmt = $dbh->prepare("SELECT * FROM `movies` WHERE `url` = ?");
if ($stmt->execute(array($_GET['movie']))) // <-- This sanitizes the value
{
// do stuff
}
will your the values you insert be automatically sanitized, and your query protected from SQL injection.
Otherwise, your SQL query will be executed like any old mysql_query(), and is vulnerable. PDO can not take a query and then automatically sanitize the vulnerable parts. That's not possible.
Try prepared statements:
$query = $db->prepare("SELECT * FROM `movies` WHERE url = ?");
$query->execute(array($request));
$result = $query->fetch(PDO::FETCH_ASSOC);
Related
I have this function in PHP. I am trying to insert (if it's necessary) and then get the app_id from the table.
private function addApp($bundle_identifier,$os_id) {
$driver = new mysqli_driver();
$driver->report_mode = MYSQLI_REPORT_ALL;
//Insert or update app details
if ($stmt = $this->db->prepare("INSERT IGNORE INTO app (app_identifier,os_id) VALUES (?,?); SELECT app_id FROM app WHERE app_identifier = ? AND os_id = ?")){
$stmt->bind_param("ssss", $bundle_identifier,$os_id,$bundle_identifier,$os_id);
$stmt->execute();
$stmt->bind_result($app_id);
if (!isset($app_id)) {
echo "is set";
$app_id=$stmt->insert_id;
}
}
if($this->db->commit()){
return $app_id;
}
return 0;
}
The issue here is that stmt is always false with the error:
Uncaught exception 'mysqli_sql_exception' with message '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 'SELECT app_id
FROM app WHERE app_identifier = ? AND os_id = ?' at line 1'
The weird thing is that this query works fine in my SQL.
Is that a limitation of mysqli?
According to http://php.net/manual/en/mysqli.prepare.php :
The query must consist of a single SQL statement.
Which basically answers your question. You have to use two db calls for two queries. Or use something like http://php.net/manual/en/mysqli.multi-query.php
The below is kept for information only as it refers PDO, while the question is about mysqli. It's generally useful though.
I think the reason for this working in mysql, but not in mysqli is that the latter supports prepared statements natively, while the former uses emulation. As your expression contains two queries, all bound parameters are given by driver to the first query (out of which is uses two and discards the other two). The second query then gets no parameters and therefore question marks are syntax errors. With prepared statements emulation PHP actually substitutes question marks with the properly escaped values and so forms two valid queries.
You can enable emulation using $db->setAttribute(PDO::ATTR_EMULATE_PREPARES, true), however, this may slightly affect performance.
See also http://www.php.net/manual/en/pdo.setattribute.php
This question already has answers here:
How do I create a PDO parameterized query with a LIKE statement?
(9 answers)
Closed 6 years ago.
I am using PDO with PHP to submit queries to my SQL server. I need to use the LIKE clause to check a username to ensure that it is allowed (eg; it does not contain any banned words), so I am using this SQL query...
SELECT * FROM `table` WHERE (`name` LIKE %?%);
I am then inserting the paramater with PDO later like this...
$statement->bindParam(1, $username)
When I try to run this, I get this error...
Fatal error: Uncaught exception 'PDOException' with message 'SQLSTATE[42000]: Syntax error or access violation: 1064 You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near '%'dibdibs'%)' at line 1' in C:\xampp\htdocs\scripts\sql.php:57 Stack trace: #0 C:\xampp\htdocs\scripts\sql.php(57): PDOStatement->execute() #1 C:\xampp\htdocs\api\users.php(30): dibdibs\pdo->query('SELECT * FROM `...', Array) #2 {main} thrown in C:\xampp\htdocs\scripts\sql.php on line 5
The PDO code works fine for other queries, when I am using = instead of LIKE, but is is throwing the above error when I try to use the LIKE clause.
I have put my full code on Pastebin, if you need to check it. I am using GET to get data, as I am using this with AJAX (which is also working fine), but the username I have tried is 'dibdibs', which works fine in other queries.
Use This
U can use any of these two
$query = $database->prepare('SELECT * FROM table WHERE column LIKE ?');
$query->execute(array('%value%'));
while ($results = $query->fetch())
{
echo $results['column'];
}
// without loop
$query = "SELECT * FROM tbl WHERE address LIKE ?";
$params = array("%$var1%");
$stmt = $handle->prepare($query);
$stmt->execute($params);
I am trying to get a database query page to work but cant seem to do so.
my Code so far (here I tried bindValue, but previously tried bindParam and got the same result):
var_dump($_POST);
$dbh = new PDO ("mysql:host=$myServer;dbname=$myDB", $myUser, $myPw);
$columName = $_POST["columName"];
$tblName = $_POST["tblName"];
$valueName = $_POST["valueName"];
$specificValue = $_POST["specificValue"];
$stmt = $dbh->prepare("SELECT :columName FROM :tblName Where :valueName = :specificValue");
$stmt->bindValue(":columName", $columName);
$stmt->bindValue(":valueName", $valueName);
$stmt->bindValue(":tblName", $tblName);
$stmt->bindValue(":specificValue", $specificValue);
$stmt->execute();
$result = $stmt->fetch();
if(empty($result)){echo "empty";}
print_r ($stmt);
print_r($result);
Printing result and $stmt brings following results:
empty
PDOStatement Object ( [queryString] => SELECT :columName FROM :tblName Where :valueName = :specificValue )
What did I do wrong? What could I try to get it to work?
I am new to the whole coding thing, so please ask if I forgot any code or other important information!
Thanks!
Placeholder parameters can only represent VALUES in the query. Tables, field names, sql key words, etc.. are all impossible to use placeholders on.
If you need to build a dynamic query and replace field/table names, then you'll have to use good old string construction methods, and be aware that you'll be opening yourself to SQL injection attacks again:
$sql = "SELECT * FROM $foo WHERE $bar = :baz";
$stmt = $dbh->prepare($sql);
$stmt->bindValue(':baz', $baz);
I'm afraid you need to rethink how parameterised queries work. It's not just a case of magically inserting data in a safe way. It's about distingushing between the structure of a query and the data.
So the database name, the column names, the table names and any SQL keywords are part of the structure of the query. Every time you run the query, they will be the same.
The data, however, can change between running the query.
So the structure needs to be in place when the query is prepared. However, you obviously can't just plonk the $columName variable etc into the query for SQL injection reasons. If you really need to have flexible queries like this (nb that you probably don't) you need to create a whitelist of allowed values, either in your code or retrieved from the database.
Your query is invalid (you're using parameters for object identifiers) but you are not getting any notification because you have neither configured PDO to throw exceptions nor are calling the error check functions manually.
Add the PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION option to PDO's constructor:
$dbh = new PDO ("mysql:host=$myServer;dbname=$myDB", $myUser, $myPw, array(PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION));
Once you do so, you'll get a prompt exception on the exact issue, e.g.:
PDOException: SQLSTATE[42000]: 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 ''user' Where 'login' = 'john'' at line 1 in [...]
As you can see, this is trying to run a query like (e.g.):
SELECT 'user_id'
FROM 'user'
Where 'login' = 'john'
Additionally, beware of SQL injection. It's terribly unsafe to compose SQL queries using data from $_POST.
I am using PDO, and am thrown an error when using the following code:
$stmt = $pdo->prepare("SELECT username FROM users WHERE
WHERE INSTR(`games`, '{$gameid}') > 0
");
$gameid = $gamedata['id'];
$stmt->execute(array(
':gameid'=>$gameid
));
$players = $stmt->fetch(PDO::FETCH_ASSOC);
Through looking at past answers this is supposed to work, however I am met with the following error:
Fatal error: Uncaught exception 'PDOException' with message 'SQLSTATE[42000]: 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 'WHERE
INSTR(`games`, 'crysis') > 0' at line 2' in C:\xampp\htdocs\gs\gamepage.php:19 Stack
trace: #0 C:\xampp\htdocs\gs\gamepage.php(19): PDOStatement->execute(Array) #1 {main}
thrown in C:\xampp\htdocs\gs\gamepage.php on line 19
It also appears it's grabbing 'games' as a literal and not the column
What am I doing wrong?
You have a double WHERE:
SELECT username FROM users WHERE
WHERE
You're also doing some funny things with $gameid, namely setting the variable after substitution, and binding an unused :gameid parameter. You also have a SQL injection vulnerability and should really use a parameter to pass $gameid instead of creating dynamic SQL.
You have the word games encased in "back quotes" and not "single quotes" like the {$gameid} variable is using. They are probably making the db engine assume it is a column name instead of text.
$stmt = $pdo->prepare('SELECT `username` FROM `users`
WHERE INSTR(`games`, :gameid) > 0;');
And you should use $stmt->bindValue() or $stmt->bindParameter() before executing the query.
This won't work if gameid is an ... INTEGER ! ? ! ?
I'm having a problem with a query prepared in PHP with PDO. The code:
$link = new PDO("mysql:dbname=$dbname;host=127.0.0.1",$username,$password);
$link->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
$query = $link->prepare("SELECT locality_name FROM :passedday GROUP BY locality_name ORDER BY locality_name DESC");
$query->bindParam(":passedday",$day); //Where day is, well, a day passed to the script elsewhere
$query->execute();
$result = $query->fetchAll();
$link = null;
//Do things with the $result.
The error message I am getting is:
SQLSTATE[42000]: 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 ''05_26_09' GROUP BY locality_name ORDER BY locality_name DESC' at line 1
When I execute the query on the server directly, it returns the appropriate result set without any problem. Any ideas what I'm doing wrong?
TIA.
Edit:
$day is passed as a GET argument. So, http://127.0.0.1/day.php?day=05_26_09 leads to $day = $_GET['day'];.
If 05_26_09 is supposed to bet the table's name, then I guess you've an escaping problem. Is your local operating system different from the live server?
I don't think you can use bindValue()/bindParam() for something else than values (eg. table name, field name). So I'm a bit suprised, that it works on your local system.
PDO uses mysql's C-API for prepared statements.
http://dev.mysql.com/doc/refman/5.0/en/mysql-stmt-prepare.html says:The markers are legal only in certain places in SQL statements. [...] However, they are not allowed for identifiers (such as table or column names)As a rule of thumb I use: "if you can't wrap it in single-quotes in an ad-hoc query string you can't parametrize it in a prepared statement"