SitePoint Sponsor

User Tag List

Results 1 to 25 of 186

Threaded View

  1. #1
    Making a better wheel silver trophy DR_LaRRY_PEpPeR's Avatar
    Join Date
    Jul 2001
    Location
    Missouri
    Posts
    3,428
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)

    PHP and MySQL coding tips

    Hi all,

    I thought it would be good to create a thread with a lot of my common PHP and MySQL coding tips that I mention in other topics on here all the time. These are valuable things that I've learned during 1 year with PHP and MySQL. I believe these are good do's and don'ts, that most experienced coders would agree with, and not just my opinions.

    Note: in my examples, I'm using the new arrays ($_GET/$_POST/$_COOKIE/$_SERVER) because I'm assuming that you're using at least PHP 4.1.0. If you have an older version, then use the old, longer arrays ($HTTP_GET_VARS/$HTTP_POST_VARS/$HTTP_COOKIE_VARS/$HTTP_SERVER_VARS). But you should upgrade because of the file-upload vulnerability in unpatched versions prior to 4.1.2. That's a tip by itself!

    PHP

    register_globals
    First and foremost, I believe, is the use of register_globals. For those of you who don't know, register_globals allows you to access variables from forms and URLs (such as file.php?var=foo) as $var in your script -- "magically" created global variables. Unfortunately, this old method continues to be used in most tutorials/examples. The PHP developers seem to have realized that register_globals was a bad idea, though. They discuss Using Register Globals in the PHP manual and recommend turning them off in php.ini:

    Note that register_globals is going to be deprecated (i.e., turned off by default) in the next version of PHP, because it often leads to security bugs.
    ...
    You should do your best to write your scripts so that they do not require register_globals to be on
    In fact, as of PHP 4.2.0, register_globals is now off by default on new PHP installations. By writing code that relies on register_globals being on, you risk having that code not work on some systems! Wouldn't you rather use the preferred method of accessing variables and have your code work on all PHP installations?

    The proper way to access these variables is via their respective arrays. So instead of $var, in the above example, you should use $_GET['var']. Similarly, use $_SERVER['HTTP_USER_AGENT'] instead of just $HTTP_USER_AGENT.

    The main arrays are $_GET, $_POST, $_COOKIE, and $_SERVER, depending on where the variable came from, obviously. You can read more about them, and a couple of others, here and here in the manual.

    Please access your variables via these arrays!


    magic_quotes, addslashes(), and stripslashes()
    magic_quotes_gpc, when on, automatically adds slashes to all GET/POST/COOKIE data so that you don't need to use addslashes() before using GET/POST/COOKIE data in MySQL queries, etc. (e.g. with magic_quotes_gpc OR addslashes(), I'm becomes I\\'m). Well, magic_quotes_gpc is no convenience and just complicates things! Forum member HarryF has written an article entitled Slash 'em: The War Against Magic Quotes.

    Since magic_quotes_gpc can be on or off, you don't know whether to use addslashes() or not. You don't want to use addslashes() when magic_quotes_gpc is on because you'll add too many slashes (e.g. I'm becomes I\\\\'m), which is bad. Use addslashes() if magic_quotes_gpc is off, and don't if it's on (you can find out its setting with get_magic_quotes_gpc()). But you can't use the same code all the time. One workaround is something such as:

    PHP Code:
    if (!get_magic_quotes_gpc()) { $txt addslashes($txt); } 
    Things are further complicated if you want to first manipulate text that has had magic_quotes_gpc applied. You then have some text that has slashes added and some that doesn't. The effect of this is: some text will be wrong whether you use addslashes() or not.

    It's easiest to turn off magic_quotes_gpc, which I recommend, and use addslashes() manually all the time and not worry about the wrong amount of slashes. This is what it says in the recommended php.ini:

    magic_quotes_gpc = Off
    Input data is no longer escaped with slashes so that it can be sent into SQL databases without further manipulation. Instead, you should use the function addslashes() on each input element you wish to send to a database.
    As I said above, if you use addslashes() when magic_quotes_gpc is on, too many slashes will be added. For inserting I'm into MySQL, you want it to be I\\'m (and it will come out as I'm). Using addslashes() with magic_quotes_gpc, however, will give you I\\\\'m. THAT will come out of MySQL as I\\'m, which is not the original text. Most people assume that you are supposed to use stripslashes() when retrieving data from MySQL because otherwise they have slashes in their text. But that's fixing a problem that should never have occurred. If you have to use stripslashes() on text from your database, it's because you added too many slashes when you inserted it. You should never have to use stripslashes() on text from your database. If you do, you need to fix the problem at the source, rather than after the fact.

    You can turn off magic_quotes_gpc in php.ini or like this in a .htaccess file:

    Code:
    <IfModule mod_php4.c>
    	php_flag magic_quotes_gpc off
    </IfModule>
    If that's not possible, you can put the following code at the top of all your files (in a require or include). It will strip the slashes that magic_quotes_gpc added, virtually turning it off.

    Code:
    function strip_magic_quotes($arr)
    {
    	foreach ($arr as $k => $v)
    	{
    		if (is_array($v))
    			{ $arr[$k] = strip_magic_quotes($v); }
    		else
    			{ $arr[$k] = stripslashes($v); }
    	}
    
    	return $arr;
    }
    
    if (get_magic_quotes_gpc())
    {
    	if (!empty($_GET))    { $_GET    = strip_magic_quotes($_GET);    }
    	if (!empty($_POST))   { $_POST   = strip_magic_quotes($_POST);   }
    	if (!empty($_COOKIE)) { $_COOKIE = strip_magic_quotes($_COOKIE); }
    }

    ereg vs preg
    When it comes to the regular expression functions, ereg* and preg*, the preg functions are the clear choice. The preg functions are generally twice as fast as their ereg counterpart. They also support more advanced regular expression operations. I can't think of any reason why you would need to use the ereg functions.

    preg manual page and pattern syntax (long and confusing but pretty good).


    PHP tags
    I recommend always using the full PHP open tag, <?php, rather than the short one, <?. This means also that instead of <?=$var?>, it's better to use the full <?php echo $var?>. Using the full open tag ensures that your code will work on all PHP installations, regardless of the short_open_tag setting.


    Alternative control structure syntax
    I highly recommend staying away from the if (): ... endif; style syntax and sticking with curly braces, if () { ... }. This is the preferred syntax and it makes your code easier to read.


    error_reporting
    You should probably test your code with error_reporting set to at least E_ALL & ~E_NOTICE (all errors except notices) so that you aren't suppressing errors that should be fixed. error_reporting can be set in php.ini or with the error_reporting() function.


    Line breaks
    People want to know how they can retain textarea line breaks in HTML. You should store text in the database in its original format (e.g. with just newlines) and then use nl2br() to convert newlines to HTML <br /> tags on display (thanks to the people here for teaching me that ). That's all good, except for one problem with nl2br(): it doesn't seem to convert \r newlines (edit: this has now been fixed in PHP 4.2.0).

    Windows uses \r\n newlines; *nix uses \n; Mac uses \r.

    nl2br() works correctly on text from Windows/*nix because they contain \n. However, if you get text from a Mac, nl2br() will not convert its newlines (again, fixed in PHP 4.2.0). To remedy this, I use the following bit of code to convert \r\n or \r to \n before inserting it into the database. It won't hurt anything and ensures that nl2br() will work on the \n only newlines on display. Also, it has the side effect of saving 1 byte in the database per newline from Windows (by storing only \n instead of \r\n).

    PHP Code:
    $txt preg_replace('/\r\n|\r/'"\n"$txt); 

    Strings
    1) As a finesse thing, I use single quotes around strings whenever possible (e.g. strings that don't contain variables, single quotes, \n, etc.). This is supposed to make less work for the PHP parser.

    2) When an array variable isn't in a string, put quotes around string-literal keys so they are not regarded as constants:

    PHP Code:
    // OK
    echo $row[$key];

    // Wrong, unless key is a constant
    echo $row[key];

    // Right
    echo $row['key'];

    // OK, since it's in a string
    echo "Text: $row[key]"
    3) Remember, you can break out of PHP mode for large sections of HTML. This is faster than echo'ing and you don't need to escape quotes.


    Quotes around numeric data in queries
    For numeric columns in MySQL, you shouldn't put quotes around any of their values in queries. As our resident database guru, MattR, says, "that is very non-standard and will only work on MySQL." But if it's unknown data, how do you know that it's numeric and not letters that will cause an error? You can make sure that only a number is used in the query by first type-casting the data as int (or float for decimal numbers):

    PHP Code:
    // If id is being passed in the URL
    $id = (int) $_GET['id'];

    $r mysql_query("SELECT * FROM table WHERE id=$id"); 
    Then even if id is set to "abc," the worst that can happen is a 0 will be used in the query. No quotes; no error.



    MySQL

    Column types and attributes
    1) Be familiar with MySQL's column types along with their ranges/lengths. You should use the smallest column type that will hold the data that you expect to store. Most of the time, you probably don't need INT, because MEDIUMINT, SMALLINT, or TINYINT have enough range. Using a smaller type saves space and speeds things up.

    2) Declare all of your columns NOT NULL unless you need to store NULL values (NULL is not the same as 0 or the empty string). If you need to store NULL, you'll know. Again, NOT NULL saves space and speeds things up.

    3) Making INT-family columns UNSIGNED will effectively double the positive range with the same storage requirement. For example, TINYINT's highest value is 127. TINYINT UNSIGNED's highest value is 255.


    Indexes and optimization
    1) First, I sometimes see people create tables like this:

    Code:
    CREATE TABLE table (
    	id INT UNSIGNED NOT NULL AUTO_INCREMENT,
    	.....
    	KEY (id),
    	UNIQUE (id),
    	PRIMARY KEY (id)
    	)
    Do not make a column KEY, UNIQUE, and PRIMARY KEY. In this case, KEY and UNIQUE don't help anything. The PRIMARY KEY is a key and it is unique. By specifying 3 indexes, it wastes space and slows down write operations.

    2) Indexes/keys are the key (no pun intended) to fast queries (especially joins). The 3 types of indexes are PRIMARY, UNIQUE, and KEY/INDEX (same thing). It's hard to explain when and how to use indexes, so I'll just point you to some relevant pages in the MySQL manual: Speed of SELECT queries and How MySQL uses indexes.

    3) When you have your indexes setup, use EXPLAIN on SELECT queries to make sure your indexes are actually being used.
    Last edited by DR_LaRRY_PEpPeR; Feb 17, 2003 at 18:43.
    - Matt ** Ignore old signature for now... **
    Dr.BB - Highly optimized to be 2-3x faster than the "Big 3."
    "Do not enclose numeric values in quotes -- that is very non-standard and will only work on MySQL." - MattR


Bookmarks

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •