Wildcard in prepared MySQLi returning bad values - php

Please see the bottom of this post for newest information and current status
Following advise from posts like this one:
Using wildcards in prepared statement - MySQLi
I have my statement set up and it works with no errors. But it does not return the correct data.
My select statement has this for the WHERE:
WHERE `Name` LIKE ? order by `Name`
My string to set up the binding, and then the actual binding.
$whatToBind = '%'. $whatName .'%';
$stmt = $mysqli->prepare($selectStr);
$stmt->bind_param('s', $whatToBind);
$stmt->execute();
When I get my return, it will completely miss records that it should match.
Like, if I send in "Ken L", I get back records for "Ken Linton" but not "Ken Lawton". If I put in "Lawton", I get no return at all.
This is typical behavior across the board. If I search a phone number field, I get returns on "658", but no returns on "609-658".
If anyone can clue me in on what I'm missing, that would be great.
Example returns that show the exact examples I'm referring to:
Incomplete:
Empty, though it shouldn't be:
Returns all, including the record that should have been there with the other 2:
Questions to answer:
Some further things to check:
Check the MySQL / PHP interaction character set is set correctly, typically with: $mysqli->set_charset("utf8mb4"); right after database connection is established.
It is set to utf8. Although it behaved the same before this was set.
Can you show any output from $mysqli->error ?
There are no errors. Just incomplete returns
Can you show us your whole SQL query?
It's included in the screen grabs. Although, that's just a plain string. And it doesn't account for what the prepared statement looks like.
Can you show the Collation / MySQL structure of the Names column?
It is all utf8 as per GoDaddy's phpMyAdmin
Can you show what the value of $whatName is right before binding?
It's at the top of the screen grab. It's echoed back to show it before anything else happens.
At this point I am thinking that the issue lies in what happens when the field I'm searching has a space or other character that is not a letter. Not what I'm passing in exactly. But more like, once the statement is prepared what is prepared is not matching what is in the field it is searching. This doesn't happen when you search the field prior to where the space exists. This is why "Ken" works 100% of the time, but "Lawton" fails completely. It's after the space.
I have tried all manner of converting the encoding type. And I have tried the various methods of concatenating the string. The results I'm getting are either no better, of completely breaking it.
Still 21 hours left on this bounty, if anyone has any more ideas.
At this point, I'd be more happy to award 25 each to the two dudes that provided the best information. Seems unfair to reward one and not the other.

Please note that the details on this answer are unlikely to resolve the question on their own. With my own further testing I established that appending % or _ wildcards to strings before they are bound does not effect the way they are bound to the query.
What you are currently trying to do is Concatenate the data ($whatName) with an SQL instruction % each side of it, and the Prepared Statement parser is simply not having this, as it defeats the security purposes of prepard statements.
So, the solution is that you need to manually concatenate the variable into the LIKE statement only at the point of insertion, and not before, as you are doing at the moment.
The example below will do as you intend:
$selectStr = WHERE `Name` LIKE CONCAT('%',?,'%') ORDER BY `Name`
$whatToBind = $whatName;
$stmt = $mysqli->prepare($selectStr);
$stmt->bind_param('s', $whatToBind);
$stmt->execute();
Note that the data and the query never mix, until the prepared statement is executed.
A note on UTF-8 and character sets on MySQL:
Do not use the utf8_ MySQL character sets as they are an incomplete subset of true UTF-8 and so can still raise serious issues with character recognition. Instead you want to be using utf8mb4_ character sets/collations/etc.
Character encoding may be a related issue to your problem, and I highly recommend reading up on the excellent answers given on this Stack Overflow Question as well as using the PHP mb_ multibyte string functions.
Some further things to check:
Check the MySQL / PHP interaction character set is set correctly, typically with: $mysqli->set_charset("utf8mb4"); right after database connection is established.
Can you show any output from $mysqli->error ?
Can you show us your whole SQL query?
Can you show the Collation / MySQL structure of the Names column?
Can you show what the value of $whatName is right before binding? (while your question makes sense, having a specific example of a specific situation and a specific result as well as an intended result is very useful for us to debug.
Silly thing but ensure you don't have a LIMIT on your results! :-D

It probably is some sort of mixed up encoding issue in $whatName.
Check if your $whatName variable encoding, is UTF8.
mb_detect_encoding($whatName, 'UTF-8', true) // should return true
if not then you will have to use mb_detect_encoding and mb_convert_encoding on $whatName to convert it to utf8.
If you have not done this already
Set proper charset
$mysqli->set_charset('utf8mb4');
// if your MySQL version is lower than 5.5.3 then
// use $mysqli->set_charset('utf8');
before your prepared statement
$stmt = $mysqli->prepare($selectStr);
$stmt->bind_param('s', $whatToBind);
$stmt->execute();

Related

PDO string comparision fails programatically [duplicate]

I am looking to get row count to check if same email is already in database or not. i have tried couple of mechanism but no success. when i run my query directly in the database it gives me the row count but via PDO execute it gives me 0.
i have used fetchAll method to manually count, even used rowCount method that also not working
$sql = 'SELECT count(*) FROM inbox WHERE uid = "'.$email_number.'" AND from_email = "'.$email_f.'"';
$result = $link->prepare($sql);
$result->execute();
$number_of_rows = $result->fetchColumn();
issue is with this $email_f, it contains html
SELECT count(*) FROM inbox WHERE uid = "6961"
AND from_email = "abc Offers <abc#abcs.com>"
this is the query which i have printed from $sql and when i execute it in database directly in phpmyadmin, it works fine. give me count of 3 but via execute i get 0.
First of all, you have to embrace the fact: if your query found no rows, it means there is no match, even if you can swear the data is all right. When the query returns no rows, then there are no rows to match the condition. So you have to find out - why. But first of all you need to make sure that your query is all right:
Problems caused by SQL errors
First of all you need to make sure that your query actually runs without errors as "no result" could mean an error in the query. Refer to these answers for the details: pdo and mysqli.
Problems caused by the condition
Check your conditions. There are mutual exclusive conditions, such as WHERE col=1 AND col=2. It will never return any rows. Try to simplify the condition until it starts returning some rows, and then refine the conditions to get the desired result.
But all right, there are no errors, conditions are correct, and you can swear there is data in the table to match your query. Still, there are some pitfalls:
Problems caused by the data
Most likely there are some converted or non-printable characters in the input data (or database). For example, there could be a linefeed character or a peculiarly encoded symbol, or some characters such as < and > converted into HTML entities. As a result, the query contains <abc#abcs.com> will never match a text <abc#abcs.com>.
The problem is, this is only a guess, and nobody can tell you what the actual issue is, because it is your database, your input data and only you can find the issue.
I wrote an article that explains how to debug your PDO issues.
To debug a particular issue, you need
make sure the full error reporting is enabled for both PDO and PHP. It really helps, showing you occasional typographic errors, spelling errors and the such
scrutinize both the data in the database and the input to find the difference. bin2hex() function would help, revealing all non-printable and converted characters, in both database and the input.
Problems caused by the connection credentials
Another frequent issue is when you have several databases and connect to the wrong one that doesn't have the data requested. This issue is similar to this one, so just follow the same routine, only checking not the list of tables but the data rows.
Problems caused by character set/encoding
It's a rare case, but just to to be sure, follow the checklist from this great answer
An irrelevant but important note
On a side note, but very important nevertheless: your prepared statement is a cargo cult code that protects nothing. Here is how it must be:
$sql = 'SELECT count(*) FROM inbox WHERE uid = ? AND from_email = ?';
$result = $link->prepare($sql);
$result->execute([$email_number,$email_f]);
$number_of_rows = $result->fetchColumn();

Select row whare column value contains ampersand(&) in mysql php pdo [duplicate]

I am looking to get row count to check if same email is already in database or not. i have tried couple of mechanism but no success. when i run my query directly in the database it gives me the row count but via PDO execute it gives me 0.
i have used fetchAll method to manually count, even used rowCount method that also not working
$sql = 'SELECT count(*) FROM inbox WHERE uid = "'.$email_number.'" AND from_email = "'.$email_f.'"';
$result = $link->prepare($sql);
$result->execute();
$number_of_rows = $result->fetchColumn();
issue is with this $email_f, it contains html
SELECT count(*) FROM inbox WHERE uid = "6961"
AND from_email = "abc Offers <abc#abcs.com>"
this is the query which i have printed from $sql and when i execute it in database directly in phpmyadmin, it works fine. give me count of 3 but via execute i get 0.
First of all, you have to embrace the fact: if your query found no rows, it means there is no match, even if you can swear the data is all right. When the query returns no rows, then there are no rows to match the condition. So you have to find out - why. But first of all you need to make sure that your query is all right:
Problems caused by SQL errors
First of all you need to make sure that your query actually runs without errors as "no result" could mean an error in the query. Refer to these answers for the details: pdo and mysqli.
Problems caused by the condition
Check your conditions. There are mutual exclusive conditions, such as WHERE col=1 AND col=2. It will never return any rows. Try to simplify the condition until it starts returning some rows, and then refine the conditions to get the desired result.
But all right, there are no errors, conditions are correct, and you can swear there is data in the table to match your query. Still, there are some pitfalls:
Problems caused by the data
Most likely there are some converted or non-printable characters in the input data (or database). For example, there could be a linefeed character or a peculiarly encoded symbol, or some characters such as < and > converted into HTML entities. As a result, the query contains <abc#abcs.com> will never match a text <abc#abcs.com>.
The problem is, this is only a guess, and nobody can tell you what the actual issue is, because it is your database, your input data and only you can find the issue.
I wrote an article that explains how to debug your PDO issues.
To debug a particular issue, you need
make sure the full error reporting is enabled for both PDO and PHP. It really helps, showing you occasional typographic errors, spelling errors and the such
scrutinize both the data in the database and the input to find the difference. bin2hex() function would help, revealing all non-printable and converted characters, in both database and the input.
Problems caused by the connection credentials
Another frequent issue is when you have several databases and connect to the wrong one that doesn't have the data requested. This issue is similar to this one, so just follow the same routine, only checking not the list of tables but the data rows.
Problems caused by character set/encoding
It's a rare case, but just to to be sure, follow the checklist from this great answer
An irrelevant but important note
On a side note, but very important nevertheless: your prepared statement is a cargo cult code that protects nothing. Here is how it must be:
$sql = 'SELECT count(*) FROM inbox WHERE uid = ? AND from_email = ?';
$result = $link->prepare($sql);
$result->execute([$email_number,$email_f]);
$number_of_rows = $result->fetchColumn();

Returning Numbered Based Like Results in a PDO Like Statement [duplicate]

I am looking to get row count to check if same email is already in database or not. i have tried couple of mechanism but no success. when i run my query directly in the database it gives me the row count but via PDO execute it gives me 0.
i have used fetchAll method to manually count, even used rowCount method that also not working
$sql = 'SELECT count(*) FROM inbox WHERE uid = "'.$email_number.'" AND from_email = "'.$email_f.'"';
$result = $link->prepare($sql);
$result->execute();
$number_of_rows = $result->fetchColumn();
issue is with this $email_f, it contains html
SELECT count(*) FROM inbox WHERE uid = "6961"
AND from_email = "abc Offers <abc#abcs.com>"
this is the query which i have printed from $sql and when i execute it in database directly in phpmyadmin, it works fine. give me count of 3 but via execute i get 0.
First of all, you have to embrace the fact: if your query found no rows, it means there is no match, even if you can swear the data is all right. When the query returns no rows, then there are no rows to match the condition. So you have to find out - why. But first of all you need to make sure that your query is all right:
Problems caused by SQL errors
First of all you need to make sure that your query actually runs without errors as "no result" could mean an error in the query. Refer to these answers for the details: pdo and mysqli.
Problems caused by the condition
Check your conditions. There are mutual exclusive conditions, such as WHERE col=1 AND col=2. It will never return any rows. Try to simplify the condition until it starts returning some rows, and then refine the conditions to get the desired result.
But all right, there are no errors, conditions are correct, and you can swear there is data in the table to match your query. Still, there are some pitfalls:
Problems caused by the data
Most likely there are some converted or non-printable characters in the input data (or database). For example, there could be a linefeed character or a peculiarly encoded symbol, or some characters such as < and > converted into HTML entities. As a result, the query contains <abc#abcs.com> will never match a text <abc#abcs.com>.
The problem is, this is only a guess, and nobody can tell you what the actual issue is, because it is your database, your input data and only you can find the issue.
I wrote an article that explains how to debug your PDO issues.
To debug a particular issue, you need
make sure the full error reporting is enabled for both PDO and PHP. It really helps, showing you occasional typographic errors, spelling errors and the such
scrutinize both the data in the database and the input to find the difference. bin2hex() function would help, revealing all non-printable and converted characters, in both database and the input.
Problems caused by the connection credentials
Another frequent issue is when you have several databases and connect to the wrong one that doesn't have the data requested. This issue is similar to this one, so just follow the same routine, only checking not the list of tables but the data rows.
Problems caused by character set/encoding
It's a rare case, but just to to be sure, follow the checklist from this great answer
An irrelevant but important note
On a side note, but very important nevertheless: your prepared statement is a cargo cult code that protects nothing. Here is how it must be:
$sql = 'SELECT count(*) FROM inbox WHERE uid = ? AND from_email = ?';
$result = $link->prepare($sql);
$result->execute([$email_number,$email_f]);
$number_of_rows = $result->fetchColumn();

PDO based query with space in criteria string not working in PHP [duplicate]

I am looking to get row count to check if same email is already in database or not. i have tried couple of mechanism but no success. when i run my query directly in the database it gives me the row count but via PDO execute it gives me 0.
i have used fetchAll method to manually count, even used rowCount method that also not working
$sql = 'SELECT count(*) FROM inbox WHERE uid = "'.$email_number.'" AND from_email = "'.$email_f.'"';
$result = $link->prepare($sql);
$result->execute();
$number_of_rows = $result->fetchColumn();
issue is with this $email_f, it contains html
SELECT count(*) FROM inbox WHERE uid = "6961"
AND from_email = "abc Offers <abc#abcs.com>"
this is the query which i have printed from $sql and when i execute it in database directly in phpmyadmin, it works fine. give me count of 3 but via execute i get 0.
First of all, you have to embrace the fact: if your query found no rows, it means there is no match, even if you can swear the data is all right. When the query returns no rows, then there are no rows to match the condition. So you have to find out - why. But first of all you need to make sure that your query is all right:
Problems caused by SQL errors
First of all you need to make sure that your query actually runs without errors as "no result" could mean an error in the query. Refer to these answers for the details: pdo and mysqli.
Problems caused by the condition
Check your conditions. There are mutual exclusive conditions, such as WHERE col=1 AND col=2. It will never return any rows. Try to simplify the condition until it starts returning some rows, and then refine the conditions to get the desired result.
But all right, there are no errors, conditions are correct, and you can swear there is data in the table to match your query. Still, there are some pitfalls:
Problems caused by the data
Most likely there are some converted or non-printable characters in the input data (or database). For example, there could be a linefeed character or a peculiarly encoded symbol, or some characters such as < and > converted into HTML entities. As a result, the query contains <abc#abcs.com> will never match a text <abc#abcs.com>.
The problem is, this is only a guess, and nobody can tell you what the actual issue is, because it is your database, your input data and only you can find the issue.
I wrote an article that explains how to debug your PDO issues.
To debug a particular issue, you need
make sure the full error reporting is enabled for both PDO and PHP. It really helps, showing you occasional typographic errors, spelling errors and the such
scrutinize both the data in the database and the input to find the difference. bin2hex() function would help, revealing all non-printable and converted characters, in both database and the input.
Problems caused by the connection credentials
Another frequent issue is when you have several databases and connect to the wrong one that doesn't have the data requested. This issue is similar to this one, so just follow the same routine, only checking not the list of tables but the data rows.
Problems caused by character set/encoding
It's a rare case, but just to to be sure, follow the checklist from this great answer
An irrelevant but important note
On a side note, but very important nevertheless: your prepared statement is a cargo cult code that protects nothing. Here is how it must be:
$sql = 'SELECT count(*) FROM inbox WHERE uid = ? AND from_email = ?';
$result = $link->prepare($sql);
$result->execute([$email_number,$email_f]);
$number_of_rows = $result->fetchColumn();

Dynamic select value

Example:
$user_input = $_POST['input'];
'SELECT '.$user_input.' FROM table_name'
So it's selecting a column in a database based on a secure (this example isn't secure obviously) value. Is this practical/allowable code?
In SQL you simply send a string to the DBMS (like MySQL). Because of this you can build any string you want and submit it to the DBMS.
You just have to make sure the resulting SQL query is valid. That means that e.g. the columns exist and that no invalid symbol appears.
On it's face, this code is valid, assuming that $user_input must be a valid column name, which means that it must exist and must not contain any special characters, reserved words, etc. (unless they're escaped).
As you said, however, this code isn't secure, but as long as you plan to build the query securely and use PDO or MySQLi (no deprecated mysql_* functions...), you should be fine. If you need an example that doesn't use deprecated functions (including mysql_real_escape_string, which is also being deprecated) I'll provide one.
I know you stated that you know this code isn't secure, but here's another example if you're curious. As was discussed in the comments and this question, this input:
$user_input = '; DELETE FROM table_name ; *';
'SELECT '.$user_input.' FROM table_name'
will delete the entire contents of the table table_name. Even though this code raises a syntax error, MySQL will continue to execute it, thus effectively truncating table_name.

Categories