I have built a search engine using php and mysql.
Problem:
When I submit a word with an apostrophe in it and return the value to the text field using $_GET the apostrophe has been replaced with a backslash and all characters after the apostrophe are missing.
Example:
Submitted Words: Just can't get enough
Returned Value (Using $_GET): Just can\
Also the url comes up like this:search=just+can%27t+get+enough
As you can see the ' has been replaced with a \ and get enough is missing.
Question:
Does anybody know what causes this to happen and what is the solution to fix this problem?
The code:
http://tinypaste.com/11d62
If you're running PHP version less than 5.3.0, the slash might be added by the Magic Quotes which you can turn off in the .ini file.
From your description of "value to the text field" I speculate you have some output code like this:
Redisplay
<input value='<?=$_GET['search']?>'>
In that case the contained single quote will terminate the html attribute. And anything behind the single quote is simply garbage to the browser. In this case applying htmlspecialchars to the output helps.
(The backslash is likely due to magic_quotes or mysql_*_escape before outputting the text. I doubt the question describes a database error here.)
Update: It seems it's indeed an output problem here:
echo "<a href='searchmusic.php?search=$search&s=$next'>Next</a>";
Regardless of if you use single or double quotes you would need:
echo "<a href='searchmusic.php?search="
. htmlspecialchars(stripslashes($search))
. "&s=$next'>Next</a>";
(Notice that using stripslashes is a workaround here. You should preserve the original search text, or disable the magic_quotes rather.)
Okay I forgot something crucial. htmlspecialchars needs the ENT_QUOTES parameter - always, and in your case particularly:
// prepare for later output:
$search = $_GET['search'];
$html_search = htmlspecialchars(stripslashes($search), ENT_QUOTES);
And then use that whereever you wanted to display $search before:
echo "<a href='searchmusic.php?search=$html_search&s=$next'>Next</a>";
Single quotes are important in PHP and MySQL.
A single quote is a delimeter for a string in PHP, for example:
$str = 'my string';
If you want to include a literal quote inside a string you must tell PHP that the quote is not the end of the string. It is escaped with the backslash, for example:
$str = 'my string with a quote \' inside it';
See PHP Strings for more on this.
MySQL operates in a similar way. An example query might be:
$username = 'andyb';
$quert = "SELECT * FROM users WHERE user_name = '$username'";
The single quote delimits the string parameter. If the $username included a single quote, this would cause the query to end prematurely. Correctly escaping parameters is an important concept to be familiar with as it is one attack vector for breaking into a database - see SQL Injection for more information.
One way to handle this escaping is with mysql_real_escape_string().
Related
I am using PHP/mysqli to read in comments, but various comments in the table have either a single quote or a double quote.
I am storing the comments in a data-attribute. Using the Chrome console, I can see where the quote is throwing the whole code out of whack.
<?php
echo "<td><a href='' class='comment' data-toggle='modal' data-comment='".htmlentities($row[comment])."'>" . $row[partner_name] . "</a></td>";
?>
As you can see in the code above, I tried to use htmlentities. I also tried addslashes and a combination of the two.
Either way, I still can't get the comment to display properly because of the quote inside the mysql table.
Is there another PHP function that I can use to fix this?
Directly above is a screen shot from the Chrome console. Right after the words POTENTIAL 53 there is a single quote that is throwing my code off. All the other orange text is being read as HTML when it's supposed to be part of the comment.
There has to be a way to read the single quote as part of the string.
Pass the flag, ENT_QUOTES, to your htmlentities function. See http://php.net/htmlentities. This will replace quotes with entified quote and prevent it from breaking out of the data-comment attribute.
Well, there are two problems:
You have to encode stuff, especially quotes:
$text = htmlentities($value, ENT_QUOTES);
The title attribute does not work with newlines, so you will have to deal that. Something like this should do the job:
$text = preg_replace('/\r?\n/', '#xA;', $text);
Try escaping the quotes in your data. Something to this affect:
$pattern = "/\"|\'/";
$replace = '\\\"';
$subject = $row[comment];
$rowComment = preg_filter($pattern, $replace, $subject);
*Tip - You can also filter the data before storing it.
Description: echo $rowComment will produce a string with all quotes escaped;
For example I want to store the String "That's all". MySQL automatically escapes the ' character. How do I echo that String from the database using php but remove the \ in front of escaped characters like \' ? I would also like to preserve other formatting like new lines and blank spaces.
Have you tried stripslashes(), regarding the linebreaks just use the nl2br() function.
Example:
$yourString = "That\'s all\n folks";
$yourString = stripslashes(nl2br($yourString));
echo $yourString;
Note: \\ double slashes will turn to \ single slashes
You should probably setup your own function, something like:
$yourString = "That\'s all\n folks";
function escapeString($string) {
return stripslashes(nl2br($string));
}
echo escapeString($yourString);
There are also several good examples in the nl2br() docs
Edit 2
The reason your are seeing these is because mysql is escaping line breaks, etc. I am guessing you are using mysql_* functions. You should probably look into mysqli or PDO.
Here is an example:
$yourString = "That's all
folks";
echo mysql_escape_string($yourString);
Outputs:
That\'s all\r\n folks
If you use prepared statements, those characters will not be escaped on insert.
Use stripslashes() to remove slashes if you cannot avoid adding slashes on input.
At first, magic_quotes_gpc escapes the character like ' or ". You can also disable this in your php.ini. But then you should escape the things yourself that no query can get "infected".
Lookup mysql injection for more information.
When the escaped string is been written in your database. The string doesn't contain theses escape charakters and when you output them again. You should see the result as you want it.
Me for myself prefer the method by storing everything without escapes and escape or display things when I output them. You could also easily use an str_replace("\n", "", $text) to prevent newslines are displayed.
Greetings MRu
I was reading Does $_SESSION['username'] need to be escaped before getting into an SQL query? and it said "You need to escape every string you pass to the sql query, regardless of its origin". Now I know something like this is really basic. A Google search turned up over 20, 000 results. Stackoverflow alone had 20 pages of results but no one actually explains what escaping a string is or how to do it. It is just assumed. Can you help me? I want to learn because as always I am making a web app in PHP.
I have looked at:
Inserting Escape Characters, What are all the escape characters in Java?,
Cant escape a string with addcslashes(),
Escape character,
what does mysql_real_escape_string() really do?,
How can i escape double quotes from a string in php?,
MySQL_real_escape_string not adding slashes?,
remove escape sequences from string in php I could go on but I am sure you get the point. This is not laziness.
Escaping a string means to reduce ambiguity in quotes (and other characters) used in that string. For instance, when you're defining a string, you typically surround it in either double quotes or single quotes:
"Hello World."
But what if my string had double quotes within it?
"Hello "World.""
Now I have ambiguity - the interpreter doesn't know where my string ends. If I want to keep my double quotes, I have a couple options. I could use single quotes around my string:
'Hello "World."'
Or I can escape my quotes:
"Hello \"World.\""
Any quote that is preceded by a slash is escaped, and understood to be part of the value of the string.
When it comes to queries, MySQL has certain keywords it watches for that we cannot use in our queries without causing some confusion. Suppose we had a table of values where a column was named "Select", and we wanted to select that:
SELECT select FROM myTable
We've now introduced some ambiguity into our query. Within our query, we can reduce that ambiguity by using back-ticks:
SELECT `select` FROM myTable
This removes the confusion we've introduced by using poor judgment in selecting field names.
A lot of this can be handled for you by simply passing your values through mysql_real_escape_string(). In the example below you can see that we're passing user-submitted data through this function to ensure it won't cause any problems for our query:
// Query
$query = sprintf("SELECT * FROM users WHERE user='%s' AND password='%s'",
mysql_real_escape_string($user),
mysql_real_escape_string($password));
Other methods exist for escaping strings, such as add_slashes, addcslashes, quotemeta, and more, though you'll find that when the goal is to run a safe query, by and large developers prefer mysql_real_escape_string or pg_escape_string (in the context of PostgreSQL.
Some characters have special meaning to the SQL database you are using. When these characters are being used in a query they can cause unexpected and/or unintended behavior including allowing an attacker to compromise your database. To prevent these characters from affecting a query in this way they need to be escaped, or to say it a different way, the database needs to be told to not treat them as special characters in this query.
In the case of mysql_real_escape_string() it escapes \x00, \n, \r,\, ', " and \x1a as these, when not escaped, can cause the previously mentioned problems which includes SQL injections with a MySQL database.
For simplicity, you could basically imagine the backslash "\" to be a command to the interpreter during runtime.
For e.g. while interpreting this statement:
$txt = "Hello world!";
during the lexical analysis phase ( or when splitting up the statement into individual tokens) these would be the tokens identified
$, txt, =, ", Hello world!, ", and ;
However the backslash within the string will cause an extra set of tokens and is interpreted as a command to do something with the character that immediately follows it :
for e.g.
$txt = "this \" is escaped";
results in the following tokens:
$, txt, =, ", this, \, ", is escaped, ", and ;
the interpreter already knows (or has preset routes it can take) what to do based on the character that succeeds the \ token. So in the case of " it proceeds to treat it as a character and not as the end-of-string command.
I am using php5.3.6 and mysql 5.1.56 and CodeIgniter. Here is what I did.
Input some text in textarea, something like this:
what's this?
I'm bob.
$string = $_POST['name'];
$insertdata = mysql_real_escape_string($string);
Insert $insertdata into database.
It shows "what\'s this?\n\n\nI\'m bob."(without double quotes) in the table.
Query the data stored in database, use stripslashes on it and then put it back to the textarea.
It shows "what's this?nnnI'm bob."(without double quotes) in the textarea.
My questions are:
In step 4, shouldn't it be "what\'s this?\n\n\n I\'m bob." stored in the table?
I checked php manual. It says:
mysql_real_escape_string() calls
MySQL's library function
mysql_real_escape_string, which
prepends backslashes to the following
characters: \x00, \n, \r, \, ', " and
\x1a.
How am I supposed to keep the textarea input format after using mysql_real_escape_string()?
Is there anyway to choose which slash to strip and which not to?
Notes:
magic quotes option is off
I did not use stripslashes() before
using mysql_real_escape_string()
If I use addslashes() instead of
mysql_real_escape_string(),
everything works fine.
I don' want to use addslashes() since
it is not as secure as
mysql_real_escape_string(), as far as
I know.
Thanks,
Milo
This really does feel a lot like magic_quotes_gpc = On. Are you disabling it in php.ini or at runtime? It needs to be the former, otherwise it'll remain on.
http://www.php.net/manual/en/security.magicquotes.disabling.php
The magic_quotes_gpc directive may only be disabled at the system level, and not at runtime. In otherwords, use of ini_set() is not an option.
Short answer:
// double quotes are *very* important, or chars are not interpreted
$text_from_db=str_replace("\\r","\r",str_replace("\\n","\n",$text_from_db));
Long answer
Pretty simple but tricky.
You write your textarea and hit the "return" key, there is placed a \r\n (on Windows systems) with slashes that escape the "r" and "n" letter rising their special meaning of carriage return and newline.
You actually can't see them because they are "not printable" chars.
The slash char itself (0x1B) is invisible, that is a single slash is a "not printable" char, to make it visible you have to "transform" it in a printable slash char (0x5C) and to achieve that you have to double it "\\".
Now back to the question: if you can read the slash, probably that's beacuse that slash is not the 0x1B but rather 0x5C, so the "n" and "r" lose their special meaning and you get them as mere strings.
The code I posted does this conversion, converting the "[0x5C]n" string in a "[0x1B]" char.
Notes
Hope this helps, it did for me. IMPORTANT : it is not normal that the text that comes from the db has this issue if it has been stored correctly. My suggestion is to triple check insertion and retrieving because (given from the issue) you could be applying the quoting twice somewhere.
The Best Solution..
$insertdata = mysql_real_escape_string($string); (You can insert it in your database if you want)
echo stripslashes(str_replace('\r\n',PHP_EOL,$insertdata)); (The output is exactly as your input was)
You must escape data before inserting it into the database, to ensure you do not produce broken queries and to avoid SQL injections.
However, when you retrieve that data via a SELECT, you'll receive the data unescaped, ready to be used.
MySQL escapes the string, but when displaying the result back to you it will give you the same result as if it was unescaped.
This has been driving be crazy, but I can't seem to find an answer. We run a technical knowledge base that will sometimes include Windows samba paths for mapping to network drives.
For example: \\servername\sharename
When we include paths that have two backslashes followed by each other, they are not escaped properly when running 'addslashes'. My expected results would be "\\\\servername\\sharename", however it returns "\\servername\\sharename". Obviously, when running 'stripslashes' later on, the double backslash prefix is only a single slash. I've also tried using a str_replace("\\", "\", $variable); however it returns "\servername\sharename" when I would expect "\\servername\sharename".
So with addslashes, it ignores the first set of double-backslashes and with str_replace it changes the double-backslashes into a single, encoded backslash.
We need to run addslashes and stripslashes for database insertion; using pg_escape_string won't work in our specific case.
This is running on PHP 5.3.1 on Apache.
EDIT: Example Code
$variable = 'In the box labeled Folder type: \\servername\sharename';
echo addslashes($variable);
This returns: In the box labeled Folder type: \\servername\\sharename
EDIT: Example Code #2
$variable = 'In the box labeled Folder type: \\servername\sharename';
echo str_replace('\\', '\', $variable);
This returns: In the box labeled Folder type: \servername\sharename
I'd also like to state that using a single quotes or double-quotes does not give me different results (as you would expect). Using either or both give me the same exact results.
Does anyone have any suggestions on what I can possibly do?
I think I know where is a problem. Just try to run this one:
echo addslashes('\\servername\sharename');
And this one
echo addslashes('\\\\servername\sharename');
PHP escapes double slashes even with single quotes, because it is used to escape single quote.
Ran a test on the problem you described, and the only way I could get the behavior you desired was to couple a conditional with a regex and anticipate the double slashes at the start.
$str = '\\servername\sharename';
if(substr($str,0,1) == '\\'){
//String starts with double backslashes, let's append an escape one.
//Exclaimation used for demonstration purposes.
$str = '\\'.$str;
echo addslashes(preg_replace('#\\\\\\\\#', '!',$str ));
}
This outputs:
!servername\\sharename
While this may not be an outright answer, it does work and illustrates a difference in how the escape character is treated by these two constructs. If used, the ! could easily be replaced with the desired characters using another regex.
This is not a problem with addslashes, it is a problem with the way you are assigning the string to your variable.
$variable = 'In the box labeled Folder type: \\servername\sharename';
echo $variable;
This returns: In the box labeled Folder type: \servername\sharename
This is because the double backslash is interpreted as an escaped backslash. Use this assignment instead.
$variable = 'In the box labeled Folder type: \\\\servername\\sharename';
I've determined, with more testing, that it indeed is with how PHP is handling hard-coded strings. Since hard-coded strings are not what I'm interested in (I was just using them for testing/this example), I created a form with a single text box and a submit button. addslashes would correctly escape the POST'ed data this way.
Doing even more research, I determined that the issue I was experiencing was with how PostgreSQL accepts escaped data. Upon inserting data into a PostgreSQL database, it will remove any escape characters it is given when it actually places the data in the table. Therefore, stripslashes is not required to remove escape characters when pulling the data back out.
This problem stemmed from code migration from PHP 4.1 (with Magic Quotes on) to PHP 5.3 (with Magic Quotes deprecated). In the existing system (PHP4), I don't think we were aware that Magic Quotes were on. Therefore, all POST data was being escaped already and then we were escaping that data again with addslashes before inserting. When it got inserted into PostgreSQL, it would strip one set of slashes and leave the other, therefore requiring us to stripslashes on the way out. Now, with Magic Quotes off, we escape with addslashes but are not required to use stripslashes on the way out.
It was very hard to organize and determine exactly where the problem lay, so I know this answer is a little off to my original question. I do, however, thank everyone who contributed. Having other people sound off on their ideas always helps to make you think on avenues you may not have on your own.