tags:

views:

85

answers:

9

Im using the follow script to insert records into my DB:

$sql = "INSERT INTO fotetweets VALUES('$tweetid','$dp', '', '$username','$tag', '$twittercontent', '$twittertimestamp', '')";
mysql_query($sql);

However what if $twittercontent contains the ' char, I think it will fail. Correct?

If so how can I deal with it correctly?

+1  A: 

That's why you should use mysql_real_escape_string() funtion first

http://www.php.net/manual/en/function.mysql-real-escape-string.php

It is important, that you always escape (or in general sanitize) variables you interpolate into your queries that come from untrusted sources (i.e. not from you ;) ). Topic for you to Google for read about: 'SQL injection'

Mchl
so, mysql_real_escape_string() shouldn't be used for trusted input?
Col. Shrapnel
I wouldn't say 'shouldn't'. More like you can omit it when you know it will no be needed. Also as far as handling untrusted variables goes, for numeric tyes, typecasting is usually a better solution than escapig, so I should perhaps add that to the answer ;)
Mchl
I love that "you can omit it when you know". **That** is the reason why prepared statements are WAY better (actually it's the only reason): because noone feel smartass enough to judge, omit or not omit it's usage, but use it unconditionally.
Col. Shrapnel
I agree they are better, but I also hate the API PHP gives us to use them ;)
Mchl
You didn't get the point, WHY they are better. You can make escaping usage no worse. Just by using it without too much thinking.
Col. Shrapnel
+2  A: 

Correct. Not only it will fail but it will also leave you open to SQL Injection attacks.

To avoid these problems, you can use:

Remember, user input should always be sanitized.

NullUserException
Why this word "user input" again? What about non-user input? No escaping/parametrizing?
Col. Shrapnel
@Col For example...?
NullUserException
Example of what? Of `'` symbol in "trusted" data? I am just asking why such separation? Why everyone, every friggin one, mention "user" or "untrusted" input? While data source is completely irrelevant. Escaping is query related, not input related.
Col. Shrapnel
@Col How often do you query for things that are not user input (or a function of user input) in web development? Regardless, where do I say that you should only escape user input?
NullUserException
How else it can be interpreted? Why to mention it, if there is no difference in data processing? Why to use word "sanitized"? This "sanitization" is just a subset, a side effect of proper formatting. And this formatting is totally irrelevant to data source.
Col. Shrapnel
+4  A: 

You will want to look into mysql_real_escape_string. However, I would look into using the mysqli or PDO class instead and utilize prepared statements.

EDIT

Note, these can all be found / were pretty much taken from the PHP Manual under examples for prepared statements.

Example Usage for MySQLi:

<?php
$mysqli = new mysqli("localhost", "my_user", "my_password", "my_database");

/* check connection */
if (mysqli_connect_errno()) {
    printf("Connect failed: %s\n", mysqli_connect_error());
    exit();
}

/* create a prepared statement */
$stmt =  $mysqli->stmt_init();
if ($stmt->prepare("INSERT INTO fotetweets VALUES(?, ?, '', ?, ?, ?, ?, '')")) {
    /* bind parameters for markers */
    $stmt->bind_param("issssi", $tweetid, $dp, $username, $tag, $twittercontent, $twittertimestamp);

    /* execute query */
    $stmt->execute();

    /* close statement */
    $stmt->close();
}
?>

Example Usage PDO:

<?php
$dsn = 'mysql:dbname=testdb;host=127.0.0.1';
$user = 'dbuser';
$password = 'dbpass';

try {
    $dbh = new PDO($dsn, $user, $password);
} catch (PDOException $e) {
    echo 'Connection failed: ' . $e->getMessage();
}

$sth = $dbh->prepare('INSERT INTO fotetweets VALUES(?, ?, '', ?, ?, ?, ?, '')');
$sth->execute(array($tweetid, $dp, $username, $tag, $twittercontent, $twittertimestamp));
?>

Example of mysql_real_escape_string usage:

$tweetid = (int) $tweetid; // static cast to integer, if that is what it should be.
$sql = "INSERT INTO fotetweets VALUES(
    $tweetid,'" . mysql_real_escape_string($dp) . "', 
    '', '" . mysql_real_escape_string($username) . "', 
    '" . mysql_real_escape_string($tag) . "', 
    '" . mysql_real_escape_string($twittercontent) . "', 
    '" . mysql_real_escape_string($twittertimestamp) . "', '')";

You can find more information and extra usage examples at the manual pages listed above. Given I do know what $dp is I cannot tailor this exactly.

SIDE NOTE

This is all the assumption I am willing to make. The OP could be getting the data from POST and/or in an array form, or he could be getting it from a different means. Either or, given the example the OP posted, this is as accurate as I could be to tailor to the OP. If you have an issue or think it could be better explained / shown, well go ahead and add another answer which addresses it and not just another complaining comment remark about how no one does anything right when you are not willing to pony up the "correct" answer yourself.

And of course if it is an array, this changes a lot of items and the OP should clear that up and not just random people making "guesses" as to where and how the data is being retrieved.

Brad F Jacobs
@ silent downvoter, care to enlighten me on the downvote?
Brad F Jacobs
all examples seems ugly to me... Don't you forget to escape $tweetid in the last one
Col. Shrapnel
Well why don't you provide a "pretty" example? I noticed in your reply you state that someone should post a "Real usage" well what prevents you from doing that? I mean, if you really want to know the best way is to do your own research and find out what works best for you and note "ugly" is in the eye of the beholder. Just because you feel it is ugly, does not make it so.
Brad F Jacobs
but it IS ugly. why to take it so personal? if I have to insert 20 fields - am I have to write mysql_real_escape_string 20 times or assign 20 variables out of $_POST array?
Col. Shrapnel
You are just assuming it is from `$_POST` array. If you read my remarks it states that I will not make assumptions. If the OP would like it to be furthered tailored, he could provide a bit more information as to where the data is coming from. For all we know it is coming in from a SimpleXML object. Yes, I would prefer to just do the array method, but with lack of information it is useless to try and guess what the OP is using and what he really wants in the end. Feel free however, to take what I posted and re-post it to use `$_POST`, maybe that will be what the OP is looking for.
Brad F Jacobs
And to answer the question about the `$_POST` array, well that is all good, but what if the variables are not in the proper order? You will notice that the prepared statements are in order and need to be so. You could assume that they come in the proper order, but what if someone uses cURL and tweaks the data around (for no other reason than fun). You could, however, have a system like Zend_Form in place that knows what data to expect. But to just assign `$_POST` blindly to a prepared statement, well that is just asking for trouble.
Brad F Jacobs
lol you are taking it as personal as though it's your best code :-) okay, it's nice then :)
Col. Shrapnel
and $_POST fields order problem cannot be solved, lol. Everyone is doomed to assign every variable by hand forever. So be it
Col. Shrapnel
I am? Interesting. I was under the impression that I was simply asking you for a pretty version of it that you wrote or prettied up that would be better and uses `$_POST` for the prepared statement(s). As I did not write the above code (just modified it so it was relevant to the Question), it would be extremely hard for me to take it personally.
Brad F Jacobs
Col. Shrapnel, if you noticed in that reply, I did mention Zend_Form, you can use / create custom functions to take the array and make it fit your needs. There is extra code needed to accommodate it. I am simply stating that doing `$stmt->execute($_POST)` is not a viable solution and would require a intermediate code to filter the array. IE, knowing what are the valid fields (an extra array or link to the database table) etc. It is just not practical to show that type of a solution, when the OP did not provide the needed information for it.
Brad F Jacobs
That's right, the last one. I am just wondering, why everyone just copy and paste a code that using raw API functions. I have seen thousands production scripts where exactly the same code is used. Sites like SO do not make a thing to improve code quality...
Col. Shrapnel
I would agree, but it is really hard to show someone how to use the custom code and to make them believe it is a better solution and to have them change how they do business. This is why I, and I assume most people, give the cookie cutter responses. If, however, he specifically asked a better / alternative / safer method to his current, it might be a different story and a better explanation would be warranted and would probably yield more thorough and better quality answers.
Brad F Jacobs
A: 

Just before you run this query, use this:

$twittercontent = mysql_real_escape_string($twittercontent);
Aditya Menon
A: 

yes it would fail as it would prematurely terminate the string. To fix this use

mysql_real_escape_string($twittercontent) in place of $twittercontent

codaddict
A: 

As it was mentioned above, you have to use mysql_real_escape_string()

note that you have to use this function not for the $twittercontent variable only, but for the every field in the query
and not only for inserting and not only for this table.
and from "untrusted input".

But literally every variable you are going to put into query in quotes, should be processed with this function. No exceptions or conditions.
Note if you don't put variable in quotes in the query, this function become useless

Another way, already mentioned too, is to change entire database driver.
Unfortunately, noone bring a useful example of real life usage, which could be extremely useful.

Col. Shrapnel
I find it extremely useful to escape md5 hashes.
Mchl
@Mchl I find it extremely useful **not to think** of data meaning at all. Database do not distinguish md5 hashes from HTML formatted article. Why bother to separate data processing? Why not to make it uniform?
Col. Shrapnel
This kind of thinking lead to creation of magic_quotes feature, which kicks our backs to this day.
Mchl
@Mchl may be you didn't notice, but this kind of thinking lead to creation of parametrized queries. Which parametrize md5 hashes as well. What a pity ;-) While magic_quotes is completely different story
Col. Shrapnel
@Mchl honestly, *a database driver* should know nothing of data meaning. Isn't it obvious? The only thing a driver can be concerned of, is data *type*. But it's better to eliminate this dependence too. It will make things easier.
Col. Shrapnel
I think this discussion is somewhat similar to defensive programming vs programming to contract discussion. Both metodologies have arguments for and against as well as fierce supporters and fanatic enemies. Let's leave it at that.
Mchl
A: 

Make your life simpler:

//$pdo = new PDO("mysql:host=localhost;dbname=testdb", user, pass);

$pdo->prepare("INSERT INTO fotetweets VALUES (?,?,?,?,?,?,?,?)")
    ->execute( array($tweetid, $dp, '', $username, $tag, $twittercontent, $twittertimestamp, '') );

This sends the data correctly to the database, without security issues. Use it as template for all queries. (Note that you still have to apply htmlspecialchars() when outputting your database content again later...)

mario
I am sure these variable came from some array. Why not to use this array instead?
Col. Shrapnel
That's what I'd do. However sometimes you have a $_POST["submitbutton"] in it.
mario
@mario but it's boring. It is not a benefit. You have to get assign all these variables first (10 lines of code!) and then write it again by hand. That's just awful. No wonder noone bother to use PDO. There ought to be neat way of doing this
Col. Shrapnel
Could you pop off the submitbutton first if you know it's the last item? I don't use pdo, but if the issue is just an extra array item, seems like that should work...
Don
@Don, in that example, you don't have to chop off anything. Use as is. As an alternative you could use bind :parameters instead of question marks and thus pass the $_POST array directly. See Daniels answer, you just don't need the ->bindParam()s usually. But that's a pro feature, start learning the question mark syntax first.
mario
@Col. Shrapnel, you're right. But you'd have the 10 assigns too for the oldschool mysql_query/real_escape pair. And you could shorten it here by directly using $_POST[*] vars. It's just required for `INSERT VALUES(?,?,?,?)` question mark syntax if you need the right ordering to throw arguments into the table. The <form> data might be reshuffeled in $_POST. - I'd personally use the :named PDO syntax. But you might also do (figuratively): `->("INSERT INTO tbl ({$array_keys($_POST)}) VALUES (?,?,?,...)")->execute(array_values($_POST))`. (I have a wrapper function to simplify such stuff.)
mario
No, I can't use array_keys($_POST), as it spoils whole idea of parametrized query and makes query wide open to SQL injection.
Col. Shrapnel
@Col. Shrapnel: I should have made the _figuratively_ bold. Was out of characters. Anyway I have this wrapper function which does exactly that low level work for me. The original poster won't need it, the sort-specific (?,?,?) INSERT syntax is fine for him.
mario
A: 

Hi,

As it was mentioned before me you can use mysql_real_escape_string
OR
if you use PDO you can also use binding and the you do not have to worry about escaping.

$stmt = $db->prepare("INSERT INTO fotetweets VALUES(:tweetid,:dp, '', :username,:tag, :twittercontent, :twittertimestamp, '')");
$stmt->bindParam(':tweetid', $tweetid);
$stmt->bindParam(':dp', $dp);
$stmt->bindParam(':username', $username);
$stmt->bindParam(':tag', $tag);
$stmt->bindParam(':twittercontent', $twittercontent);
$stmt->bindParam(':twittertimestamp', $twittertimestamp);
$stmt->execute();

Daniel Lenkes
couldn't it be executed with just `$stmt->execute($_POST);`, without this boring binding?
Col. Shrapnel
why do you want to bind everything inside $_POST? but your right that I would be too lazy to write it by hand. I would write a method to my db object which accepts a tablename and an array of values, but it is an other story.
Daniel Lenkes
Exactly the same function can be used to escape data. So, there is just no benefits in switching drivers - right?
Col. Shrapnel
A: 

You can also use addslashes(). mysql_real_escape_string() is better though. I agree with using PDO.

Josh
addslashes() has some limitations and not recommended to use. At least for multi-byte encodings, except utf8
Col. Shrapnel