home *** CD-ROM | disk | FTP | other *** search
/ H4CK3R 4 / hacker04 / 04_HACK04.ISO / src / PHP / tidbits4.txt < prev    next >
Encoding:
Text File  |  2002-05-06  |  6.0 KB  |  75 lines

  1. Not So Magic Quotes
  2.  
  3. If you have to run your PHP3 scripts on more than one machine, most probably you'll know this problem: you copy it over to the other server and it won't work. The most common issue from my experience with projects like phpMyAdmin or phpAds is that there are differing settings for the magic_quotes_runtime or magic_quotes_gpc directives.
  4.  
  5. It is important to have a clear understanding what "escaping strings" means and how it is handled by PHP3 and database-systems like MySQL.
  6.  
  7.  
  8. Escaping
  9.  
  10. Let's assume you would like to insert the string "Let's do it" into a MySQL database. Probably you would come up with something like this:
  11.  
  12. $result = mysql_query("INSERT INTO foo VALUES ('Let's do it.'); 
  13.  
  14. Obviously, this won't work. MySQL takes the single quote in "Let's" as the separator for the string and wonders what the meaning of the commands "do" and "it" is :). Therefore, you have to write the single quote in a way MySQL understands it as part of a string: You escape it by prefixing a back-slash to the critical character ("Let's do it"). In other words: the purpose of escaping a string is to allow special characters to be treated as part of it. PH3 has two built-in functions which deal with escaping: addslashes() and stripslashes(). Using these two functions you can manually escape all critical characters within strings and strip back-slashes from a string:
  15.  
  16. $foo = "Let's do it.";
  17. $escaped_foo = addslashes($foo);
  18. echo $foo; // output: "Let's do it."
  19. echo stripslashes($foo); // output: "Let's do it."
  20.  
  21.  
  22. Life made easy
  23.  
  24. PHP3 is intended to make your life as a web-developer easier. One of the developers had the idea to save the user from the hassle with escaping strings manually and added two configuration directives:
  25.  
  26. magic_quotes_gpc = [on|off];
  27. magic_quotes_runtime = [on|off];  
  28.  
  29. If you've set magic_quotes_gpc to "on", PHP3 automatically escapes all strings passed through forms (get/post) or cookies. This behaviour can be pretty useful, because you don't have to addslashes() a string before inserting it into a DB. If you would like to print out the string again to the client (eg. for input validation), you'll need to apply stripslashes() to it.
  30. Magic_quotes_runtime escapes automatically escapes strings returned from external data-sources, such as databases or files. Say you've got a file "foo.php3", containing only one line: "Let's do it." If magic_quotes_runtime is "on", reading from this file will automatically escape the single quote: echo fread(fopen("foo.php3", "r"), filesize("foo.php3")); // output: "Let's do it." 
  31. In real life, this function isn't very useful though.
  32.  
  33. Magic? Bah.
  34.  
  35. As with any software trying to be more intelligent than the user, PHP3's magic_quotes_* functions introduce some problems. Imagine that you have magic_quotes_gpc set to "on" because you're a lazy person and do everything to avoid work. You can pass strings over to MySQL without worrying whether to escape them. Now remember that dream from last night and imagine for a moment that you've sold one of your PHP3-scripts to an incredibly rich client. But just when you're preparing to go on a very long vacation you receive a call from your client who tells you that the scripts don't work but only produce MySQL-errors. You guessed it already: She has magic_quotes_gpc set to "off".
  36.  
  37. The problem is that a script requiring magic_quotes_gpc=on or magic_quotes_runtime=on won't work on systems which have these directives set to "off" (and vice versa, of course). According to Murphy, the chance that you've set exactly the same directives as the script requires is tending towards zero. 
  38.  
  39. Deep magic
  40.  
  41. To resolve this issue, you have two options: You can either require the user to have a certain configuration for your script (eg. magic_quotes_runtime=on and magic_quotes_runtime=off) or you can write your script in a way that it doesn't matter what the directive is set to. If you choose the first option (as I did for example with phpMyAdmin or phpAds), better be prepared to answer questions on why the script doesn't work. With Apache you can set PHP3 configuration directives in .htaccess-files, so it isn't too much hassle. But try to have two different configurations with the CGI-version of PHP...
  42.  
  43. A more elegant solution would be to set the directives at runtime or at least reading their current value. You can only set magic_quotes_runtime at runtime though: 
  44.  
  45. set_magic_quotes_runtime(0); // off
  46. set_magic_quotes_runtime(1); // on 
  47.  
  48. But you can get the current value of both directives: $gpc = get_magic_quotes_gpc(); // (0 for off, 1 for on) 
  49.  
  50. $runtime = get_magic_quotes_runtime(); // (0 for off, 1 for on)  
  51.  
  52. To write really portable scripts you'd have to use conditional addslashes() and stripslashes() all over the place: 
  53.  
  54. $result = mysql_query("SELECT * FROM foobar");
  55. while ($row = mysql_fetch_array($result))
  56.    {
  57.    if (get_magic_quotes_runtime() == 1)
  58.       $row["foo"] = stripslashes($row["foo"]);
  59.    echo $row["foo"];
  60.    } 
  61.  
  62. This isn't really my understanding of a time-saver... 
  63.  
  64. Conclusion
  65.  
  66. I for my part just assume magic_quotes_gpc = on and use a set_magic_quotes_runtime(0) on top of my scripts. With this configuration, it is very comfortable to work: when inserting user-entered data into a DB you don't have to use addslashes() and when displaying data from a DB you don't need stripslashes(). By setting the magic_quotes_runtime directive within your script you eliminate at least one possible error.
  67.  
  68. Gotcha's & tips
  69.  
  70. To avoid confusion stick with one style through all your scripts. 
  71. Keep in mind that escaping is only needed to allow a string to contain special characters. Even if you pass an escaped string to MySQL, it is stored there as the original string (or to be exact, the original, un-escaped string is returned from operations like SELECT). Unless you have set magic_quotes_runtime to "on", you don't need to apply stripslashes() to data returned from a database! 
  72.  
  73. Stripslashes() applied to a string containing an ordinary back-slash will strip this slash: 
  74. echo stripslashes("c:windows") will output "c:windows". 
  75.