I'm using PDO with ODBC from PHP7.4 to SQLServer 12 with this Connection String:
$conn = new PDO('odbc:DRIVER={SQL Server};SERVER=MyServer,1433;Database=MyDatabase;', 'MyUser', 'MyPass');
A regular query with an Integer parameter returns data:
$SQL = <<<EOL
Select
[10-Digit Groups].[Area Code],
[10-Digit Groups].[Group]
From
[10-Digit Groups]
Where
[10-Digit Groups].[Area Code] = ?
EOL;
$stmt = $conn->prepare($SQL);
$ac1 = 602;
$success = $stmt->bindParam(1, $ac1);
$success = $stmt->execute();
foreach($stmt as $row){
var_dump($row);
}
So I add a subquery (Ctr1):
$SQL = <<<EOL
Select
[10-Digit Groups].[Area Code],
(Select Count(*) From [10-Digit Groups]) Ctr1,
[10-Digit Groups].[Group]
From
[10-Digit Groups]
Where
[10-Digit Groups].[Area Code] = ?
EOL;
$stmt = $conn->prepare($SQL);
$ac1 = 602;
$success = $stmt->bindParam(1, $ac1);
$success = $stmt->execute();
foreach($stmt as $row){
var_dump($row);
}
And it fails with:
//Uncaught PDOException: SQLSTATE[22018]: Invalid character value for cast specification: 206 [Microsoft][ODBC SQL Server Driver][SQL Server]Operand type clash: text is incompatible with int (SQLExecute[206] at ext\pdo_odbc\odbc_stmt.c:259)
I can perform similar queries with STRING parameters, but they fail with this error:
//Uncaught PDOException: SQLSTATE[42000]: Syntax error or access violation: 402 [Microsoft][ODBC SQL Server Driver][SQL Server]The data types nvarchar and text are incompatible in the equal to operator. (SQLExecute[402] at ext\pdo_odbc\odbc_stmt.c:259)
I've tried setting and unsetting these:
$conn->setAttribute(PDO::ATTR_EMULATE_PREPARES, false);
$conn->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
And I've tried setting the DataType in PDO:
$success = $stmt->bindParam(1, $a1, PDO::PARAM_STR); //Or PDO::PARAM_INT where appropriate
I've also hard-coded the parameter values into the SQL to ensure they work.
I've also tried passing the parameters in the 'execute' statement:
PDO->execute([602])
I've also tried converting both sides of the WHERE clause to nvarchar or int.
Everything works as normal with no subquery, but once it's there, the Prepared Statement fails.
Any suggestions to try (Driver String, Subquery Nesting Strategies, other PDO Attribute adjustments, etc.)?
I fixed this with 2 actions:
Install "ODBC Driver 11 for SQL Server" from Microsoft (search for it)
And change
DRIVER={SQL Server};
to
DRIVER={ODBC Driver 11 for SQL Server};
It caused a couple of rewrites, but for the most part was a direct replacement.
It allows for multiple parameters alongside subqueries.
All examples above work fine with this change.
P.S. This change also works for non-PDO odbc commands in PHP.
I have some HANA queries which use PLACEHOLDER input and of course I want to prevent an sql injection.
I try to use ? in odbc_prepare()
$query = <<<SQL
SELECT
col,
...
FROM table_name('PLACEHOLDER'=('$$some_key$$', ?))
WHERE col = ?
SQL;
$stmt = \odbc_prepare($conn, $query);
if ($stmt !== false) {
\odbc_execute($stmt, ['placeholder_value', 'where_value']);
}
but I receive this warning:
Warning: odbc_prepare(): SQL error: [SAP AG][LIBODBCHDB SO][HDBODBC] Syntax error or access violation;257 sql syntax error: incorrect syntax near "?": line 32 col 40 (at pos 1283), SQL state 37000 in SQLPrepare
and statement wasn't created. So my code now looks like this:
$query = <<<SQL
SELECT
col,
...
FROM table_name('PLACEHOLDER'=('$$some_key$$', 'placeholder_value'))
WHERE col = ?
SQL;
$stmt = \odbc_prepare($conn, $query);
if ($stmt !== false) {
\odbc_execute($stmt, ['where_value']);
}
As I see here htmlspecialchars() is not enough to prevent an SQL injection.
I can't remove input placeholder, I don't own HANA.
Is there any other way to prevent SQL injection in PLACEHOLDER?
The (old) placeholder syntax ('PLACEHOLDER'=('<varname>', '<var value>')) you're using here does not allow for bind variables.
Instead, the new placeholder syntax (PLACEHOLDER."<varname>"=>?) allows using bind variables.
In your code this would look like this:
$query = <<<SQL
SELECT
col,
...
FROM table_name (PLACEHOLDER."$$some_key$$" => ?)
WHERE col = ?
SQL;
$stmt = \odbc_prepare($conn, $query);
I want to submit the query as a prepared statement, like below.
$query = $this->createQuery();
$query->getQuerySettings()->usePreparedStatement(TRUE);
$sqlParamList[] = 'test#gamil.com';
$sql = 'SELECT uid FROM table_name WHERE email = ?';
$query->statement($sql, $sqlParamList);
$result = $query->execute();
But I always get errors like below.
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 '?' at line 1'
Where I am wrong?
You need to parse your $sql to a prepared statement first:
$preparedSql = $this->objectManager->get(\TYPO3\CMS\Core\Database\PreparedStatement::class, $sql, 'table_name');
With $this->objectManager->get() you instantiiate the class PreparedStatement with the arguments $sql and 'table_name'.
This will change your $sql and parse the ? to be used as prepared statement.
Another approach:
$query = $this->createQuery();
$query->getQuerySettings()->usePreparedStatement(TRUE);
$sqlParamList = [
':email' => 'test#gamil.com'
];
$sql = 'SELECT uid FROM table_name WHERE email = :email';
$query->statement($sql, $sqlParamList);
$result = $query->execute();
Cannot test it, just an approach.
I need to update my database so I write:
try {
$STH = $db->prepare("UPDATE zemljiste (naziv, ha, ar, m2, udeo_ha, udeo_ar, udeo_m2, lokacija, osnov, kat_kul, 2013_kol, ocekivano) VALUES (:1,:2,:3,:4,:5,:6,:7,:8,:9,:10,:11,:12) WHERE id = :id_akt AND user_id=:13");
$STH->bindParam(':id_akt', $_POST['naziv']);
$STH->bindParam(':1', $_POST['naziv']);
$STH->bindParam(':2', $_POST['ha']);
$STH->bindParam(':3', $_POST['ar']);
$STH->bindParam(':4', $_POST['m2']);
$STH->bindParam(':5', $_POST['udeo_ha']);
$STH->bindParam(':6', $_POST['udeo_ar']);
$STH->bindParam(':7', $_POST['udeo_m2']);
$STH->bindParam(':8', $_POST['lokacija']);
$STH->bindParam(':9', $_POST['osnov']);
$STH->bindParam(':10', $_POST['kultura']);
$STH->bindParam(':11', $_POST['prinos_2013']);
$STH->bindParam(':12', $_POST['ocekivano']);
$STH->bindParam(':13', $user_id);
$STH->execute();
but I get error:
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 '(naziv, ha, ar,
m2, udeo_ha, udeo_ar, udeo_m2, lokacija, osnov, kat_kul, 2013_ko' at
line 1Data submitted successfully
How I can solve this?
What is exactly error in my code?
UPDATE syntax is wrong and you should avoid integer placeholders
$query ="UPDATE `zemljiste`
SET naziv = :naziv, ha = :ha, ar = :ar, m2 = :m2, udeo_ha = :udeo_ha,
udeo_ar = :udeo_ar, udeo_m2 = :udeo_m2, lokacija=:lokacija, osnov = :osnov,
kat_kul = :kultura, 2013_kol=:prinos_2013, ocekivano = :ocekivano
WHERE id = :id_akt AND user_id=:user_id";
$STH = $db->prepare($query);
$STH->bindParam(':id_akt', $_POST['naziv']);
$STH->bindParam(':naziv', $_POST['naziv']);
$STH->bindParam(':ha', $_POST['ha']);
$STH->bindParam(':ar', $_POST['ar']);
$STH->bindParam(':m2', $_POST['m2']);
$STH->bindParam(':udeo_ha', $_POST['udeo_ha']);
$STH->bindParam(':udeo_ar', $_POST['udeo_ar']);
$STH->bindParam(':udeo_m2', $_POST['udeo_m2']);
$STH->bindParam(':lokacija', $_POST['lokacija']);
$STH->bindParam(':osnov', $_POST['osnov']);
$STH->bindParam(':kultura', $_POST['kultura']);
$STH->bindParam(':prinos_2013', $_POST['prinos_2013']);
$STH->bindParam(':ocekivano', $_POST['ocekivano']);
$STH->bindParam(':user_id', $user_id);
$STH->execute();
You're using a syntax for INSERT statement in UPDATE, which is wrong.
It should look like this,
UPDATE table SET key=:value, key1=:value1 WHERE id=:id AND foo=:bar. So just replace,
"UPDATE zemljiste (naziv, ha, ar, m2, udeo_ha, udeo_ar, udeo_m2, lokacija, osnov, kat_kul, 2013_kol, ocekivano) VALUES (:1,:2,:3,:4,:5,:6,:7,:8,:9,:10,:11,:12) WHERE id = :id_akt AND user_id=:13"
with
UPDATE zemljiste SET naziv =:1, ha =:2, ...... WHERE id=:id_akt AND user_id = :13
You are using the wrong syntax for update. It should be:
UPDATE zemljiste SET naziv=:1, ha=:2, ar=:3, ... WHERE ...
How to place a php variable into query?
$shopid = $pdo->query('SELECT shopid FROM `shop` WHERE shopname='$shopname'')->fetchAll(PDO::FETCH_ASSOC);
This is not working, the error message show:
"Parse error: syntax error, unexpected '$shopname' (T_VARIABLE)"
No
Do not insert parameters this way. You should be using bindParam
$statement = $db->prepare('SELECT shopid FROM shop WHERE shopname=:shopname');
$statement->bindParam(':shopname', $shopname, PDO::PARAM_STR);
$statement->execute();
If $shopname is coming from an untrusted source, you are wide open to SQL injection. To fix this, you should make use of PDO and it's prepared statement API:
$query = $pdo->prepare("SELECT shopid FROM shop WHERE shopname = ?");
$query->bindValue(1, $shopname, PDO::PARAM_STR);
$query->execute();
$shopid = $query->fetchAll(PDO::FETCH_ASSOC);
if you support the PDO ,why not use the prepare, and it is more safe.
$stmt = $pdo->prepare('SELECT shopid FROM shop WHERE shopname=:shopname');
$stmt->bindParam(':shopname', $shopname);
$shopname = $yourdefined;
$stmt->execute();
$stmt->bindColumn(1, $shopid);
while($stmt->fetch()){
echo $shopid,PHP_EOL;
}
Well,you can also use the base sql like this:
$shopid = $pdo->query('SELECT shopid FROM `shop` WHERE shopname=\'{$shopname}\'')->fetchAll(PDO::FETCH_ASSOC);
You weren't wrapping your query properly.
$shopid = $pdo->query("SELECT shopid FROM `shop` WHERE `shopname`='$shopname'");
Try This:
$query = "SELECT shopid FROM shop WHERE shopname= '".$shopname."'";
$result = mysql_query($query);