Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

PHP PDO + Prepare Statement

Tags:

php

pdo

$sql='SELECT phrase,english FROM static_site_language WHERE page=?;';
$pds=$database->pdo->prepare($sql); $pds->execute(array($_POST['languagepage']));

The above code runs fine. However I need to put another variable into the prepare statement. I have tried the following but it doesn't seem to work:

$sql='SELECT phrase,? FROM static_site_language WHERE page=?;';
$pds=$database->pdo->prepare($sql); $pds->execute(array($_POST['language'],$_POST['languagepage']));

I know $_POST['language'] (from printing it) only contains the word 'english'. Is it possible to put a prepare variable in this part of a select?

thx

like image 316
Adam Avatar asked Dec 30 '11 02:12

Adam


1 Answers

Query parameters can take the place of only a constant value -- not a column name.

All columns and tables must be named at the time you prepare a query, you can't postpone choosing columns to the subsequent execute step.

When you want user input to determine a column name, use a Whitelist Map to limit user input to valid choices. The keys of the map array are the legal user inputs. The values of the map array are the strings you want to use in the SQL query, in this case column names.

$lang_col_map = array(
  "DEFAULT" => "english",
  "en"      => "english",
  "es"      => "spanish"
);
$lang_col = $lang_col_map[ $_POST["language"] ] ?: $lang_col_map[ "DEFAULT" ];

$sql='SELECT phrase,$lang_col FROM static_site_language WHERE page=?;';
$pds=$database->pdo->prepare($sql); 
$pds->execute(array($_POST['languagepage']));

This way you can be sure that only values in the $lang_col_map can become part of the SQL query, and if the user tries to send anything tricky in the http request, it's ignored because it doesn't match any key of that map. So the query is safe from SQL injection.

See my presentation SQL Injection Myths and Fallacies for more information.

like image 89
Bill Karwin Avatar answered Oct 07 '22 14:10

Bill Karwin