'IN' clause with multiple 'AND' Condition - php

I have a SQL query which is returning me an incorrect result.
" SELECT * FROM directory WHERE '".$_REQUEST['occupation']."' IN (occupation,pro_cat1,pro_cat2,pro_cat3,pro_cat4,pro_cat5) AND state = '".$_REQUEST['state']."' AND city = '".$_REQUEST['city']."' AND status = 1 ORDER BY rand() "
Here I want to check if occupation is one of the 6 values provided in the IN clause (while also adding some more clauses in the WHERE concatenated with an AND).
It does return me a result, however it is incorrect. Where have I gone wrong?

If the values you are looking for are strings, you need to quote them:
... IN ('occupation','pro_cat1','pro_cat2','pro_cat3','pro_cat4','pro_cat5') ...
^ here ^ etc.
You should also never inject variables directly into a query. Instead you should use a prepared statement with placeholders for your variables.
Also, column names should not be quoted (unless they are reserved words, contain spaces, etc.) but if you need to quote them, you should use back-ticks:
... directory where `".$_REQUEST['occupation']."` IN ...
^ here ^
Also note that table- and column names cannot be prepared so they always have to be white-listed before you inject them into your query.

Related

Concat statement in mysql with PHP causes mysqli_query to return false

I have the following query:
$sqlquery="SELECT CONCAT_WS(".",php_version_major, php_version_minor, php_version_build) AS phpversion, COUNT(id) AS COUNT, YEAR(createdate) AS YEAR, MONTH(createdate) AS MONTH FROM logs_checklist_interface GROUP BY phpversion, YEAR(createdate), MONTH(createdate) ORDER BY createdate ASC";
$rsData=mysqli_query($dblink,$sqlquery);
$rsData returns FALSE with this query. The cause seems to be the concat_ws statement. If I remove that it works fine. I've tried the other CONCAT function and it's the same result.
What is wrong with such a simple statement that causes mysqli_query() to get upset ?
If you do this:
$myString = "abc" . "xyz";
You get a string abcxyz, not abc"."xyz
I suppose that you think that " means something different to PHP in the cases where you intended it to be used as a string delimiter in an SQL expression.
$sqlquery="SELECT CONCAT_WS(".",php_version_major,
^ php quote ^ ^ sql string delimiters?
But unfortunately, that's not true. PHP sees both instances of " as PHP quotes. Therefore this is two PHP strings, using the PHP string concatenation operator ..
So the resulting SQL query is:
SELECT CONCAT_WS(,php_version_major, ...
This has a comma directly after the parenthesis, so it's nonsense syntax.

Removing/disabling backticks on variable in Active Record query in CodeIgniter

I'm trying to make a "between" query on my database using the Query Class of CodeIgniter, however, when adding a variable to the where clause, it adds backticks to the variable.
$this->db->select(TABLE_DISCOUNTSCARRIER.'.discount')->select(TABLE_DISCOUNTSCARRIER.'.idCarrier')
$this->db->from(TABLE_DISCOUNTSCARRIER);
$this->db->join(TABLE_DISCOUNTS, TABLE_DISCOUNTSCARRIER.'.idDiscount='.TABLE_DISCOUNTS.'.idDiscount');
$this->db->where(TABLE_DISCOUNTSCARRIER.'.idCarrier', $carrier);
$this->db->where($data['from'].' BETWEEN '.TABLE_DISCOUNTS.'.from AND '.TABLE_DISCOUNTS.'.to');
$this->db->or_where($data['to'].' BETWEEN '.TABLE_DISCOUNTS.'.from AND '.TABLE_DISCOUNTS.'.to');
Which is being parsed into this (the last two lines)
SELECT
discountbycarrier.discount,
discountbycarrier.idCarrier
FROM (discountbycarrier)
JOIN discounts
ON discountbycarrier.idDiscount=discounts.idDiscount
WHERE `discountbycarrier`.`idCarrier` = '6'
AND `5` BETWEEN discounts.from AND discounts.to
OR `10` BETWEEN discounts.from AND discounts.to
Already tried setting the $this->db->_protect_identifiers=false; but it removes the backticks on the rest of the statements but not the variables. Already tried using the intval() of the variable but neither this works.
As you can see the variable $carrier is correctly being parsed as integer.
Any ideas? Thanks in advance.
Change this
discounts.from
to
discounts.`from`
Or better (best practice) don't use reserved keywords for table columns, the word FROM is part of the query language, in other words.
Backticks are used to escape reserved keywords and spaces.
UPDATE
Something like this ( although I didn't look the documentation )
$this->db->where('? BETWEEN '.TABLE_DISCOUNTS.'.from AND '.TABLE_DISCOUNTS.'.to', $data['from']);
add this before the query
$this->db->_protect_identifiers=false;

Combine LIKE and IN in PHP MySQLi prepared statement

Trying to build a searchpage for an equipment database, and I have a prepared statement which takes an equipment 'tag' (always required) and searches a keyword in six different data fields where the 'tag' matches user input.
The problem is that no results are found if the keyword is IN one of these possibly long fields, so many intended results are missing.
In regular SQL I'd just to a table join and add a LIKE query to an IN query; but with mysqli I'm using a prepared statement with the ? placeholder and not sure what can be done about using this mark more than once for each variable.
The statement I have is this:
if (!($stmt = $conn->prepare("SELECT * FROM equipment
WHERE EQUIP_CND LIKE ?
AND (EQUIP_TYP LIKE ? OR ((EQUIP_SER LIKE ? OR EQUIP_PNO LIKE ?)
OR (EQUIP_LOC LIKE ? OR EQUIP_CMT LIKE ?)));"))) {
echo "Prepare failed: (" . $conn->errno . ") " . $conn->error;
}
And I want to just replace LIKE with LIKE IN. How to achieve this?
The like requires wildcards to have loose matching.
e.g.
select * from table where a like 'b'
is the same as:
select * from table where a = 'b'
so a record of b would be found but abc would not.
From the manual:
With LIKE you can use the following two wildcard characters in the pattern:
% matches any number of characters, even zero characters.
_ matches exactly one character.
So to find abc you'd use:
select * from table where a like '%b%'
For prepared statements the wildcards get appended to the variable, or in the binding, NOT in the query itself. Example 6 on the PDO manual page shows this. http://php.net/manual/en/pdo.prepared-statements.php#example-991 (after the comment // placeholder must be used in the place of the whole value)

MySQL IN clause - String and INT comparison

I have a stored procedure which takes in a single String parameter - the value passed into this parameter is a comma separated list of ID's from PHP - something like 2,3,4,5
`DECLARE tags_in VARCHAR(255);`
Within the Stored procedure I would like to select the rows which have ids corresponding to the ids in the parameter - the query would be like
`SELECT * from tags WHERE tag_id IN (tags_in)`
I pass in the values from PHP to MySQL using the following statement binding the value as a string
`$stmt->bindParam(':tags', '2,3,4', PDO::PARAM_STR);`
Problem - the actual query being executed by MySQL is as below - where the parameters passed in are considered as one string
`SELECT * from tags WHERE tag_id IN ('2,3,4')`
When the query I want executed is as below where the parameters are considered as individual integers
`SELECT * from tags WHERE tag_id IN (2,3,4)`
Any suggestions on I can accomplish this?
SQL placeholders can represent only SINGLE values. If you pass in some comma separated values, they won't be seen as multiple individual values with commas, they'll just be treated like a monolithic string.
e.g.
... WHERE foo IN (:bar)
... WHERE foo = :bar
are functionally identical as far as the SQL parser are concerned, and it won't make allowances for passing in your CSV values. Both will execute the same way:
... WHERE foo IN ('1,2,3')
... WHERE foo = '1,2,3'
You'll either have to limit yourself to only as many values as you have placeholders, or dynamically build your SQL and put in a placeholder for each individual value you're trying to put into the IN clause.
e.g.
$placeholders = array_fill(0, count($values_to_check) -1, '?');
$in_clause = implode(',', $placeholders);
/// builds ?,?,?,?,?,....?
$sql = "SELECT ... WHERE foo IN ($in_clause)";
$stmt = $dbh->prepare($sql);
$stmt->execute($values_to_check);
This is one place where prepared statements fall flat on their faces, and you have to fall back to good old "build some sql dynamically".
There is sometimes another way to accomplish the desired result by casting the integer you're trying to compare as a string surrounded by commas and checking if the result is contained in your list of possible values (with added commas on either side as well). It's not the most efficient for performance maybe, but it allows you to do what you want in a single procedure or query.
For example (in your case) something like this might work:
SELECT * from tags WHERE INSTR (CONCAT(',', tags_in, ','), CONCAT(',', tag_id, ',') );
MySql is a little bit weird in that it does the conversion from int to char within the CONCAT function, some other databases require explicit casting.

Using variable names as column names

I am creating an website where i am using user specified values as the column name of my table and it works fine but, when it comes to update it am unable to do it in the same process
here are my codes to create a column name from user specified value
mysqli_query($sql,"ALTER TABLE `cmpcheck` ADD `$emailID` VARCHAR( 100 ) NOT NULL ");
Here are my codes to update the above column
mysqli_query($sql,"UPDATE cmpcheck SET `$emailID` = `".$q."` LIMIT 1 ");
Any Help?
You are using the wrong quotes for your value:
mysqli_query($sql,"UPDATE cmpcheck SET `$emailID` = '".$q."' LIMIT 1 ");
^ ^
With a backtick (`) you are referencing to a column-name.
Besides that: make sure to properly escape both $emailID and $q
Backticks go around table and column names. You should use single quotes around string values.
mysqli_query($sql,"UPDATE cmpcheck SET `$emailID` = '$q' LIMIT 1 ");
Also, there's no reason to switch from variable substitution (as you do for $emailID) to concatenation with ..
It would be even better to use a prepared statement to substitute $q, instead of variable substitution into the query. But you can't do that for the column name.
You could try :
mysqli_query($sql,"UPDATE cmpcheck SET `".$emailID."` = '".$q."' LIMIT 1 ");
Also look at preparing your statements.

Categories