Error with PHP parameters in SQL function call - php

I have two PHP variables in a class that are integers ($id and $descCode).
I'm trying to get these into my SQL function call as characters (the database is looking for these to be CHAR 2 and CHAR 10 respectively).
For some reason, this is triggering an error:
Use of parameter marker or NULL not valid
What exactly am I doing wrong here?
$results = array();
$results = $db->select("SELECT newCodeTest(:id,:desc) as newCode FROM testTable",
[
'id' => (string)$id,
'desc' => (string)$descCode
]
);

You can not use PDO in this way.
Look at this (possible duplicate): Can PHP PDO Statements accept the table or column name as parameter?.
Set those values as basic string
$id = $pdo->quote($id);
$desc = $pdo->quote($desc);
"SELECT newCodeTest({$id},{$desc}) as newCode FROM testTable"
Info about quoting:
https://www.php.net/manual/en/pdo.quote.php
Interesting info about performance
https://www.php.net/manual/en/pdo.quote.php#122967

Related

Is the in_array function a safe way of blocking code injection/sql injection?

If i have a php file which is receiving a $_GET['value'] is it safe from sql injection or code-injection for me to start my php file with
if (in_array($_GET['value'], $allowed_values);)
{ /* normal page code handling the $_GET['value'] */
} else { unset($_GET['name'])
}
$allowed values is obviously an array of all values which i am expecting as safe for $_Get['value']. Is this still unsafe? Thank you.
Yes, that's a common and safe technique that can be used in situations where query parameters can't be used. For instance, if the value will be used as a table or column name, you can't provide it as a query parameter, you have to substitute it directly into the SQL string. Whitelisting like this is the recommended way to ensure that this is safe.
It depends on the values in the $allowed_values array, and how you are interpolating the value into your SQL query.
For example:
$allowed_values = [ 'a word' ];
if (in_array($_GET['value'], $allowed_values)) {
$sql = "SELECT * FROM mytable WHERE id = {$_GET['value']};";
}
Definitely not safe. It results in the SQL:
SELECT * FROM mytable WHERE id = a word;
This is a syntax error.
Why would you not just use SQL query parameters? Then you don't need to worry if it's safe or not. Query parameters separate the values from the SQL parsing, so there's no way any kind of value can cause SQL injection.
You won't have to have an $allowed_values array. You won't have to remember to check if the GET input is in the array. You won't have to worry about quoting or escaping.
It's true that query parameters only work for values, that is in place of a quoted string literal or quoted datetime literal or numeric literal. If you need other parts of your query to be dynamic, like the table name or column name or SQL keywords, etc. then use an allow-list solution like you are showing.
But the more common case of interpolating dynamic values is better handled by query parameters:
$sql = "SELECT * FROM mytable WHERE id = ?";
$stmt = $pdo->prepare($sql);
$stmt-execute( [ $_GET['value'] ] );
let's discuss this thing in little details:
Your code is like this :
if (in_array($_GET['value'], $allowed_values);) {
...........
$sql = "SELECT * FROM mytable WHERE id = $_GET['value']";
...........
}
else {
unset($_GET['name'])
}
now let's assume, you have some values :
the in_array() function will allow only some pre-defined values, you couldn't have the option to take custom user input by $_GET, but as only pre-defined values are allowed,any SQL command will be safe inside if statement.
now take this example of $allowed_values array :
$allowed_values = ['some details' , 'another details' ,3, ' 105; DROP TABLE mytable;', 22 , 'ok'];
If any of these array values have a string that can have potential SQL injection capability, then there will be an issue. but I think you will not put any such string in the array $allowed_values. ( in this above-mentioned example, index 3, ' 105; DROP TABLE mytable;' can delete the table mytable ). else the SQL command will be safe.
now you can add an extra layer of safety in the code, by using PDO for any SQL query. (in this example you do not need that, as in_array() function is 100% safe unless you yourself put any malicious code in the array, as per my above-mentioned example). but for other types of user input where you have to do some SQL query depend on the user input, you can use PDO -prepared statement.
a PDO example is this :
$servername = "localhost";
$username = "username";
$password = "password";
$dbname = "myDBPDO";
$conn = new PDO("mysql:host=$servername;dbname=$dbname", $username, $password);
// set the PDO error mode to exception
$conn->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
$stmt = $conn->prepare("INSERT INTO photos (username, kname) VALUES (?, ?)");
$stmt->execute([ $username , $kname ]);
For more info, try w3school link: https://www.w3schools.com/php/php_mysql_prepared_statements.asp

PHP and MySQL, call_user_func_array doesn't work with variable as argument

I'm trying to set up a dynamic MySQL query, using mysqli prepared statements. I need to compare multiple values (unknown how many) to a single column.
The following works:
$qs = '?,?';
$query = 'SELECT r_id FROM sometable WHERE someindex IN ('.$qs.')';
$statement = $db_conn->prepare($query);
call_user_func_array(array($statement, 'bind_param'), array('ss', 'Something', 'somethingelse'));
I get a result back from the DB, and can do as I please with the return. BUT, the following does not work:
$qs = '?,?';
$query = 'SELECT r_id FROM sometable WHERE someindex IN ('.$qs.')';
$statement = $db_conn->prepare($query);
$test = array('ss', 'Something', 'something else');
call_user_func_array(array($statement, 'bind_param'), $test);
With the only difference being the assignment of $test, instead of creating the array directly within call_user_func_array.
Similarly:
$one = 'pizza';
$two = 'pie';
call_user_func_array(array($statement, 'bind_param'), array('ss', $one, $two));
also does not work. The statement doesn't even execute.
If I can't put variable names directly into the statement, I can't have the dynamic queries. What's going on? Is there a fix for this, or maybe another (equally simple) way I can run a query on a single column, with an unknown number of terms? References or pointers (i.e. &$one) do not work either.
There seems to be a couple known issues with call_user_func_array back in 2012, or around there, but I can't find anything more recent. I am using PHP 5.5
EDIT 1
Known issue, back in 2007 here

having problems to execute a PHP code with simple mySQL query

I am trying to execute a query with a WHERE clause but it looks like the id I retrieve needs to be perhaps converted from an array into something else. I am new to PHP so I am struggling a little:
...some previous query here
$sharepoint_id = $data[0];
//returns Array([ID] => a5f415a7-3d4f-11e5-b52f-b82a72d52c35)
qry = mysql_query("SELECT HostName FROM MSSWireList WHERE id=".$sharepoint_id);
$data = array();
while($rows = mysql_fetch_array($qry))
{
$data[] = array(
"ID" => $rows['ID'],
"Record" => $rows['Record'],
"HostName" => $rows['HostName']
);
}
return json_encode($data);
also tried $sharepoint_id = $data[0]->ID;
Thank you
"returns Array([ID] => a5f415a7-3d4f-11e5-b52f-b82a72d52c35)"
That's a string and not an integer. The variable in your WHERE clause needs to be quoted.
WHERE id='".$sharepoint_id."' ");
Checking for errors would have signaled the syntax error.
Add or die(mysql_error()) to mysql_query().
Ref: http://php.net/manual/en/function.mysql-error.php
Your present code is open to SQL injection. Use mysqli_* with prepared statements, or PDO with prepared statements.
Edit:
You only selected the HostName column from your query and not the other two, ID and Record.
However, when going over a loop, row names are case-sensitive.
So, if your row's case is id as opposed to ID, then that will matter in your loop.
$rows['ID'] and $rows['id'] are two different animals.
Sidenote:
Pulled from a comment I asked already:
qry = mysql_query if that your real code, it's missing a $ for qry.
And if so, error reporting would have thrown you an undefined constant qry notice.
http://php.net/manual/en/function.error-reporting.php
I won't take you to task for using the old mysql driver instead of mysqli or PDO, or for not using a prepared statement - I'll leave that for others to do - but
"...WHERE id = '" . $sharepoint_id['ID'] . "'"
should do the job.

Proper way to escape query in Codeigniter [duplicate]

This question already has answers here:
Update the value of a field in database by 1 using codeigniter
(3 answers)
Closed 24 days ago.
$sql = ("update Inventory SET ? = ?+1 WHERE ID= ?");
$query = $this->db->query($sql, array($field,$field,$id))->affected_rows();
The error:
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 ''Upvotes' = 'Upvotes'+1 WHERE ID= 386464' at line 1
Basically it's adding quotes around the Upvotes field causing it to be a malformed query what's the most practical way to remove the single quotes or rewrite the query entirely?
The answers here arn't quite right, as they are expecting you to already have the upvote count. I think this is what you're looking for:
$this->db->where('ID', $ID);
$this->db->set('Upvotes', 'Upvotes+1', FALSE);
$this->db->update('Inventory');
Use the line below to confirm the output it should give you something like:
echo $this->db->last_query();
UPDATE Inventory SET Upvotes = Upvotes+1 WHERE ID = 386464
The third paramater of false tells CI to not protect the query with backticks.
When possible, try to use CI's query builder to lower the chances of syntax errors. As per Codeigniter Documentation:
$data = array(
'title' => $title,
'name' => $name,
'date' => $date
);
$this->db->where('id', $id);
$this->db->update('Inventory', $data);
In your case, you are probably looking for something like this:
$data = array(
'Upvotes' => $upvotes + 1
);
$this->db->where('CARD_ID', '386464');
$this->db->update('Inventory', $data);
Now, if you want to run a custom code that you cant run using CI's query builder class, then do this:
$custom_sql = "update Inventory SET Upvotes = Upvotes + 1 WHERE CARD_ID = 86464";
$query = $this->db->query($custom_sql);

Doctrine andWhere orWhere doesn't seem to bind more than one parameter

I have a query like this:
$name = "field1";
$name2 = "field2";
$value = "searchTerm";
$query->select('*')->
from("TableName")->
where($name . " = ?", array($value))->
andWhere($name2 . " = ?", array($value));
I was suprised to see that when this executes the query generates MS SQL Error 102 (syntax error) because the query sent to sql server looks like this:
SELECT * FROM TableName WHERE field1 = 'searchTerm' AND field2 = ?
The question mark was taken literally in each additional condition added to the query! :o
Perhaps I am doing something wrong and someone can set me straight here.
Whew! I found the answer!
For whatever reason doctrine does not use PDO's prepared statement functionality for SQL server. Connection/Mssql.php substitutes any parameters within the query string and passes an empty array to Connection::execute. This would be fine:
If the prepared statements didn't work (maybe they didn't work in sql 2000 when the connection driver was first written?) :/
If the substitution actually successfully substituted more than one value! :o
The fix is easy:
in Connection/Mssql.php on line 314 change the execute function below:
public function execute($query, array $params = array())
{
if(! empty($params)) {
$query = $this->replaceBoundParamsWithInlineValuesInQuery($query, $params);
}
return parent::execute($query, array());
}
to:
public function execute($query, array $params = array())
{
return parent::execute($query, $params);
}
You could just as easily remove the overridden function.
Don't forget to make the same changes to exec which appears just below the execute function in the same code file.
Also, you may wish to test this before using it with versions of SQL server earlier than 2005 as I have not tested this solution with that version.

Categories