I'm trying to build a dynamic query based upon selections passed to a script. Example:
$qry = "SELECT * FROM machinekaart
INNER JOIN afleveradressen ON afleveradressen.raaid = mkrraaid
INNER JOIN kontaktpersonen ON kontaktpersonen.rkpraaid = mkrraaid
WHERE mkrrid != '' " ;
if($_SESSION['oud'])
$qry .= " AND mkrvo < " . $cur_jaar_maand;
Field mkrvo is a text field, and can contain yyyy-mm besides other values.
e.g. when the varable $cur_maand_jaar contains '2015-01' the selection will be everything lower than 2014
How can I stop this from happening and selecting everything lower than '2015-01' ??
I would suggest quoting that variable, so the values are taken literally:
if($_SESSION['oud'])
$qry .= " AND mkrvo < '" . $cur_jaar_maand . "'";
Better than that, please use PDO so you can use bindings, it's safer and best optimized.
Eg.
if($_SESSION['oud'])
$qry .= " AND mkrvo < ?";
// build your PDO Connection $myPdoConnection ...
$pdoStatement = $myPdoConnection->prepare($qry);
$pdoStatement->execute(array($cur_jaar_maand));
Within the SQL text, enclose the string literal in single quotes, so it's not evaluated as a numeric expression.
Evaluated in a numeric context: 2015-01 produces a value of 2014.
But '2015-01' is evaluated as a string literal.
(If the string literal is evaluated in a numeric context (e.g. '2015-01' + 0) the string will evaluate to a numeric value of 2015.)
The code you posted appears to be vulnerable to SQL Injection.
Consider what SQL text is generated when $cur_jaar_maand happens to evaluate to 0 OR 1=1 --.
A much better pattern is to make use of prepared statements with bind placeholders.
Related
We use doctrine 2 and want to write parameterised code like this:
attributes #> \'{' . $con->quote($attrId) . ':' . (int)$value . '}\'';
to have a query like this:
WHERE attributes #>'{"color":14}';
The "color" is the custom (user chosen) name of an attribute. So I feel that quote() is an appropriate function to shield it. But it wraps a parameter with single quotes, what makes the request syntax incorrect.
quoteIdentifier() function wraps with double quotes, BUT I'm not sure if it's right to use it in this context.
How to build a safe code to get the request I need?
Here is a way to do it with json_build_object and pg_exec_params:
<?php
$dbconn = pg_connect('');
$data = 'some"th\'ing';
pg_query_params($dbconn, 'SELECT json_build_object($1::text, $2::integer)', [$data, 14]);
?>
You need the explicit type casts so that PostgreSQL knows whether the argument is a string or a number.
You can include the double quotes in the string.
$attr = '{"' . $attrId . '":' . (int) $value . '}';
Don't depend on quoting to keep you safe, but instead execute the query with a method that binds the value to a prepared statement.
$statement = $con->executeQuery('SELECT * FROM your_table WHERE attributes #> ?', [$attr]);
I have a variable that is a filter for my query:
$filterString.=" AND venue = ".$venue;
And I want this variable (when called) to add the AND filter statement to my query.
My query is as follows (with the failed attempt):
mysql_query("SELECT * FROM event
WHERE city = '$city' " . $filterString . "
ORDER BY date ASC");
I think the venue needs to be surrounded by single quotes:
$filterString.=" AND venue = '".$venue.".";
However, it is better to use parameterized queries, instead of embedding queries directly in the SQL string.
You could use:
$filterString .= !empty($venue) ? " AND venue = '$venue'" : '';
Substitute whatever test you want at the start, the idea is to return a blank string if $venue doesn't apply to the filter.
To answer your other comment question:
WHERE 1
is a valid condition that works like Anything
I have some columns type int, but value is empty. So I want to convert empty to null when I insert to database.
I use code:
function toDB($string) {
if ($string == '' || $string == "''") {
return 'null';
} else {
return "'$string'";
}
}
//age,month,year is type integer.
$name="Veo ve";
$age='10';
$month='';
$year='';
$query="Insert Into tr_view(name,age,month,year) values ({toDB($name)},{toDB($age)},{toDB($month)},{toDB($year)})
$db->setQuery($query);
$result= $db->query();
But it show error:
pg_query(): Query failed: ERROR: syntax error at or near ";" LINE 153: {toDB(10)}, ^ in...
Why?
There is the NULLIF() function:
SELECT NULLIF(var, '');
If var equals the 2nd parameter, you get NULL instead.
The example replaces the empty string '' with NULL.
There is no "empty string" for the type integer. Both parameters must be of compatible type, so sanitize your input in PHP.
If you did not define a column default, you can also just omit the column in the INSERT command and it will be filled with NULL (which is the default DEFAULT).
Check if the parameter is empty in PHP and don't include the column in the INSERT command if it is.
Or use the PHP literal NULL instead like Quassnoi demonstrates here.
The rest only makes sense for string types
To make absolutely sure, nobody can enter an empty string add a CHECK constraint to the table:
ALTER TABLE tr_view
ADD CONSTRAINT tr_view_age_not_empty CHECK (age <> '');
To avoid exceptions caused by this, you could add a trigger that fixes input automatically:
CREATE OR REPLACE FUNCTION trg_tr_view_avoid_empty()
RETURNS trigger
LANGUAGE plpgsql AS
$func$
BEGIN
IF NEW.age = '' THEN
NEW.age := NULL;
END IF;
IF NEW.month = '' THEN
NEW.month := NULL;
END IF;
RETURN NEW;
END
$func$;
CREATE TRIGGER tr_view_avoid_empty
BEFORE INSERT OR UPDATE ON tr_view
FOR EACH ROW
WHEN (NEW.age = '' OR NEW.month = '')
EXECUTE PROCEDURE trg_tr_view_avoid_empty();
While Erwin's answer about NULLIF is awesome, it doesn't address your syntax error.
Let's take a look at the query:
$query="Insert Into tr_view(name,age,month,year) values ({toDB($name)},{toDB($age)},{toDB($month)},{toDB($year)})
Earlier you defined a function called toDB. Unfortunately the syntax you are using here is not how to call a function from within a double-quoted string, so the curlies and toDB( bits are still being passed through. There are two alternatives:
Concatenation using .:
$query='insert Into tr_view(name,age,month,year) values (' . toDB($name) . ',' . toDB($age) . ',' . toDB($month) . ',' . toDB($year) . ')')
You can interpolate a callable variable into a double-quoted string thusly:
$fn = 'toDB';
$query="Insert Into tr_view(name,age,month,year) values ({$fn($name)},{$fn($age)},{$fn($month)},{$fn($year)})";
The first is clear and sane, the second is vague to the unfamiliar and downright insane.
However, you still should not be assembling input like this. You still may be vulnerable to SQL injection attacks. You should be using prepared statements with parameterized placeholders.
The Postgres extension uses pg_prepare for this. They have the distinct advantage of, say, allowing you to pass a PHP null instead of having to worry about all of that null-detection and quoting.
If you insist on keeping toDB as-is, consider adding one of the pg_escape_ functions, like pg_escape_string, to the thing that builds quoted strings.
I am trying to use session variable($_SESSION['asc_id'], which holds some value like "AS0027001") in an SQL statement, but it is not working.
When I hardcode the value, it is providing results.
Can anyone please correct me.
MySQL query which is not working
$asc_id = $_SESSION['asc_id'];
$rs = mysql_query('select asc_lastname, asc_firstname, asc_middlename, lname_fname_dob
from issio_asc_workers where asc_user_type = 31
and asc_id = "$asc_id"
and lname_fname_dob like "' .
mysql_real_escape_string($_REQUEST['term']) .
'%" order by lname_fname_dob asc limit 0,10', $dblink);
Mysql query which is working
$rs = mysql_query('select asc_lastname, asc_firstname, asc_middlename, lname_fname_dob
from issio_asc_workers where asc_user_type = 31
and asc_id = "AS0027001" and lname_fname_dob like "' .
mysql_real_escape_string($_REQUEST['term']) .
'%" order by lname_fname_dob asc limit 0,10', $dblink);
Variable substitution only works within double quoted strings, not single quoted ones. In other words, you should do;
$rs = mysql_query("select .... and asc_id = '$asc_id' and ... limit 0,10", $dblink);
Btw, you did make sure the value doesn't include any characters that may lead to SQL injection, right? Otherwise you should use mysql_real_escape_string to make sure before inserting it into a query.
When you print the strings, it will be clear. When the question is reformatted to leave the SQL readable, the problem is clear. (The first rule for debugging SQL statements is "print the string". A second rule, that makes it easier to comply with the first, is always put the SQL statements into a string which you pass to the SQL function.)
You use the . notation to embed the request term in the string; you don't use that to embed the $asc_id into the string. You should also use mysql_real_escape_string() on the session ID value to prevent SQL injection.
First print the variable $asc_id . If it displays nothing, session is unavailable . In that case you missed session_start() in top of the current executing page .
From the SQL query, you cannot replace the value of a variable inside single quoted string .
Use . symbol for mixing string value with variable or use double quoted string . I prefer first one .
For troubleshooting , simplest method is printing variable values. From the result , you will understand what is missing .
Thanks
Try this. from the comment you added, I modified it like this
session_start(); //add this if you did not do it yet
$asc_id = $_SESSION['asc_id'];
$rs = mysql_query("select asc_lastname, asc_firstname, asc_middlename, lname_fname_dob
from issio_asc_workers where asc_user_type = 31
and asc_id = '$asc_id'
and lname_fname_dob like '".
mysql_real_escape_string($_REQUEST['term']) .
"%' order by lname_fname_dob asc limit 0,10", $dblink);
Let's say I have a query:
" SELECT * FROM table
WHERE donor_id = " .$this->session->userdata('id') ."
GROUP BY rating"
However, it appears that I get a mysql syntax error here, citing that $this->session->userdata('id') gives me '25' for example, instead of 25. Are there any workarounds here to prevent $this->session->userdata('id') from being quoted?
Thanks.
In CI, I do this all the time:
$id = intval($this->session->userdata('id'));
$sql = " SELECT * ".
" FROM table ".
" WHERE donor_id = {$id} ".
"GROUP BY rating ";
//process $sql below
Creating query like this will make you easier to spot bug and prevent SQL injection. Use concatenation when you need to split query to multiple lines instead of make it a long multiple string is to prevent the actual query string got too long. Indent the SQL keyword is to make it easier spot logical and syntax bug.
intval($this->session->userdata('id'))
Assuming you mean that it is returning you a string instead of an integer you could always try using settype or intval:
$var = '2';
settype($var, "integer");
$var = intval($var);
However, if you mean that the quotes are for some reason hard-coded in, you could do a string replace, if you are sure that the value will not contain quotes:
ech str_replace("'", "", "'2'"); // prints 2