What is wrong with the SQL? - php

I'm trying to use PDO, so i got this together:
So, $_GET['word'] = "Jimi Hendrix" and $_GET['cat'] = "music".
$now = htmlentities(rawurldecode($_GET['word']));
$cat = htmlentities($_GET['cat']);
$dsn = 'mysql:dbname=DATABASE;host=localhost';
$user = "USER";
$password = "PASS";
# connect to the database
try {
$DBH = new PDO($dsn, $user, $password);
$DBH->setAttribute( PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION );
# the data to select
$data = array($cat, $now);
$STH = $DBH->prepare("SELECT id, name FROM ? WHERE name LIKE ?");
$STH->execute($data);
$result = $STH->fetchAll();
}
catch(PDOException $e) {
echo "Uh-Oh, something wen't wrong. Please try again later.";
file_put_contents('PDOErrors.txt', $e->getMessage(), FILE_APPEND);
}
echo "<pre>";
print_r($result);
echo "</pre>";
But the code above is returning:
SQLSTATE[42000]: Syntax error or access violation: 1064 You Have a Syntax error in your SQL near ''music' WHERE name LIKE 'Jimi Hendrix'' on line 1

You can't pass the table name as a parameter for the query. You'd need to construct/execute a dynamic SQL string.

It is probably because you are trying to insert the table name as a parameter. You may be able to do this as a stored procedure if necessary.

The category is converted into a string and when the query is prepared it is converted into:
SELECT id, name FROM 'cat' WHERE name 'music'
The table shouldn't be a string, what you can do is:
# the data to select
$data = array($now);
$STH = $DBH->prepare("SELECT id, name FROM $cat WHERE name LIKE ?");
$STH->execute($data);

As others have said, you cannot parameterize a table name with PDO (Or any other SQL interface that I know of).
You used to be able to find table naming conventions here:
http://www.mysql.com/doc/en/Legal_names.html
But it's been Larry Ellisowned.
I'd recommend finding a regex to validate MySQL table names and using that. A basic regex would be:
/[A-Za-z][A-Za-z0-9_]*/
But that wont account for reserved words.

Related

Postgresql not binding in prepared statement for SELECT in PHP

<?php
try
{
global $db;
$user = 'postgres';
$password = '*****'; //For security
$db = new PDO('pgsql:host=localhost;dbname=dnd', $user, $password);
$db->setAttribute( PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION );
}
catch (PDOException $ex)
{
echo 'ERROR!!: ' . $ex->getMessage();
die();
}
$table = htmlspecialchars($_REQUEST['table']);
$idNum = htmlspecialchars($_REQUEST['id']);
try {
//$query = "SELECT * FROM $table WHERE id = $idNum"; This works
//$query = "SELECT * FROM $table WHERE id = :number"; This works
$query = "SELECT * FROM :tableName WHERE id = :number";
$statement = $db->prepare($query);
$statement->bindValue(":tableName", $table, PDO::PARAM_STR);
$statement->bindValue(":number", $idNum, PDO::PARAM_INT);
$statement->execute();
$info = $statement->fetchAll(PDO::FETCH_ASSOC);
} catch (PDOException $excep) {
echo "Opps: " . $excep->getMessage();
die();
}
Okay I'm going crazy here trying to get this to work.
I have a database set up that I need to query from. I receive the query from an AJAX request with the name of the table I want and the id for the item. When I try to query with both variables, the binding does not occur in the prepared statement and instead I get this error code
Opps: SQLSTATE[42601]: Syntax error: 7 ERROR: syntax error at or near "$1" LINE 1: SELECT * FROM $1 WHERE id = 1 ^
When I have just the straight PHP variables it works fine so I know it can work, but when I want to bind multiple it seems to fail and give a variable number as above.
I can also get it to work if I simply have one of the variables bound, such as the second commented out query in the code - this only works tho if I have the variable I want at the end and not if I wanted to lookup the table spot. (I.E.
$query = "SELECT * FROM :tableName WHERE id = $idNum"; does not work)
I need to cleanse the variables to prevent SQL injection, but I can't do that without binding the variables in a prepared statement. Any help would be appreciated!
According to the PHP manual you can't bind a tablename. As you mentioned it, you can replace it by a variable, but you can't replace it with a placeholder.
So the only solution that will work for you is the query you have above:
$query = "SELECT * FROM $table WHERE id = :number"
This will be what you're looking for. If you want to make it safe for injection, you have to find another way. (Regex for example).
Ref: http://us3.php.net/manual/en/book.pdo.php#69304

IN statment on a MySQL INNER JOIN php pdo

i have an array i want to implode, then pass to a query and spit out all the matching values, but all i get is a 1064 violation, im sure its some silly syntax i've missed.
$filmImplode = implode("','", $filmList);
$query = "
SELECT
watch.film_id,
films.film_api_id
FROM
watch
INNER JOIN films ON films.film_id = watch.film_id
WHERE
films.film_api_id IN ('$filmImplode')
AND watch.user_id = :user_id";
$query_params = array(':user_id' => 1);
try {
$stmt = $db->prepare($query);
$getWatched = $stmt->execute($query_params);
} catch (PDOException $ex) {
echo 'something went wrong' . $ex->getMessage();
}
$getWatched = $stmt->fetchAll();
The SQL error reads
something went wrongSQLSTATE[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
'item0','item1','item2','itme3','item4' at line 3
I see 2 potential issues:
you may have film names with quote that will mess up your query. Escape them.
you have a space in your : user_id parameter
Try this:
array_walk($filmList, function(&$film){
$film = $db->quote($film);
});
$filmImplode = implode(",", $filmList);
$query = "
SELECT
watch.film_id,
films.film_api_id
FROM
watch
INNER JOIN films ON films.film_id = watch.film_id
WHERE
films.film_api_id IN ($filmImplode)
AND watch.user_id = :user_id";
$query_params = array(':user_id' => 1);
try {
$stmt = $db->prepare($query);
$getWatched = $stmt->execute($query_params);
} catch (PDOException $ex) {
echo 'something went wrong' . $ex->getMessage();
}
$getWatched = $stmt->fetchAll();
An even better approach, as suggested here, would be to build dynamically the IN condition writing the placeholders and to then bind the parameters in the prepare method.
The problem seems to be around filmImplode.
Are your film_api_ids int? If not, you should make sure they are passed as string constants in your SQL.
WHERE films.film_api_id IN ('XXX-123-XX', 'YYY-456-YY')
Instead of
WHERE films.film_api_id IN (XXX-123-XX, YYY-456-YY)
Also, those single quotes look shady, try without single quotes if all filmIds are integer.
WHERE films.film_api_id IN ($filmImplode)

PHP MYSQL SELECT Returns NULL

I executing the following code which creates a company_id as a UUID_SHORT in a temporary table.
This company_id will then be used to insert records in multiple tables with the UUID as the primary key. My issue is when I try retrieve the company_id that is $company_id in my code it is null. However if I json_encode ($tempResult) the company_id value is there. What am I doing wrong?
Any help is much appreciated, thank you!
try {
$conn = new PDO("mysql:host=localhost;dbname=$dbname", $db->id, $db->pass); //connect to db
$conn->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION); //error modes
$temp = $conn->prepare('CREATE TEMPORARY TABLE tempId (user_id VARCHAR(17) PRIMARY KEY, company_id VARCHAR(17))');
$temp->execute();
$temp = $conn->prepare('INSERT INTO tempId(user_id, company_id) VALUES(:user_id, UUID_SHORT())');
$temp->bindParam(':user_id', $_SESSION['username'], PDO::PARAM_INT);
$temp->execute();
$temp = $conn->prepare('SELECT company_id FROM tempId WHERE user_id = :user_id ');
$temp->bindParam(':user_id', $_SESSION['username'], PDO::PARAM_INT);
$temp->execute();
$tempResult= $temp->fetchAll(PDO::FETCH_ASSOC);
$company_id = $tempResult->company_id;
// $result[1] =$_SESSION('username');
} catch(PDOException $e) {
$result = $e->getMessage();
}
print json_encode($company_id);
Here:
$tempResult= $temp->fetchAll(PDO::FETCH_ASSOC);
If the fetchAll is successful, then $tempResult will be an array. For debugging, we can verify this using the convenient var_dump, e.g.
var_dump($tempResult);
If $tempResult is an array, I'm wondering about this expression:
$tempResult->company_id
What does that return? What do you expect that to return? Why?
EDIT: I know better than to answer a question with a question, or three questions.
However, I can't (in good conscience) bring myself to giving an "answer" to the problem with OP code...
at least not without (figuratively) scratching my head wondering about the actual SQL being used in the code.
What is the purpose of the TEMPORARY TABLE? Why is there an INSERT to it? Why is the UNSIGNED BIGINT datatype (returned by UUID_SHORT() function) being cast to a VARCHAR(17)? Is there some reason we want to lop off 1 or 2 digits when the function returns 18 or 19 decimal digits?
If the intent of this block of code is to return a value from MySQL UUID_SHORT() function, I'm not understanding why we need more than one statement. Obviously, there's something I'm missing, why this wouldn't suffice:
try {
$conn = new PDO("mysql:host=localhost;dbname=$dbname", $db->id, $db->pass);
$conn->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
$sth = $conn->prepare('SELECT UUID_SHORT() AS company_id');
$sth->execute();
$company_id = $sth->fetchColumn();
} catch(PDOException $e) {
//var_dump($e->getMessage);
} finally {
if(isset($sth)){ $sth->close(); }
if(isset($conn)){ $conn->close(); }
}
(An application wouldn't churn database connections like this; there would either be a connection pool, or the connection would be passed in to this routine.)
Not sure, but as soon as fetchAll returns array, your code:
$company_id = $tempResult->company_id;
is invalid, you should:
$company_id = $tempResult[0]['company_id'];
or
$tempResult= $temp->fetch(PDO::FETCH_ASSOC);
$company_id = $tempResult['company_id'];

How to prevent weird user inputs from breaking things in queries?

Is there a good standard solution to deal with characters like ' and " from being used in user inputs on a web platform?
I'm using php for a webpage and if I have, for example, a search bar which have the following query behind it.
$sql = "select * from aTable where aColumn like '%".$searchedKeyword."%'";
If I search for like Greg's icecream the ' will break the script. Also, I'm guessing if I search for something like 1' or ID>0 my script will have a false effect.
What is the common solution here? Do you usually filter away undesired characters, or is there maybe some method or similiar built-in to php?
You can us PDO and prepared statements to prevent SQL injection.
http://php.net/manual/en/pdo.prepared-statements.php
$searchedKeyword = "mykeyword";
//Database details
$db = 'testdb';
$username = 'username';
$password = 'password';
//Connect to database using PDO (mysql)
try {
$dbh = new PDO('mysql:host=localhost;dbname='.$db, $username, $password);
} catch (PDOException $e) {
var_dump("error: $e");
}
//Prepared SQL with placeholder ":searchedKeyword"
$sql = "select * from aTable where aColumn like '%:searchedKeyword%'";
$sth = $dbh->prepare($sql);
//Bind parameter ":searchedKeyword" to variable $searchedKeyword
$sth->bindParam(':searchedKeyword', $searchedKeyword);
//Execute query
$sth->execute();
//Get results
$result = $sth->fetchAll(); //fetches all results where there's a match

PHP Return ID[uniqueidentifier] after sql INSERT

Like the title says, I want the id of a row to be returned after INSERT to the database.
I've got 2 functions, one to make a connection to the database:
function db_connect() {
$host = "host";
$user = "user";
$pwd = "pwd";
$database = "db";
$con;
try{
$conn = new PDO( "sqlsrv:Server= ".$host." ; Database = ".$database." ", $user, $pwd);
}
catch(Exception $e){
die(print_r($e));
}
return $conn;
}
And one to insert a new record:
function setTiptile($name,$cols,$rows) {
$connect = db_connect();
$query = "INSERT INTO data(ID, name, cols, rows) VALUES(NEWID(),?,?,?)";
$stmt = $connect->prepare($query);
$stmt->bindValue(1, $name);
$stmt->bindValue(2, $cols);
$stmt->bindValue(3, $rows);
$stmt->execute();
return $connect->lastInsertId('ID'); // This should work, but doesn't, why?
}
I need the last function to return the ID of the inserted row, how should I do this?
EDIT:
Like the title says, the ID is an uniqueidentifier, no idea if that changes things.
EDIT: Ok, apparently I've got to use:$connect->lastInsertId('ID');, but this isn't returning anything at all. What can be the cause of that? The new row ís created in the database.
From the Manual:
Returns the ID of the last inserted row, or the last value from a
sequence object, depending on the underlying driver. For example,
PDO_PGSQL() requires you to specify the name of a sequence object for
the name parameter.
It should be something like:
return $connect->lastInsertId('yourIdColumn');
Use lastInsertId
$conn->lastInsertId();
(My) solution:
The parameter of lastInsertId() has to be the table name instead of the row name. Besides that, the table must have a row with the parameter IDENTITY checked, this is the row which is returned.
That brings to the conclusion that it's impossible to return a uniqueidentifier with lastInsertId() since this cannot have the parameter IDENTITY checked.
why not first do a select newid()
and then use that id in the insert

Categories