Are single quotes or double quotes faster?

For a full answer and a script to test yourself see this link.

What is an SQL Injection attack?

An SQL Injection attack happens when a user gives your script data crafted to change your SQL to do something you didn't intend it to do. Consider this SQL:

<?php
$sql = 'SELECT * FROM users WHERE username="'.$username.'"
AND password="'.$password.'"';
if (mysql_query($sql)) {
  echo 'Logged in!';
}
?>

It looks fine, but what if a user submitted this as their password:

" OR 1=1 OR ""="

This would cause the SQL to read:

SELECT * FROM users WHERE username="" AND password="" OR 1=1 OR ""=""

which would allow the attacker to get into your system without even knowing a login!

On many databases you can also run multiple queries by putting a semicolon in the SQL you pass. Consider this password:

"; DELETE FROM users WHERE ""="

This would run the first query, which would probably find no records, but it would then run the DELETE query which would delete all of yoru users. Note that this could also be used to delete any other data in yoru system or to change your data or insert a new user with admin priviledges.

To protect against this, you need to "escape" the variables you put into your SQL. When using Mysql you can do this:

<?php
$sql = 'SELECT * FROM users WHERE 
username="'.mysql_real_escape_string($username).'" AND 
password="'.mysql_real_escape_string($password).'"';
?>

If you're using PEAR::MDB2 you can do this (this will work for *any* database system that MDB2 supports):

<?php
$sql = 'SELECT * FROM users WHERE 
username='.$db->quote($username).' AND 
password='.$db->quote($password);
?>

If you're using PEAR::DB you can do this (this will work for *any* database system that DB supports):

<?php
$sql = 'SELECT * FROM users WHERE 
username='.$db->quoteSmart($username).' AND 
password='.$db->quoteSmart($password);
?>

What does "Call to undefined method XX::XXXX" mean?

Often people who just start using PEAR get messages such as Call to undefined method DB_Error::setFetchMode() or Call to undefined method DB_Error::query(). This is almost always a result of insufficient error checking. See PEAR Error Handling for more info on how to catch and process these errors.

What does "supplied argument is not a valid MySQL result resource" mean?

This means that your query failed. Since you're seeing this error, you must not be checking for mysql errors. It's always best to check for errors whenever you can. To see the error, use mysql_error.

<?php
$sql = 'SELECT * FROM table';
if ($sth = mysql_query($sql)) {
  while ($rec = mysql_fetch_assoc($sth)) {
    print_r($rec);
  }
} else {
  die('Mysql had an error: '.mysql_error());
}
?>

Why does my script get included multiple times with include_once / require_once?

This could also be: 'Why do I get "Cannot redeclare class/function foo in /path/to/myFile.php"?'

This is often the result of different strings being passed to the _once functions that go to the same file. For example, if you're on Windows, you can use upper-case in oen include and lower-case in another. Both will go to the same file, but the _once functions see them as different (most other operating systems, like Linux, have case-sensitive filesystems).

<?php
//incorrect way to include. This will break on Linux and other systems
require_once('db/dataobject.php');
 
//correct way to include, use the real name
require_once('DB/DataObject.php');
?>

Another example for Linux folk: If you have both the /path/to/includes directory and the /path/to/includes/subdir directory in your include_path and you have the "myinc.php" file in the subdir, you can include the file with one of two paths:

<?php
require_once('subdir/myinc.php');
require_once('myinc.php');
?>

Neither of these is more correct than the other, but they both include the same file. To fix this, use the same string for including in all of your files.

Why is magic_quotes_gpc bad?

magic_quotes_gpc is a setting which makes all of variables sent to the PHP script by the browser (POST, GET, and COOKIE) "magically" have backslashes before all single and double quotes. This setting was supposed to make inserting values from the client's browser into a database safe. In practice, though, this setting makes quotes show up everywhere, especially when you're not inserting the values into a database, processing the text first, or sending it back to the browser.

Assume that magic_quotes_gpc is on and that you have a form which is validated before submission. If the form does not validate you send the form back with the values filled out for the user's convenience.

<?php
if (isset($_REQUEST['submit'])) {
  if (strlen($_REQUEST['text']) < 30) {
    echo 'You musy enter at least 30 characters';
  } else {
    //Do something with the data
  }
}
echo '
<form name="aForm">
<input type="text" name="text" value="'.htmlentities($_REQUEST['text'], ENT_QUOTES).'"/>
<input type="submit" name="submit" value="submit"/>
</form>';

If the user submits I didn't enter 30 chars in the text field, the form will not validate and be output once more with the same value in the text field. However, due to magic_quotes_gpc naively escaping the ' in the field, the text will read I didn\'t enter 30 chars. If the user submits this again, it will read I didn\\\'t enter 30 chars. Notice how 2 extra backslahes appeared this time. The number of backslashes will nearly double with every submission.

This can be fixed in one of two ways. The first is to leave magic_quotes_gpc on and run stripslashes on the data whenever it's not going into SQL. This is a bad solutions first of all because you're wasting script time by adding slashes, then removing them. This also means extra typing every time you want to use something from the user but not put it into SQL. This is also extremely dangerous as different databases escape their data differently. For MySQL you add a backslash, but for Oracle you use two single quotes. Using backslashes with Oracle may leave you open to an SQL Inection Attack.

The second, and correct way is to handle them only when you need to and in the correct manner. Turn off magic_quotes_gpc. When you're putting data into the database always use a quoting function.

<?php
//When using PHP's mysql functions:
$value = 'O\'Donnely said, "Don\'t escape my quotes!"';
$sql = 'INSERT INTO names (name) VALUES ("'.mysql_real_escape_string($value).'")';
mysql_query($sql);
 
//When using PEAR::DB
$sql = 'INSERT INTO names (name) VALUES ('.$db->quoteSmart($value).')';
$db->query($sql);
?>

When outputting to the browser, always use htmlentities() with ENT_QUOTES. This goes for outputting variables in JavaScript too.

<?php
$value = 'O\'Donnely said, "Don\'t escape my quotes!"';
echo htmlentities($value, ENT_QUOTES);
 
//or
 
echo '<input type="text" name="name" value="'.htmlentities($value, ENT_QUOTES).'"/>';
?>

And if you're outputting to plain-text, just output it.

I would also like to note here that if you use a package such as PEAR::HTML_QuickForm, it will take care of all escaping when outputting the form and will even stripslashes for you automatically if magic_quotes_gpc is on and you can't turn it off.

Why is register_globals bad?

It makes code harder to read, it can easily introduce security vulnerabilities, and the code is guaranteed not to work if register_globals is turned off. For more, see the manual page, this discussion, this article, another article, or just search Google.

How do I speed up my queries in...

mysql?

Thus spake Curt Zirzow:

To help figure out which queries are running slow there is the
php.ini setting:

mysql.trace_mode=On

Using this will have the php library analyze your queries and if
any of them do table scans php will issue a warning about it, which
can be very helpful finding out where you need indexes.

Why does my webpage say "headers already sent"?

This is due to some code calling one of the header producing functions after some output happens on your page. These functions include: header(), session_start(), and setcookie(). Output happens because of a print or echo call or, more commonly in these cases, text between ?> and <?php. If you have even one space or newline between the close and open PHP tags, this error will happen. If you have a space or newline after the ?> at the end of a PHP file, this can happen. A common solution to this problem it to remove the ?> at the end of PHP files entirely, although this isn't recommended as it's a little sloppy.

If you can't or don't want to avoid output before calling these functions you can also use output buffering to stop PHP from outputting anything before you want it output. However, this will cause PHP to store the output until either the end of the script or until you call one of the functions which stop output buffering. This can also cause pages which take a lot of processing to seem to load more slowly as the output won't show up until output buffering is turned off.

<?php
ob_start();
echo 'output';
 
session_start();
ob_end_flush();
?>

How do I make search engines spider my dynamic site?

A common misconception is that "dynamic" pages, i.e. those with GET parameters, won't be indexed by search engines. This is simply false. Dynamic pages are processed the same as normal pages. Google in particular introduces a small delay when it sees a ? in the URL as they don't want to bog down your site by making lots of dynamic calls at once. You site will still be indexed. The largest factor when it comes to indexing is the processing time of your PHP script.

Read here for lots of good info regarding PHP and search engines: http://www.stargeek.com/php-seo.php

Why can't I use Apache 2 with PHP?

The PHP Manual says not to use PHP and Apache2 in production. This is because of multi-threading issues. Some PHP libraries are not thread-safe and therefore can crash PHP. These errors are often not seen by smaller or low-traffic sites as they are due to race conditions in the libraries. If you want to use Apache2 with PHP and not have it crash, the recommendation is to use Apache2's prefork mode.

See this thread on the php-general list for more discussion.

How do I get the last inserted Primary Key (ID) value...

from a mysql table?

Assuming you are using auto_increment…

<?php
$query = 'INSERT INTO table (field1, field2) VALUES ("value1", "value2")';
$result = mysql_query($query);
$id = mysql_insert_id();
?>

OR

<?php
$query = 'INSERT INTO table (field1, field2) VALUES ("value1", "value2")';
$result = mysql_query($query);
$query = 'SELECT LAST_INSERT_ID()';
$result = mysql_query($query);
$rec = mysql_fetch_array($result);
$id = $rec[0];
?>

from a non-mysql db?

Non-mysql DBs usually use specially defined sequences. You should get the value of the ID *before* inserting the record in this case.

from PEAR::DB?

There is no built-in way if you're using the auto_increment feature of mysql. You can use the mysql_insert_id() function, as above, but that is non-portable (won't work on other DB systems). If you truly want to be DB backend independant, you should look into PEAR::DB's sequences.

How do I loop through database results to create a...?

Select box

<?php
$query = 'SELECT * FROM my_table WHERE available';
$result = mysql_query($query) or die('Query failed : '.mysql_error());
 
/* Printing results in HTML */
echo '<select name="yourDropdownName">';
while ($line = mysql_fetch_assoc($result)) {
  echo '<option value="'.$line['itemnum'].'">'.$line['itemname'].'</option>';
}
echo '</select>';
?>

(HTML) Table

<?php
$query = 'SELECT * FROM my_table WHERE available';
$result = mysql_query($query) or die('Query failed : '.mysql_error());
 
/* Printing results in HTML */
echo '<table><tr><td>col1</td><td>col2</td></tr>';
while ($line = mysql_fetch_assoc($result)) {
  echo '<tr><td>"'.htmlentities($line['col1'], ENT_QUOTES).
       '"</td><td>'.htmlentities($line['col2'], ENT_QUOTES).'</td></tr>';
}
echo '</table>';
?>

How do I use sessions?

You have to call session_start() before using anything in the session. This must be called before there is any output to the browser. This includes whitespace after/before PHP tags, so:

<HTML>
...
<?php
session_start();

is out.

So is:

<?php
//do something
?>
 
<?php
session_start();

After the call to session_start() you can get/set/unset any session value you want at any time in the script (all of this is stored on the server). The best way to do all of this is through the $_SESSION superglobal. Use it like a normal assicative array:

<?php
$_SESSION['var'] = 'value';
?>

or:

<?php
$_SESSION['array'] = array(1, 2, 3, 4);
?>

or:

<?php
$_SESSION['object'] = new Object();
?>

Everything you put in there will be available from any function without having to use the global keyword or the $GLOBALS superglobal.

Note that you can't store resources in the session (at least, they can't be used as resources on subsequent requests.) This includes things such as open file desriptors and database connections or statement handles.

How do I make my numbers output with a certain number of decimal places?

In PHP, strings and numbers are converted back and forth on the fly. Here are some examples:

<?php
$i = 1.00;
echo $i."\n";
//outputs 1
 
$i = '1.00';
echo $i."\n";
//outputs 1.00
 
$i = 1.00;
echo (string)$i."\n";
//outputs 1
 
$i = '1.00';
echo (int)$i."\n";
//outputs 1
 
$i = '1.00';
$j = $i + 1;
echo $j."\n";
//outputs 2  (NOT 2.00)
?>

If you use a variable as a number (+ - / *, etc) then it becomes a number and PHP will output it with as many decimals as it has. If you set a variable as a string ('1.00') and don't do any math, it stays as a string. Note: variables coming from forms through GET or POST are *strings*, not numbers.

number_format() converts a number to a string. This is how it makes it output with a certain # of decimals. Note, however this example:

<?php
$i = 1;
$j = number_format($i, 2);
$k = $j + 1;
echo $j.' '.$k;
//outputs 1.00 2
?>

Note how $k became a number again which is not formatted.

Now, since you want to be able to do math on your numbers it's best to assume that all variables that you want to output as numbers are, in fact, numbers and not strings. To that end, whenever you output a number and you want it in a specific format, you should use number_format() when you are outputting it.

Why am I getting ''Fatal error: Call to undefined function: MDB2_Driver_mysql::fetchRow()''?

This is caused by incorrect use of MDB2. MDB2 returns a statement handle from its query() method which you then call fetchRow() on. If you call fetchRow() on your db object you will get the above error. The correct way to fetch rows with MDB2 is:

require_once 'MDB2.php';
$db = MDB2::connect('mysql://user@host/db');
$sth = $db->query('SELECT * FROM table');
while ($rec = $sth->fetchRow(MDB2_FETCHMODE_ASSOC)) {
    print_r($rec);
}
 
phpfaqs.txt · Last modified: 2008/09/16 11:49 (external edit)
 
Recent changes RSS feed Creative Commons License Donate Powered by PHP Valid XHTML 1.0 Valid CSS Driven by DokuWiki