Force MySQL field to lowercase with PHP

Go To StackoverFlow.com

1

I have a database with an email field, and it cycles through the database to grab all the transactions concerning a certain email address.

Users putting in lowercase letters when their email is stored with a couple capitals is causing it not to show their transactions. When I modify it to match perfect case with the other emails, it works.

How can I modify this so that it correctly compares with the email field and case doesn't matter? Is it going to be in changing how the email gets stored?

$result = mysql_query("SELECT * FROM `example_orders` WHERE `buyer_email`='$useremail';") or die(mysql_error());

Thanks ahead of time!

2012-04-04 21:34
by Brenden Clerget
I can't believe the code you've shown even correctly finds using emai - zerkms 2012-04-04 21:37
@zerkms Yeah, it won't - ceejayoz 2012-04-04 21:37
It works just fine, I took out the object oriented reference in the email field. I'm looking at it RIGHT NOW actually and it's finding all the transactions for a user's account. It just struggles with email case - Brenden Clerget 2012-04-04 21:40
@Brenden Clerget: For now - of course it works. You changed the code. And previous revision was just wron - zerkms 2012-04-04 21:41
Do you happen to know what an SQL injection is - o0'. 2012-04-04 21:41
Sigh, yes, I know what it is. I removed all those things from the code to simplify what I'm doing. I didn't want it cluttered, the classes handle all of that on their own. It's all fine and dandy. The variable is declared from something that is already sanitized - Brenden Clerget 2012-04-04 21:45


3

A mixed PHP/MySQL solution:

$result = mysql_query("
    SELECT * 
    FROM example_orders
    WHERE LOWER(buyer_email) = '" . strtolower($useremail) . "';
") or die(mysql_error());

What it does is converting both sides of the comparison to lowercase. This is not very efficient, because the use of LOWER will prevent MySQL from using indexes for searching.

A more efficient, pure SQL solution:

$result = mysql_query("
    SELECT * 
    FROM example_orders
    WHERE buyer_email = '$useremail' COLLATE utf8_general_ci;
") or die(mysql_error());

In this case, we are forcing the use of a case-insensitive collation for the comparison. You wouldn't need that if the column had a case-insensitive collation in the first place.

Here is how to change the column collation, as suggested by Basti in a comment:

ALTER TABLE `example_orders` 
CHANGE `buyer_email` `buyer_email` VARCHAR( 100 ) 
   CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL

If you choose to do that, you can run the query without COLLATE utf8_general_ci.

2012-04-04 21:41
by bfavaretto
I upvoted this because currently it is the only proposal that would work, even though it is terribly inefficient. Though the better advice would be just to figure out what's wrong with collation - zerkms 2012-04-04 21:43
@zerkms, I know, I added another option using COLLATEbfavaretto 2012-04-04 21:44
The issue is that the emails in the database aren't all lowercase, so this one shouldn't be either - Brenden Clerget 2012-04-04 21:44
You could also update the column buyer_email to use this collation per default. :- - Basti 2012-04-04 21:45
@BrendenClerget, First solution converts both sides (database and input) to lowercase, but it's not very efficient. Second options does a case-insensitive comparison by forcing a case-insensitive collation - bfavaretto 2012-04-04 21:46
@Basti actually he should do that, or he might end up with duplicate values - o0'. 2012-04-04 21:47
@Lohoris That really depends. Like Conrad wrote bob@example.com and Bob@example.com are two different email addresses according to RFC 2821. But most email providers won't allow this anyway, so yes he should do this! ;- - Basti 2012-04-04 21:49
@Basti I agree he should treat them case sensitive. That said, if for some reason something else (i.e. not an email address) had to be insensitive, then the correct way of doing it would be setting it correctly in the first place - o0'. 2012-04-04 21:51
This tip worked great. I had the other email column in my user accounts table on utf8 general ci but not on the transaction database. Since PayPal email addresses can't duplicate, I can use that safely and not worry, and I've changed that column to use that collation. Thank you!! - Brenden Clerget 2012-04-04 21:54
@Basti, done, thank - bfavaretto 2012-04-04 22:12


4

Uh... you realize that email addresses are case sensitive, right? From RFC 2821:

Verbs and argument values (e.g., "TO:" or "to:" in the RCPT command
and extension name keywords) are not case sensitive, with the sole
exception in this specification of a mailbox local-part (SMTP
Extensions may explicitly specify case-sensitive elements). That is, a command verb, an argument value other than a mailbox local-part,
and free form text MAY be encoded in upper case, lower case, or any
mixture of upper and lower case with no impact on its meaning. This
is NOT true of a mailbox local-part. The local-part of a mailbox
MUST BE treated as case sensitive.
Therefore, SMTP implementations
MUST take care to preserve the case of mailbox local-parts. Mailbox
domains are not case sensitive. In particular, for some hosts the
user "smith" is different from the user "Smith". However, exploiting the case sensitivity of mailbox local-parts impedes interoperability
and is discouraged.

(emphasis added)

2012-04-04 21:44
by Conrad Shultz
I'll just make them lowercase when they go into the database and handle these issues by hand for now - Brenden Clerget 2012-04-04 21:46
The point is that you CAN'T just change the case at will. You have to preserve case because you may be changing the address if you don't - Conrad Shultz 2012-04-04 21:48
@BrendenClerget he's trying to explain you that they are case sensitive, so treating them case insensitive is wrong - o0'. 2012-04-04 21:48
Okay, so there has to be an operator I can use to search them down in the database even if the case is different. The email addresses are coming from PayPal transactions - nobody can share a PayPal email. I just need to search down all the transactions that match that email address - Brenden Clerget 2012-04-04 21:50
@BrendenClerget See bfavaretto's answer. Just use utf8_general_ci as collation for the email column. You will be able to store the emails in their original case, but comparisons will ignore the case ("_ci" = case-insensitive). This is exactly what you wanted! :- - Basti 2012-04-04 21:52
Is PayPal ignoring case? Have you verified that? They shouldn't be. foo@example.com is not the same as FOO@example.com. They're not "shared" - they're different - Conrad Shultz 2012-04-04 21:55
Got it, thank you!!! @Conrad, sorry if I misunderstood your purpose for posting! They don't ignore case when sending emails to users, but they don't allow two versions of the same email in different cases to be registered, thus, nobody will ever share that and case on my side is irrelevant unless they change their policy - Brenden Clerget 2012-04-04 21:55
Are there any major ISPs, webmail providers, etc. providing case sensitive e-mail? If we made e-mails case sensitive at my job, it'd be a disaster. People do all sorts of odd casing - ceejayoz 2012-04-04 22:02
@ceejayoz I don't know, but I do know what the spec calls for. Most mail servers are written to spec, so companies that self-host can easily run into this even if the 3rd-party vendors don't. It's something to be aware of - and with something sensitive like finance at stake, I would hew closely to the standards - Conrad Shultz 2012-04-04 22:04
I'd err on the side that's least likely to cause problems. Given that Amazon.com allows me to any-case my e-mail address, I'm feeling pretty safe using their example - ceejayoz 2012-04-05 01:12


-1

If you do WHERE buyer_email LIKE '...' it'll by default do a case-insensitive match.

With e-mail fields, though, I prefer to lowercase the e-mail address when I insert it into the DB.

2012-04-04 21:36
by ceejayoz
LIKE behaviour, as well as = depends on the collation. They both may be case-sensitive or no - zerkms 2012-04-04 21:39
And actually advice for using LIKE for strict comparison instead of = is as bad, as LOWER()zerkms 2012-04-04 21:40
Thanks, let me try this real quic - Brenden Clerget 2012-04-04 21:40
Agree with Zerkms - Mike Purcell 2012-04-04 21:40
This one didn't work, tried it. Okay so what do I set the collation to - Brenden Clerget 2012-04-04 21:44
Mine defaults to utf8unicodeci. Other encodings I can't speak for - ceejayoz 2012-04-04 22:01
Ads