Jump to content


Photo

Misc. FAQs


  • This topic is locked This topic is locked
6 replies to this topic

#1 Steveo31

Steveo31
  • Members
  • PipPip
  • Member
  • 25 posts
  • LocationSan Jose, CA

Posted 22 April 2004 - 04:45 AM

Before I begin, I would recommend reading the manual for help with functions.  The very cool way that php.net is set up is you can type in "http://www.php.net/" and then the name of the function you want to look up, e.g. "http://www.php.net/m...mysql_num_rows" will bring up the appropriate page.  :)

List of Current Topics:
  • URL's like page.php?id=something
  • Session Errors
  • MySQL Data Retrieval
  • Trans-page variables
  • Slashes/line breaks in blocks of text
  • Decrypting MD5
  • MySQL Date/Time Formatting
  • Force Download
  • What does this error mean?


A lot of the same questions are circulating, and come in every few days.  That's great, I don't want you to NOT post in the forums, but they are easily answered and quite common as I've said.

$_GET Variables

Q:  How do you get those dynamic URL's like www.domain.com/page.php?id=home?
A:  Those are $_GET superglobals. 

First off, do you know why you are using them?  A lot of people want to know how, but don't realize the importance of it.  Now, I was guilty of this when I started out, but after a bit of coding experience, it's clear why they are necessary.  After all, you wouldn't buy a Ford Pinto just because you like horses.

If you have a Pinto, then I apologize... their reputation precedes them :D


As an example, I'll use the website I have built on my computer.  There are tables and whatnot, and all I would like to change is the content in the main center table, and the title.  Based on that, you can use GET variables to change them.

Everyone has their own coding styles, so I am not trying to convert you into my style.  This is just a working example of how to use these efficiently.  Inside the main table it looks something like this:

<table width="100%" style="etc...">
   <tr>
        <td><?php include 'caseswitch.php'; ?></td>
    </tr>
</table>

That simply includes the .php file called "caseswitch.php" into that table data row.  Inside that file are case/switch statements that show content based on the GET variable in the url.  For example, index.php?cat=articles has this statement:
switch($_GET['cat']){
    case 'articles':
        include 'articles.php';
    break;
}
Yes, I realize there are a lot of includes here, but it helps keep the code clean and seperated for ease of use.  articles.php is just HTML/PHP/MySQL code that displays what I need it to inside the table previously discussed.


Further Reading:
http://www.phpfreaks...topic=32746&hl=

---------------
Session Error

Q: I keep getting this error: Warning: Cannot send session cookie - headers already sent by (output started at session_header_error/session_error.php:2) in session_header_error/session_error.php on line _.  What can I do to fix it?
A:  This usually means that the code for starting the session, "session_start();" is not where it should be.  If your page looks like this:
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">

<html>
<head>
	<title>Untitled</title>
</head>

<body>

Hello World!

</body>
</html>
Then your session_start() code needs to go here:
<?php 
session_start();
//other header commands here
?>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">

<html>
<head>
	<title>Untitled</title>
</head>

<body>

Hello World!

</body>
</html>
After session_start, you can have cookie headers, etc.

---------------

MySQL Data Retrieval

Q:  I have inserted the data into a MySQL database, but how do I show it?  (I sometimes get "Resource id#")
A:  To do this, you should use mysql_fetch_array, or in many cases, mysql_fetch_assoc.  The first one obtains an array where you can either use the column name, or a row number.  Since I don't think in numbers, I use the second one, which only obtains an array of the column names.  More info:

http://www.php.net/mysql_fetch_array
http://www.php.net/mysql_fetch_assoc

To do this, let's assume you have a query set up.  In this case, an example would be:
$sql = "SELECT name, email FROM people_table";
$query = mysql_query($sql);
while($row = mysql_fetch_assoc($query)){
    echo $row['name'].'<br />';
    echo $row['email'].'<br />';
}
The while() loop will go through all the data in the table, and when it reaches the end (when there's no more data to go through), it will stop.  Notice how the declaration of the $row variable is not used with the equality operator, ==. 

---------------

Variables

Q:  My variables don't show up in the next page!
A:  If you are using PHP version 4.2 or higher, register_globals is off, meaning you have to refer to the variables by their types.  I would recommend keeping them off.  If you POSTed the variables, you have to refer to them by $_POST['varname'].  Same goes for $_GET, $_FILES, $_SERVER, $_COOKIE, and $_SESSION variables.

---------------

Slashes, quotes, and line breaks, oh my!

Q:  Why are there slashes/no line breaks in my MySQL result?  They weren't/were there before...!?
A:  This question is broken up into two, in case it didn't make much sense here.  The first is that a query for a bunch of text, like a post, or an article or something has backslashes next to apostrophes '.  A built in function in MySQL can add slashes if enabled. This is because the way the MySQL, and I'm sure other databases, handle information that you insert with single quotes.  Confused?  Take a look:
<?php
//set up the info to insert:
$string = "Hey man, what's up?  How've you been?";
//make a string query for simplicity's sake:
$sql = "INSERT INTO tablename (`field`) VALUES('$string')";
//make the query:
$query = mysql_query($sql) or die(mysql_error());

//Retreival of the data:
while($row = mysql_fetch_array($query)){
    echo $row['field'];
}

?>
This should bring up an error.

To get around the error, you have to addslashes:
<?php
//set up the info to insert:
$string = addslashes("Hey man, what's up?  How've you been?");
//make a string query for simplicity's sake:
$sql = "INSERT INTO tablename (`field`) VALUES('$string')";
//make the query:
$query = mysql_query($sql) or die(mysql_error());

//Retreival of the data:
while($row = mysql_fetch_array($query)){
    echo $row['field'];
}

?>
This will bring up the correct data, but with backslashes:
Hey man, what\'s up?  How\'ve you been?

If you don't addslashes, you will get an error.

PHP first gets the value of that variable you are inserting, and then tries inserting it.  If there are any apostrophes in there, then PHP/MySQL will see it as the end/beginning of another parameter in the INSERT query.

This will, unfortunately, cause the slashes show up if you echo the results without a nifty little funtion called stripslashes.  It does just what it's name says.  To use it, just pull the variable out and strip it down:
<?php 
$sql = "SELECT fieldname FROM tablename";
$query = mysql_query($sql) or die(mysql_error());
while($row = mysql_fetch_assoc($query)){
    echo stripslashes($row['fieldname']);
}
?>
This will output what you put in, no slashes.

The second part of this is the issue with line breaks in a multiline entry, so from a textbox for example.  You use the function nl2br to make sure that the line breaks STAY where you put them.  Take a look at the following example.  Let's say you enter this into a textarea:
Hi there!

Would you like to see some examples of my work?  If so, contact me!

Sincerely, 
Joe Shmoe
Now, when you put this into the database, and retrieve it without nl2br, it will look like this:
Hi there!  Would you like to see some examples of my work?  If so, contact me! Sincerely, Joe Shmoe

So, you just do this.
$comm = $_POST['comments'];
$sql = "INSERT INTO tablename (`field`) VALUES ('$comm')";
$query = mysql_query($sql) or die(mysql_error());
If you open PhpMyAdmin (or something similar) you will see it is all one paragraph.  That's fine.  When you pull it out of the database and display it, that's when you use nl2br:
$query = mysql_query("SELECT body FROM articles");
while($row = mysql_fetch_assoc($query)){
    echo nl2br($row['body']);
}
That will have the line breaks you normally had to begin with.

Thanks Barand!

----------

Decrypting MD5

Q:  How do I decrypt MD5?
A.  You can't.  If you must do data encryption and decryption, take a look at mcrypt functions.

Related Topics:
http://us2.php.net/md5
http://www.phpfreaks...showtopic=29917
http://www.phpfreaks...showtopic=33071

----------

Dates and Times in MySQL

Q.  How do I pull out a date from a MySQL DATETIME, DATE, TIME, or TIMESTAMP field into a readable format?
A.  Thanks for the idea there James (Websitenoobie).  His way:
$DATE = date('M jS Y g:ia A', strtotime($MYSQLFORMAT));
And another way:
$sql = mysql_query("SELECT DATE_FORMAT(`date_field`, '%c-%e-%y') AS the_date FROM aTable");
$row = mysql_fetch_assoc($sql);
echo $row['the_date'];

Further Reading:
Webclass date() symbols
PHP.net date() manual
MySQL Date and Time Functions

----------

Download

Q.  How can I force download of files?
A.  I found this snip of code and it looks promising. 

<?php

// force to download a file
// ex, ( [url=http://localhost/php/download.php?file=C:/Apache]http://localhost/php/download.php?file=C:/Apache[/url] Group/Apache2/hongkong.php )
// hope this can save your time :-)

$file = $_REQUEST['file'];

header("Pragma: public");
header("Expires: 0");
header("Cache-Control: must-revalidate, post-check=0, pre-check=0"); 

header("Content-Type: application/force-download");
header( "Content-Disposition: attachment; filename=".basename($file));

header( "Content-Description: File Transfer");
@readfile($file);

?>

This hasn't been much of a common question, but it is helpful nontheless.

----------

Annoying Errors

Warning: main(): Failed opening '/home/the-whom/public_html/layout.php' for inclusion (include_path='.:/usr/lib/php:/usr/local/lib/php') in /home/the-whom/public_html/join.php on line 2

Solution:  Make sure that the file you are trying to include() is named correctly, and is pointing to the right path, such as
include 'includeFolder/file.php';

Warning: mysql_result()/mysql_fetch_assoc/mysql_num_rows/mysql_fetch_object: supplied argument is not a valid MySQL result resource in /home/the-whom/public_html/join.php on line 78

Solution:  Check your SQL syntax and make sure that there is indeed a row (or rows) that match the criteria.  For example:
<?php 

$sql = mysql_query("SELECT name, id FROM users WHERE name='Jacko'");
//if there is no field called "name" you'll get an error.

?>

Error inserting your information into MySQL: No Database Selected

Solution: Connect to the Database, and if you have connected, make sure that you have selected which DB you want to use with mysql_select_db().

Fatal error: Call to undefined function: footer() in /home/the-whom/public_html/join.php on line

Solution:  Make sure the function exists.

More to come....
----------
I hope this helped, and I'll add more as they come to mind :)

-Steve

#2 Barand

Barand
  • Moderators
  • Sen . ( ile || sei )
  • 18,017 posts

Posted 24 April 2004 - 06:55 AM

So, you just do this. When you upload the data from the form, upload it as nl2br:


I would argue that it is better to store the text in the DB with the '\n' rather than using nl2br().

If you want to redisplay the text in a textarea for editing, you want the newlines but not the
'<br/>'

Use nl2br when you want to display the text containing newlines in the body of a page.
If you are still using mysql_ functions, STOP! Use mysqli_ or PDO. The longer you leave it the more you will have to rewrite.

Donations gratefully received






moon.png

|baaGrid| easy data tables - and more
|baaChart| easy line, column and pie charts

#3 Barand

Barand
  • Moderators
  • Sen . ( ile || sei )
  • 18,017 posts

Posted 24 April 2004 - 11:14 PM

How would you go about doing it?

Take the text straight from a text area, complete with newlines and save in db field. OK, you need to addslashes, remove html tags but basically normal text in the db, or maybe text in a text file.

if you are outputting to page body text, use nl2br() to show line breaks. If it goes into a textarea for edit, don't use nl2br()

Demo script:-

<?php
if (isset($_GET['sampletext'])) {

    echo "<h4>With newlines only</h4>";
    echo $_GET['sampletext'];

    echo "<h4>Using nl2br()</h4>";
    echo nl2br($_GET['sampletext']);
    echo "<hr>";
}

?>
<HTML>
<HEAD>
<meta Name="generator" content="PHPEd Version 3.1.2 (Build 3165)">
<title>Text area sample</title>
</HEAD>
<BODY>
<FORM  method="GET">
<p>Type some text
with linebreaks<br>
and submit</p>
<TEXTAREA  name="sampletext" rows="5" cols="30"><?=$_GET['sampletext']?></TEXTAREA>
<br>
<INPUT TYPE="SUBMIT"  value="Submit text">
</FORM>
</BODY>
</HTML>

If you are still using mysql_ functions, STOP! Use mysqli_ or PDO. The longer you leave it the more you will have to rewrite.

Donations gratefully received






moon.png

|baaGrid| easy data tables - and more
|baaChart| easy line, column and pie charts

#4 Websitenoobie

Websitenoobie
  • Members
  • Pip
  • Newbie
  • 8 posts

Posted 13 May 2004 - 08:34 PM

Add on -

MD5 CANNOT BE DECRYPTED!

Period.
Halcyon 5 Hosting[br]Halcyon 5 Community[br][br]Have you donated today?[br]Hybodus is also a great Christmas present! :)

#5 Websitenoobie

Websitenoobie
  • Members
  • Pip
  • Newbie
  • 8 posts

Posted 25 May 2004 - 10:11 PM

Q: How can I turn mysql date format into readable time?
(Yes I see this a lot and if you all just use the search on the forum youd all find it yet I still see a TON of these posts)
A: To do this there is a simple line of code
$DATE = date('M jS Y g:ia A', strtotime($MYSQLFORMAT));

Simply change the M jS Y g:ia A to whatever youd like, you can find the basic ones here Date Symbols
Halcyon 5 Hosting[br]Halcyon 5 Community[br][br]Have you donated today?[br]Hybodus is also a great Christmas present! :)

#6 toplay

toplay
  • Staff Alumni
  • Advanced Member
  • 973 posts

Posted 25 August 2004 - 05:22 PM

I'm seeing a few common coding oversights occur in these forums which I would like to address to help people out. Before I do, I just want to expand on some of the topics Steveo31 talks about above. Use your browsers find/search feature to pinpoint specific information in this post.

$_GET Variables – for PHP version 4.1.0 or higher.

You can use $_REQUEST instead of $_GET or $_POST variables. The $_REQUEST will work with either a get or post form submission method. By using $_REQUEST means you would not have to change your code later in the event the HTML form submission method changes.

I should point out that the PHP manual recommends that you use $_GET or $_POST directly so you know exactly where the data is coming from. I think with register_globals turned off that it's alright to use $_REQUEST (which also contains $_COOKIE data too).

Refer to: http://www.php.net/r...riables.request

For reference: http://www.php.net/variables.external


Session Errors – or about getting the "headers already sent" warning messages.

The "headers already sent" warning messages can also happen with setcookie(), header(), and mail() function uses and not just session_start(). All these type of functions need to send headers to the browser before your script outputs anything to the browser. The session_start() (and these other functions) don't necessarily have to go at the very top of a script (although it's recommended). They can go anywhere in a script as long as your script has not yet sent ANYTHING to the browser before one of these functions is executed. By 'anything' I mean non-header data like HTML/non-HTML, and no whitespaces like spaces, tabs, newlines, carriage returns, formfeeds, hidden (non-visible) characters, etc.

It's alright to have include/require files before issuing these header related functions, but again, the included file(s) must not have code that sends anything to the browser. The problem could be in the main script or found in the included file(s). Most often there are usually one or more spaces found before the opening "<?PHP" tag, or spaces and newlines after the ending "?>" PHP tag. That's all it takes; these would output to the browser as non-header data and will cause the "headers already sent" warning messages to be issued. Remember that a PHP script is by default a HTML file first and foremost and that's why we use PHP tags; to distinguish between HTML and PHP code. Anything not in PHP tags is considered HTML and is output to the browser (even if it's a single space).

The link below talks more about this topic. When you just can't find where you're outputting stuff to the browser accidentally, then I recommend you use the ob_start() function on the first line in your script. This starts output buffering which buffers non-header data sent to the browser. This will prevent the "headers already sent" warning messages. The ob_start() option should be looked at as a band-aid and not as a solution. The real solution is to locate in your script file(s) where you are sending data to the browser prematurely.

Read about how to locate whitespaces in your script by following the links found here:
http://www.phpfreaks...=0


MySQL Data Retrieval

A very common problem I see on these forums is that some people are not checking for errors after an SQL query. You need to check for a good return (no errors) before performing any subsequent SQL related commands (such as a fetch or number of rows). Also, you must check if you got data back after attempting to retrieve the data; do not just start using the row data blindly. Good coding practice never assumes there will be data returned. Example:
// Connect to MySQL server first – You can use variables instead of these literals
$db = mysql_connect('localhost', 'username', 'password');
if (!$db) {
    echo 'Could not connect to MySQL server. <br />Error # ', mysql_errno(), ' Error msg: ', mysql_error();
    exit;
}

// Select the database you want to use – You can use a variable here too instead
if (!mysql_select_db('DBname', $db)) {   // Did selection fail?
    // Handle error 
    echo 'DB Selection failed. <br />Error # ', mysql_errno(), ' Error msg: ', mysql_error();
    exit;
}

// An example for retrieving zero or more rows
$sql = "SELECT name, email FROM people_table";
$result = mysql_query($sql, $db);
if (!$result) {
    // Handle error 
    echo 'Query failed. SQL: ', $sql, '<br />Error # ', mysql_errno(), ' Error msg: ', mysql_error();
    exit;
}
// The while loop stops when there's no data left; it might not even go in loop
// and echo anything when there's no data returned on the first call to
// mysql_fetch_assoc()
while($row = mysql_fetch_assoc($result)) {  // Retrieve data until no more
    echo $row['name'], '<br />';
    echo $row['email'], '<br />';
}

// Optional – Free up memory. Done automatically when script ends
if (!mysql_free_result($result)) {  
    // Handle error or ignore it 
    echo 'Freeing results failed. <br />Error # ', mysql_errno(), ' Error msg: ', mysql_error();
    exit;
}

// Once the results table is freed, don't attempt to use the $result variable anymore

//****************************************************************

// For retrieving zero or one row (the first row with that name)
$name = mysql_escape_string('John Doe');  // or use addslashes()
$sql = "SELECT email FROM people_table WHERE name = '$name'";
$result = mysql_query($sql, $db);
if (!$result) {
    // Handle error 
    echo 'Query failed. SQL: ', $sql, '<br />Error # ', mysql_errno(), ' Error msg: ', mysql_error();
    exit;
}

$row = mysql_fetch_assoc($result);    // Try to retrieve the data
if (!$row)           // No data returned?
    // Not necessarily an error – Just no data matched search criteria
    echo 'No data found <br />'; 
else      // There is valid data returned
    echo "The email for $name is ", $row['email'], '<br />';

// Optional – Close MySQL connection. Will be closed at end of script anyway
// Do NOT put a mysql_close() after a query and before fetching data!
if (!mysql_close($db)) {  
    echo "Couldn't close database <br />";  // or ignore error
    exit;
}
Note that some people use die(), which is simply an alias of exit().

I've also seen this type of poor coding:
$nbr = mysql_num_rows(mysql_query("SELECT name, email FROM people_table"));

// or
$row = mysql_fetch_assoc(mysql_query("SELECT name, email FROM people_table WHERE id = '$id'"));
Never enclose one MySQL function inside another like that. As already explained, a query could return an error and a valid results resource won't exist (or be returned). This would then cause the outer function to fail with a "not a valid MySQL result resource" message (see the Annoying Errors section below).

TIP: You can make the formatting of SQL statements a little bit easier by using arrays and the sprintf() function. One array could hold all the column names you have in a table. Like this:
$columns = array('catg_id', 'catg_description');
You can even find out what the column names are dynamically and place the column names in an array producing the same result as above. In the following example, the first '%s' in sprintf() will be replaced with '*' and the second '%s' will get replaced with 'categories'. Here's the example:
// An example to automatically get column names
$sql = sprintf('SELECT %s FROM %s LIMIT 1',
               '*',
               'categories'
              );
echo 'COLUMN NAME SELECT SQL: ', $sql, '<br>';

$result = mysql_query($sql);
if (!$result) {
    echo 'Query failed. SQL: ', $sql, '<br>Error: ', mysql_error(), '<br>';
    exit;
}

$row = mysql_fetch_assoc($result);  // Retrieve the one row

if (!$row)  // No data found?

    // Set columns manually or display error (and exit)
    $columns = array('catg_id', 'catg_description');
else
    // Convert associate keys into values
    $columns = array_keys($row);

echo '<pre>', print_r($columns, TRUE), '</pre>';
The above code would display something like this:

COLUMN NAME SELECT SQL: SELECT * FROM categories LIMIT 1

Array
(
    [0] => catg_id
    [1] => catg_description
)

Inserting data into a table can be easier with having a columns array and a values array. Then using implode() to handle the formatting of commas and generating the SQL. This is especially handy when you have lots of column names in your table. Example:
// Escape characters when necessary and surround value with quotes
function quote($_value = '', $_check_gpc = TRUE) {

    if (($_check_gpc) &&
        (get_magic_quotes_gpc()))
        return ("'" . $_value . "'");
    else
        return ("'" . mysql_escape_string($_value) . "'");

}

/*
 * You can create arrays to hold table and column names
 */
$tables = array('categories');   // Doesn't have to be an array
$columns = array('catg_id', 'catg_description');

/*
 * Build an array of values to place in table
 * The order of values needs to correspond to column(s) order given
 */
$values = array();            // Initialize
$values[] = quote('');        // catg_id blank - auto increment
$values[] = quote($_POST['catg']); // New category – Contains: Cameras

/*
 * Use sprintf() to nicely take care of building the SQL statement
 */
$sql = sprintf('INSERT INTO %s (%s) VALUES (%s)',
               implode (', ', $tables),
               implode (', ', $columns),
               implode (', ', $values)
              );

echo 'INSERT SQL: ', $sql, '<br>';

$result = mysql_query($sql);
if (!$result) {
    echo 'Insert failed. SQL: ', $sql, '<br>Error: ', mysql_error(), '<br>';
    exit;
}

$last_id = mysql_insert_id(); // Get last auto increment id used
echo 'Last insert id: ', $last_id, '<br>';
Which displays something like this:

INSERT SQL: INSERT INTO categories (catg_id, catg_description) VALUES ('', 'Cameras')
Last insert id: 1

The update SQL is a little trickier because we have two separate arrays that hold the column name and values. You could have one array where the keys of the array are the names of the columns and the values would of course be what you want to update or modify. This sample code uses two separate arrays for column and values. When you're table contains an auto increment column, then you probably don't want to change it's value. So, this code removes it so it won't get updated. See example code:
// Returns column_name = 'value' for update SQL
function kv_pair($_key = array(), $_value = array()) {

    $_result = '';
    $_key_cnt = count($_key);
    $_value_cnt = count($_value);

    if (($_key_cnt > 0)   &&
        ($_key_cnt == $_value_cnt)) {

        $_result = array();
        for ($i = 0; $i < $_key_cnt; $i++)
            $_result[] = $_key[$i] . ' = ' . quote($_value[$i]);

        $_result = implode(', ', $_result);
    }

    return $_result;
}

$without_id = $columns;       // Copy original columns array
$id = array_shift($without_id);  // Remove first catg_id entry

$values = array();            // Initialize
$values[] = 'Books';          // Change category description to Books

$where = array();             // Initialize
$where[] = $columns[0] . ' = ' . quote($last_id); // catg_id = 'last number'
$operator = '';               // Just one condition; no need for operator

$sql = sprintf('UPDATE %s SET %s WHERE %s',
               implode (', ', $tables),
               kv_pair($without_id, $values),  // returns a string
               implode (" $operator ", $where)
              );

echo 'UPDATE SQL: ', $sql, '<br>';

$result = mysql_query($sql);
if (!$result) {
    echo 'Update failed. SQL: ', $sql, '<br>Error: ', mysql_error(), '<br>';
    exit;
}
The update code displays something like:

UPDATE SQL: UPDATE categories SET catg_description = 'Books' WHERE catg_id = '1'

Generating the select SQL is pretty simple using this method. See example code:
$where = array();
$where[] = $columns[0] . ' = ' . quote($last_id); // Need ID or description
$where[] = $columns[1] . ' = ' . quote('Books');  // but using both to show AND
$operator = 'AND';

$sql = sprintf('SELECT %s FROM %s WHERE %s',
               implode (', ', $columns),
               implode (', ', $tables),
               implode (" $operator ", $where)
              );

echo 'SELECT SQL: ', $sql, '<br>';

$result = mysql_query($sql);
if (!$result) {
    echo 'Query failed. SQL: ', $sql, '<br>Error: ', mysql_error(), '<br>';
    exit;
}

while ($row = mysql_fetch_assoc($result))

    echo '<pre>', print_r($row, TRUE), '</pre>';
The select code above would display something like this:

SELECT SQL: SELECT catg_id, catg_description FROM categories WHERE catg_id = '1' AND catg_description = 'Books'

Array
(
    [catg_id] => 1
    [catg_description] => Books
)

Here's an example of a select SQL using two tables:
$tables = array('categories', 'inventory');
$columns = array('catg_id', 'catg_description',
                 'inv_in_stock', 'inv_description', 'inv_price');

$where = array();
$where[] = $tables[0] . '.' . $columns[0] . ' = ' .
           $tables[1] . '.' . $columns[0];
$where[] = $columns[1] . ' = ' . quote('Books');
$operator = 'AND';

$columns[0] = $tables[0] . '.' . $columns[0]; // make into categories.catg_id
$sql = sprintf('SELECT %s FROM %s WHERE %s',
               implode (', ', $columns),
               implode (', ', $tables),
               implode (" $operator ", $where)
              );

echo 'SELECT SQL: ', $sql, '<br>';

$result = mysql_query($sql);
if (!$result) {
    echo 'Query failed. SQL: ', $sql, '<br>Error: ', mysql_error(), '<br>';
    exit;
}

while ($row = mysql_fetch_assoc($result))

    echo '<pre>', print_r($row, TRUE), '</pre>';
The select code above would display something like this:

SELECT SQL: SELECT categories.catg_id, catg_description, inv_in_stock, inv_description, inv_price FROM categories, inventory WHERE categories.catg_id = inventory.catg_id AND catg_description = 'Books'

Array
(
    [catg_id] => 1
    [catg_description] => Books
    [inv_in_stock] => 10
    [inv_description] => Setting Up LAMP: Getting Linux, Apache, MySQL,and PHP Working Together
    [inv_price] => 34.99
)



Variables

With the 'register_globals' php.ini configuration setting off, variables defined in your form will not be accessible by their name (i.e. $name, $address, $phone, $email, etc.). You can use the $_REQUEST superglobal array variable with the index being the name defined in your HTML form (i.e. $_REQUEST['name'], $_REQUEST['address'], $_REQUEST['phone'], $_REQUEST['email'], etc.).

This is also true about other PHP variables and functions that rely on 'register_globals' being on. Like $PHP_SELF won't be created and session_register() won't work with 'register_globals' set to off. For these instances, use $_SERVER['PHP_SELF'] and $_SESSION variables instead.

Filter get/post form data example:
http://www.phpfreaks...=0


Slashes, quotes, and line breaks, oh my!

It's important to know the settings of 'magic_quotes_gpc' and 'magic_quotes_runtime' php.ini settings before using addslashes(), mysql_escape_string(), or stripslashes() on variable data obtained from a HTML form, file or database. Usually the 'magic_quotes_gpc' is on, and 'magic_quotes_runtime' is off. You can find out their settings from within a script by using get_magic_quotes_gpc() and get_magic_quotes_runtime() functions. When these settings are on, PHP has already done the addslashes() for you. Don't arbitrarily do an addslashes() to variables because you could end up having everything double slashed. Do something like this instead:
$last_name = isSet($_REQUEST['last_name']) ? $_REQUEST['last_name'] : '';
if (!get_magic_quotes_gpc())    // When off, do escape
    $last_name = mysql_escape_string($last_name);  // or use addslashes()
// Here you can add to the table or file fine now
Similarly, after reading from a file or table do not just do stripslashes() routinely because you may strip something in your data that you want to keep. PHP will only do addslashes() to values obtained from a file or table when the 'magic_quotes_runtime' setting is on. Check the setting and do something like this (a database example):
// Do the query and check for errors. The row has O'Brien for a value
while($row = mysql_fetch_assoc($result)) {
    if (get_magic_quotes_runtime()) // O\'Brien will be returned
        echo stripslashes($row['last_name']); // Strip the backslash
    else
        echo $row['last_name'];  // O'Brien will display fine
}
You don't see that kind of handling a lot because 'magic_quotes_runtime' is usually off by default. However, I recommend that you don't rely on it being off and check for it as shown, or set it off using set_magic_quotes_runtime() function.

Note that the mysql_escape_string() function does a little more than the addslashes().

The differences between addslashes() and mysql_escape_string():
http://www.phpfreaks...=0


Decrypting MD5

There isn't any particular MD5 decryption functions, however, the MD5 hashes can be broken (not quickly but it can be done). I don't recommend using it for passwords and other important or sensitive information. Use the libmcrypt extension instead. Use long keys and make sure you store the key off the web or public directory at your site. If you can't install the libmcrypt extension, then you can use a home grown type of encryption and decryption routines. Here is one:
http://www.phpfreaks...viewcode&id=309

With sample output found at:
http://www.phpfreaks...ndpost&p=133936

I was debating whether to provide the following information/links or not. I decided to present it to warn people about the use of MD5 and since the information are already readily available on the internet.

You can download a Windows program that cracks MD5 hashes:
http://members.cox.n.../MD5Cracker.zip

Here's a PHP command prompt script that cracks MD5 hashes and keys:
http://www.securitea...5XP0X0040G.html

You can even submit an MD5 to be cracked online for free here:
http://www.passcracking.com

Project RainbowCrack:
http://www.antsight....l/rainbowcrack/

Password guessing:
http://packages.debi...admin/crack-md5

A 2004 Article on the MD5 (and SH-0, SH-1) vulnerability:
http://www.technewsw...tory/35926.html

Cracking MySQL's MD5() function:
http://alan.blog-cit...hin_seconds.htm


Dates and Times in MySQL

Read the MySQL date and time functions manual page. It's got lots of info. Here are a few forum post links related to MySQL date and time functions:

To find rows older than a certain number of day's example:
http://www.phpfreaks...=0

To add days to a date (note: to subtract you can use DATE_SUB instead):
http://www.phpfreaks...=0

To subtract months and/or years from a date:
http://www.phpfreaks...=0

Extracting the month from a date and making it into English:
http://www.phpfreaks...=0

Extracting the month, day, and year from a column:
http://www.phpfreaks...=0

An example of using 'BETWEEN' with date columns:
http://www.phpfreaks...=0


Annoying Errors

Regarding this type of messages:

Warning: mysql_result/mysql_fetch_assoc/mysql_fetch_array/mysql_num_rows/mysql_fetch_objetetc: supplied argument is not a valid MySQL result resource in …


Steveo31 is correct in that these messages are usually attributed to wrong SQL syntax in the query (or not connected to the database). What I mean by wrong syntax includes the possibility of using the wrong table or column names, and not just syntactically incorrect formatting of the query. This message can be avoided altogether; it masks/hides the real error at the query and is a by-product of wrong logic. These messages occur because error checking wasn't performed after a query and a subsequent SQL command was issued to work on the query result (when there was already a query error). This goes back to what I was explaining in the MySQL Data Retrieval section above (which has examples of correct MySQL error checking). You must check for errors and when there are errors, don't execute any more SQL commands that retrieve data or require the use of the results table. Handle the error after a query appropriately and your code logic shouldn't get as far as trying to read or examine the data inappropriately, then this warning message won't ever occur again. You need to display the real error that caused the query to fail in order for you to solve the main problem (which is usually bad SQL query syntax). Not handling errors like this is a serious logic flaw in code and I see it all the time. A big part of coding is really error checking. Don't get lazy or forget to check for errors.


Here's a few more Q & A's I'd like to share:

Q: Why do I get a "Notice: Undefined …" type of messages?

A: Sample code:
$first_name = $_REQUEST['first_name'];
The above code example would generate the following type of notice message only when the error_reporting() allows E_NOTICE type of messages (error_reporting is also a php.ini setting):

Notice: Undefined index: first_name in …


Some people are surprised by these notices and think they are out right errors; and they perhaps didn't see the notices when they were testing on their local machine, but see them on their web host providers server (or vice versa). That's because of the difference in 'error_reporting' settings between the two servers. This type of notice messages means that there doesn't seem to be an index entry with 'first_name' and so PHP considers it undefined. One way to prevent this notice is to not assume that an array index is there and check for it specifically first using the isSet() function as in this example:
$first_name = isSet($_REQUEST['first_name']) ? $_REQUEST['first_name'] : '';
This uses the ternary comparison operator. The $first_name variable will be assigned the value of $_REQUEST['first_name'] if it contains something other than NULL. Otherwise, it will be initialized to an empty string (you can set this to be anything you want as a default).

While testing scripts, I recommend that you have the E_NOTICE type of error messages on to help find possible problem areas in your code. Then turn it off before using scripts in a production setting.

Also, this example of code:
$name .= 'Doe';
Will produce the following notice message:

Notice: Undefined variable: name in …

The '.=' is concatenating the 'Doe' to the existing value found in $name. Since the $name variable has not been initialized to something first you may get unpredictable results. Make sure you set/initialize all variables before using the '.=' concatenation assignment. The following code example will not produce the notice since a straight equal assignment is used before the use of '.=':
$name = 'Jane ';
$name .= 'Doe';
echo $name;   // Displays Jane Doe


Q: Do I really need to use quotes with associative array indexes?

A: Yes. I recommend to use this syntax $ary['something'] instead of $ary[something]. Here's an explanation of why to always use quotes in associative array indexes:
http://www.phpfreaks...=0


Q: I'm trying to do an equal comparison. Why does this piece of code always executes the first 'if' statement?
$value = 2;
if ($value = 1)
    echo 'one';   // This gets displayed
elseif ($value = 2)
    echo 'two';
A: The equal comparison operator in PHP requires two equal signs (==) and not just one (=). One equal sign is an assignment operator. In this case, the '1' was assigned to the $value variable at the first 'if' expression, and this made the expression evaluate to TRUE; causing the echo 'one' to be executed. With this type of code example, PHP produces no errors (when there's a variable name to the left of the equal sign). This makes debugging this kind of problem more difficult and time consuming. It's not always very apparent.

Here's a tip to avoid this problem in the future. Get used to coding the 'if' expression with the literal value first or to the left of the equal sign, like this:
$value = 2;
if (1 == $value)
    echo 'one';
elseif (2 == $value)
    echo 'two';  // This gets displayed
That way if you happen to make a mistake and put just one equal sign again, then PHP will give you a parse error. The code of '1 = $value' is invalid because PHP can't assign the contents of $value to '1' (a literal; it must be a variable). This could potentially save you lots of time in testing/debugging because you get an error alert.

Q: Why does this switch statement keep executing all my case statements?
A: Sample code:
switch ($choice) {
    case '1' : echo 'one selected';
    case '2' : echo 'two selected';
    case '3' : echo 'three selected';
    default: echo 'Invalid entry';
}
The logic will fall-through and execute the remaining case statements because there are missing 'break' commands. The 'break' will get you out of the switch statement (and others like for, foreach, while, do..while). Change the code to something like this:
switch ($choice) {
    case '1' : 
        echo 'one selected';
        break;
    case '2' : 
        echo 'two selected';
        break;
    case '3' : 
        echo 'three selected';
        break;
    default: 
        echo 'Invalid entry';
        break;
}
There's no need to use 'break' on the last (or default) entry but it helps for consistency, and if you happen to later add another case condition, then the 'break' will already be there and you won't run into any more fall-through logic problems.

Q: I get a parse error while using array variables inside double quotes, why?
A: Sample code:
echo "Hello $row['name'] <br>";
The PHP parser doesn't always recognize array variables in double quotes. It mostly has a hard time recognizing associative and multi-dimensional array variables. By surrounding the array variable in curly braces you're telling the PHP parser exactly where the variable name begins and ends (so it will recognize the variable and it won't give a parse error). The curly braces will not be displayed. Here are examples of different solutions:
echo "Hello {$row['name']} <br>";  // Curly braces example

echo "Hello ", $row['name'], " <br>"; // Separate by commas

echo "Hello " . $row['name'] . " <br>"; // It works but avoid (it's slower)
Note that PHP will not recognize any type of variable when enclosed in single quotes. i.e. echo 'Hello $name' will just display that as is, and not the value contained in the $name variable. See complex syntax example at:
http://us3.php.net/m...parsing.complex


Q: I want to define an array with values, but is there a way to start a numeric index with something other than zero?

A: Yes. You can set a numeric array index to any number by doing something like: $ary[20] = 'twenty'. The following are examples using '=>' to set the index value:
$months = array( 1 =>
                'January',
                'February',
                'March',
                'April',
                'May',
                'June',
                'July',
                'August',
                'September',
                'October',
                'November',
                'December');

echo $months[8]; // Displays August

// Another example:
$nbrs = array(10 => 'Ten', 20 => 'Twenty', 30 => 'Thirty');

echo $nbrs[30]; // Displays Thirty


Q: I'm trying to add some values obtained from a HTML form and it's giving me the wrong total, why?

A: Remember that browsers return form values to the server and your script as string values (even if they look like numbers). Use type casting to insure that you are adding numbers and not dealing with strings. You can also use the intval() and floatval() functions to convert strings into integers and real numbers. Examples of type casting:
$value = (int) 10;  // Integer
$amt = (float) 12.95; // Floating point number
$str = '20'; // A string value. Same as doing $str = (string) '20';
You can also refer to these posts:
http://www.phpfreaks...=0
http://www.phpfreaks...=0


Q: I've been told using count() in a 'for' loop is bad, why is that?

A: It's not bad per say, it's just that the 'for' loop will run a little longer needlessly because PHP has to execute the count() function on every loop iteration. Changing the code from something like this:
// $month is an array that contains the names of each month
for ($i = 1; $i <= count($month); $i++)  // count() executed 12 times
    echo $month[$i], '<br>';
To something like this makes the 'for' loop run as much as 45% faster:
// $month is an array that contains the names of each month
$cnt = count($month);            // Only need to do once
for ($i = 1; $i <= $cnt; $i++)  // Use the $cnt variable instead
    echo $month[$i], '<br>';


Q: How can I make a function recognize a variable set outside of the function?

A: Within the function use the 'global' keyword followed by the variable name. Separate each variable with a comma when there's more than one variable to list. See:
http://www.phpfreaks...=0
http://www.phpfreaks...=0


Q: When defining a function and it's arguments, is there a way to assign the default value of an argument using a variable?

A: No. However, you can use constants as shown in this post:
http://www.phpfreaks...=0


Q: Do I need to put quotes around my search criteria in a 'WHERE' clause when it's only going to be a number?

A: Yes, you should. The MySQL manual explains this point well. See this post:
http://www.phpfreaks...=0


Q: My SQL query looks alright, yet I'm getting a MySQL syntax error, but why?

A: Check to make sure that you're not accidentally using a MySQL reserved word which would mess up your SQL syntax. For simplicity and clarity never try and use a MySQL reserved word for database, table, or column names. You can by using the backtick character, but why make it confusing on yourself and others? See this post which also contains two useful MySQL manual links:
http://www.phpfreaks...=0
http://www.phpfreaks...=0


Q: I'm using a MySQL function in a query and mysql_fetch_assoc() to read the data, but I can't get at the column data that I'm using the MySQL function on, help?

A: Use the 'AS' MySQL keyword to name what you want the result data column to be called. That name will be used as the index key of the associative array. Here's an example:
$sql = "SELECT MAX(price) AS highest_price FROM inventory";
$result = mysql_query($sql);
if (!$result) {
    // Handle error 
    echo 'Query failed. SQL: ', $sql, ' Error: ', mysql_error();
    exit;
}
$row = mysql_fetch_assoc($result);
if (!$row)
    echo 'No data returned';
else
    echo 'That highest price is $', $row['highest_price'];    // name used in the 'AS'


Q: Is there a way I can know what the column names are in my MySQL table?

A: You can do a 'SELECT * FROM table_name LIMIT 1' type of SQL query and retrieve the data with a mysql_fetch_assoc(), which creates an associative array with the column names as the index of the array. Then you can do a 'foreach' loop to display the array keys which will be your column names of the table. See:
http://www.phpfreaks...=0

An example of using 'DESCRIBE' to obtain column information from a known table:
http://www.phpfreaks...=0


Q: How can I add a column to an existing MySQL table?

A: The 'ALTER' SQL command can make lots of different types of changes to tables. For a link reference and a syntax use example see this post:
http://www.phpfreaks...=0


Q: I did my SQL query and it didn't find the row so I inserted a new row. Then I found out later that there are duplicates in my table. Why didn't it find my original row/data?

A: Sample code:
// The $email variable was set to something before this point. i.e  'test@example.com'

$sql = "SELECT CONCAT_WS(' ', first_name, last_name) AS user_name FROM user_table WHERE email = '$email'";
$result = mysql_query($sql);
if (!$result) {
    // Handle error 
    echo 'Query failed. SQL: ', $sql, ' Error: ', mysql_error();
    exit;
}

// Inserted new row here

The problem with the above code is that it was written with an assumption that it's alright to insert a new row because there was no error returned after the query. This is a costly mistake. A query can return no error but there may or may not be data waiting to be retrieved from the results table. You must use mysql_num_rows() to see if there are any rows in the results table, or retrieve the data with one of the many functions available, like mysql_fetch_assoc(). Only after doing one of these two methods will you really know if there is data that matched the search criteria (in the 'WHERE' clause) or not. I can't stress this point enough.

Now, the important missing code segment has been added in this example:
.
.
.
$result = mysql_query($sql);
if (!$result) {
    // Handle error 
    echo 'Query failed. SQL: ', $sql, ' Error: ', mysql_error();
    exit;
}

// Must fetch the data 
$row = mysql_fetch_assoc($result);
if (!$row) {
    echo 'No user found with that email address';

    // It's now alright to insert a new row here
 
} else {

    echo 'That email address is already being used by ', $row['user_name'];

}
Here's an example using the mysql_num_rows():
.
.
.
$result = mysql_query($sql);
if (!$result) {
    // Handle error 
    echo 'Query failed. SQL: ', $sql, ' Error: ', mysql_error();
    exit;
}

// See how many rows matched the search 
$nbr_rows = mysql_num_rows($result);
if (0 == $nbr_rows) {
    echo 'No user found with that email address';

    // It's now alright to insert a new row here
 
} else {

    // Can't display who already uses it because we haven't retrieved the data yet
    echo "That email address is already being used by $nbr_rows member(s)";

}
In this case, having the email address column as being a non-duplicate index or primary key would also help. When an attempt to add a new row with an already existing email address, MySQL will not allow it and return a duplicate entry or key error.


Q: Is there another way of getting around escaping quotes all the time?
A: Sample code:
echo "<table><tr><td colspan=\"4\">Title: <input type=\"text\" name=\"group\" size=\"36\" maxlength=\"36\"></td></tr></table>";
This shows that all the double quotes in the string are escaped (\"). When you don't have any PHP variables inside the double quotes, then there's no need to start the string with double quotes. In this case, you can start the string with single quotes like this:
echo '<table><tr><td colspan="4">Title: <input type="text" name="group" size="36" maxlength="36"></td></tr></table>';
That makes it much easier to read and there's less typing. Whatever character you start the string with, single or double quotes, that same character must be escaped if it's contained within that string (but the other quote doesn't have to be).

Here are two options, when you use variables:
$group = 'group';

echo "<table><tr><td colspan='4'>Title: <input type='text' name='$group' size='36' maxlength='36'></td></tr></table>";

// or this way:
echo '<table><tr><td colspan="4">Title: <input type="text" name="', $group, '" size="36" maxlength="36"></td></tr></table>';

// or when assigning to a variable:
$table = '<table><tr><td colspan="4">Title: <input type="text" name="' . $group . '" size="36" maxlength="36"></td></tr></table>';
echo $table;

Some of my fellow colleagues may not approve of me letting you know about the heredoc syntax method. Some just don't like its use, but it is another option and I think you should know about it even if you may decide not to use it. You may come across scripts that use it and it's good to know what it is and its syntax. Heredoc examples:
http://www.phpfreaks...t=0
http://www.phpfreaks...t=0

The best option is to keep all HTML and JavaScript out of your PHP scripts (or at least as much as possible). By using Smarty template engine you can keep the HTML and JavaScript out of your PHP scripts. It does require a bit of a learning curve though. A note on Smarty:
http://www.phpfreaks...t=0


Q: How do I handle different Timezones and Daylight Savings Time?

A: An example of handling timezones:
http://www.phpfreaks...t=0

And in the same post, handling Daylight Savings Time:
http://www.phpfreaks...t=0


Q: Is there a way I can execute PHP code that's stored in a file or table?

A: Yes, by using the eval() function. See examples here:
http://www.phpfreaks...=0
http://www.phpfreaks...=0


Q: How do I calculate the elapsed time between two dates in PHP?

A: An example of a function to calculate the differences between two dates:
http://www.phpfreaks...t=0


Q: Is there a way to return more than one value back from a function?

A: Yes, and here is an example:
http://www.phpfreaks...=0


Q: Can an include/require file return a value?

A: Yes, and here's an example:
http://www.phpfreaks...t=0#entry132833


Q: Is there a way to set the include path within PHP and not the php.ini file?

A: Setting the include path with ini_set() example:
http://www.phpfreaks...=0


Q: How do I read all the filenames in a directory?

A: Here's a coding example that reads all the filenames in one directory and populates an array:
http://www.phpfreaks...=0


Q: The set_error_handler() is not able to handle parse errors. Is there a way to stop displaying parse errors and other types too?

A: See error handling example using output buffering (ob_start):
http://www.phpfreaks...=0


Q: Is there a pre-made PHP function to tell me if a number is odd or even?

A: No, not exactly. However, you can build your own small function. See code here:
http://www.phpfreaks...=0


Q: How do I retrieve just the 'index.php' from this /home/user/index.php path?

A: Use basename() function or use the 'basename' index returned from the array of pathinfo() function. See: http://www.php.net/m...on.basename.php
http://www.php.net/m...on.pathinfo.php


Q: How can I retrieve the different parts of a URL?

A: Use the parse_url() function. See: http://www.php.net/parse_url


Q: Is there any way to change my web host providers php.ini settings?

A: They most likely won't let you change the main php.ini file, however, if they're using the Apache server, then you may be able to override your web host providers settings using a .htaccess file. You use the Apache php_flag or php_value directives. Basically, create a .htaccess file and place it in the root or web directory and place the settings you want to change in it, like this:
php_flag register_globals off
php_flag magic_quotes_gpc off
php_flag session.use_trans_sid on
php_value session.gc_maxlifetime 600
php_value session.cookie_domain .example.com
php_value arg_separator.output &amp;
php_value include_path .:/usr/lib/php:/usr/local/lib/php:/home/user/phplib

These settings remain permanent until you choose to change them again or delete the .htaccess file. See ini_set() too.

#7 toplay

toplay
  • Staff Alumni
  • Advanced Member
  • 973 posts

Posted 09 September 2004 - 03:00 AM

Q & A section continued:

Q: I'm trying to use sessions, but they aren't being saved?

A: There could be several reasons for this; it could be coding logic problems and/or session configuration settings problems. Below is a brief troubleshooting guide to help you figure out what the problem could be. The problem could be one of these or a combination of any of these. Please note that all these are listed here because these items have caused people issues at one time or another. So, don't assume anything and verify everything. In case you don't know, PHP sessions try to use cookies by default. Any reference to session settings (like session.xxx) is referring to the settings contained within the php.ini configuration file. Refer to: http://us3.php.net/session.
  • Check to make sure that the browser you're using has 'enable cookies' set on. Also, see item # 26 below.
  • Try using a different browser to see if it makes a difference.
  • Make sure that you close your browser window between each session test. This will delete the session cookie (provided the 'session.cookie_lifetime' is set to zero).
  • Set the 'session.save_path' to a valid directory such as "/tmp" for Linux/Unix and make sure it has the correct permissions set. For Windows, set it to something like "C:/temp" (or "c:\temp" or "c:\\temp" depending on server and version) and make sure the directory is there and isn't set to read-only.
  • The 'session.save_handler' should be set to "files" for normal/default flat file use. For database based sessions, it would be set to "user" (but if you were saving sessions in a table, you would already know that).
  • The following session settings give the most users access to your site:
    session.use_cookies=1
    session.use_only_cookies=0
    session.use_trans_sid=1

    By having the 'session.use_trans_sid' on it will put the session name and ID on all links/URL's automatically when a user doesn't accept cookies (provided of course that the 'url_rewriter.tags' is set with a proper value). Some people don't like to see that on their site's URL, but it's necessary to retain session data when a cookie can't be created. The choice to have it on is yours (it defaults to off). I tend to think that when 'session.use_only_cookies' is off (the default), then it makes sense to have the 'session.use_trans_sid' on. Similarly, if you're only going to allow cookie based sessions by having 'session.use_only_cookies' on, then it's alright to have 'session.use_trans_sid' off (the default), forcing users to accept cookies if they want to use your site. Also, see item # 12 below.
  • For PHP versions 4.1.0 and higher, use the $_SESSION superglobal array variable to store your sessions data in. For earlier PHP versions, use the $HTTP_SESSION_VARS variable instead. Inside functions and classes, you have to use the global keyword with $HTTP_SESSION_VARS. Example of both version uses:
<?PHP
session_start();

// For PHP >= 4.1.0
function set_var ($index, $value) {

    $_SESSION["$index"] = $value;

    return TRUE;
}

// For PHP < 4.1.0
function set_var ($index, $value) {

    global $HTTP_SESSION_VARS;

    $HTTP_SESSION_VARS["$index"] = $value;

    return TRUE;
}

set_var('foo', 'bar');
?>
  • You need to have a session_start() function call on every page where session data is set or will be read/used (assuming of course that 'session.auto_start' is set to off). It's best placed at the top of your script, but it doesn't have to be, as long as the script hasn't output anything to the browser yet. Otherwise, you'll get "headers already sent" warning messages. See the Session Errors - "headers already sent" warning messages section above for more details on that.
  • Use $_SESSION/$HTTP_SESSION_VARS or session_register() function but not both. Seriously, use one or the other. Don't mix using a session variable and session_register() in the same script. Note that session_register() function requires that the 'register_globals' setting be on for it to work (which is a security risk). Avoid having 'register_globals' on and using session_register() and related functions such as session_is_registered() and session_unregister(). For PHP version 4.1.0 and higher it's recommend to just use $_SESSION. Read the "Caution" boxes at this manual page: http://us3.php.net/s...ister#AEN116800
  • Put aside your script for a moment and try a small simple session test scripts to see if sessions work on your system:
    set.php script:
<?PHP
session_start();
$_SESSION['test'] = 'Hello World!';
header('Location: read.php?' . SID);
exit;
?>
read.php script:
<?PHP
session_start();
echo isSet($_SESSION['test']) ? $_SESSION['test'] : 'Not Set';
?>
Put both scripts in the same web directory. Run set.php. It will then redirect to read.php. If it works, then you should see 'Hello World!' displayed. If the session data isn't being saved, you'll see the 'Not Set' message instead. If you see the session name and ID in the URL, then it means session cookies aren't being created (or allowed). So, continue reading and trying different things listed here.
  • Look in the 'session.save_path' folder and see if you can see files in there. They will be named something like "sess_xxx", where "xxx" would be different 32 character session ID numbers. If you see files there, then that's a good sign that your session files are being created/saved. When you don't see files in there, then check the 'session.save_path' setting is really pointing to a valid directory with correct permissions set.

    To verify that sessions are really being saved, locate and use a text editor to open the 'sess_xxx' file generated when the test script above ran. You should see:
    test|s:12:"Hello World!";

    This is how sessions look when they are saved in serialized format. The 'test' is the session index value. The 's' indicates the value being saved is a string. The '12' is how many characters are currently being saved. And of course the value being saved is inside the double quotes.
  • When 'session.use_trans_sid' is on and your script uses header with location to redirect, then it's recommended that you use the SID constant in the URL to handle those times where a session cookie isn't saved. Having 'session.use_trans_sid' on will not automatically put the SID in redirects; you have to do it manually yourself throughout your scripts. Example:
<?PHP
session_start();
// Do something here
header('Location: scriptname.php?' . SID);
exit;
?>
When session cookies are not saved, you will loose the session if you don't add the SID on the header with location commands. The page being redirected to will not know that there's an existing session, and instead would end up creating a new session ID (of course in the case where the redirected page has a session_start). Also, see item # 6 above.
  • The $_SESSION variable is not accessible until after a session_start(). Make sure you don't try and assign or use $_SESSION until after a session_start().
  • The session_name() and session_id() functions without passing an argument return their current respective session name and session ID values. Without any arguments, these functions must be called anywhere in a script AFTER a session_start(). When you're using these functions with arguments to assign a session name or ID, then these functions must be called BEFORE the session_start() function. Otherwise, it has no effect. An example of just retrieving session info.:
<?PHP
session_start();
echo session_name();  // Displays current session name in effect
echo session_id();   // Displays the current session id
?>
Here's an example when setting custom session names and ID's:
<?PHP
echo session_name('sess');  // Set the session name 
echo session_id('abcdef123456');   // Set the session id
session_start();
?>
  • Don't use session_destroy() unless you're sure that you no longer want the whole entire session saved. If you wish to keep the session ID but want to start fresh, you can clear the session data by doing: $_SESSION = array();

    To just remove individual pieces of session data, then use the unset() function, like this:
    unset($_SESSION['index']);

    Where 'index' is the array key you used to save information in. Do NOT ever use unset() on the whole session variable itself like so: unset($_SESSION) because that will stop you from being able to save anything through $_SESSION anymore.

    Note that session_destroy() doesn't clear $_SESSION and the session cookie. Examine the following code example because there's a flaw.
<?PHP
session_start();

if ('logout' == $action) {
    session_destroy();
}

$logged_in = isSet($_SESSION['logged_in']) ? TRUE : FALSE;

if ($logged_in)
    echo "You're still logged in.";
else
    echo "You're logged out now.";
?>
Lets assume that the user is logged in and $_SESSION['logged_in'] has already been set. When the user requests to be logged out, which will make the $action variable contain 'logout', the session_destroy() will be executed. However, the $_SESSION variable information will still be intact. The logic flow will then fall through and display the wrong message to the user. It will display the still logged in message when it should display that they've been logged out. To correct the bug, a $_SESSION = array(); would be placed before the session_destroy() function call. Actually, from what I've experienced, this can be used after session_destroy() too. Also, delete the session cookie by using setcookie(). Full corrected code:
<?PHP
session_start();

if ('logout' == $action) {
    $_SESSION = array();
    session_destroy();
    if (!headers_sent()) {
            $_sessCookie = session_get_cookie_params();

            $_result = @setcookie(session_name(), '', time() - 172800,
                                  $_sessCookie['path'],
                                  $_sessCookie['domain'],
                                  $_sessCookie['secure']);
    }
}

$logged_in = isSet($_SESSION['logged_in']) ? TRUE : FALSE;

if ($logged_in)
    echo "You're still logged in.";
else
    echo "You're logged out now.";
?>
  • Make sure that 'session.gc_maxlifetime' is set to a decent value in seconds. It defaults to 1440 seconds (24 minutes). This is the session inactivity timeout limit. When there's no activity (by the user) within the designated number of seconds, PHP will expire the session and consider it void/useless. Note that when the user does an activity like refresh the page or click on a link on your site, the inactivity timer is reset back to zero. Meaning, that the user has another 24 minutes (in this example) from the last time they did something on your site before the session will expire; and so on and so on. Some people mistake it to mean that the session will expire after 24 minutes have elapsed from the time the session was first created. This is not so.
  • The 'session.cookie_lifetime' should NOT be set less than the 'session.gc_maxlifetime' value. It defaults to zero which is fine because it means the session cookie will remain in effect until the user closes their browser window. This setting is also specified in seconds. Some people set the 'session.gc_maxlifetime' and 'session.cookie_lifetime' to something high (like days or months) which I think is a security risk. Try using straight cookies instead.
  • Some people have had problems getting sessions to work with frames. Sessions are locked while being accessed. When having frames, each page might fight for access to the session data. Some may have to wait while another page releases it. The PHP manual recommends to use the session_write_close() function right after a script/page is done with using the session data. This releases the lock sooner and framed pages won't have to wait on each other as long. The following post is a member who had no problems in the end with using sessions in frames:
    http://www.phpfreaks...=0
  • If you're noticing that sessions aren't being saved when you do a redirect (even with using SID), then it might help to use session_write_close() just before the header() with location function. This assures the session data will get saved before the redirect. Session data is normally saved automatically at the end of your script. Note the session_commit() function is an alias of session_write_close(). Also, have an 'exit' in your script (preferably right after the header() command).
  • If you're getting the "headers already sent" warning messages, then see the Session Errors  – or about getting the "headers already sent" warning messages section above.
  • Most of you know about the Internet Explorer fix by using "Cache-control: private". If not read about it here:
    http://www.phpfreaks...=0
  • When saving objects in sessions, use serialize() to save them and unserialize() when you retrieve/read them. See manual page on Serializing objects. Also, the 'session.auto_start' setting must be off (which is the default). This is because PHP objects inside session classes must be loaded before the session in started. That can't happen when the session gets automatically started because of 'session.auto_start' being on. Load your classes, then use the manual session_start() function instead.
  • When you unset() a session variable, then do a redirect with header() with location, sometimes the session information that you unset() isn't gone. Try using session_write_close() before the header() with location function, and put an 'exit' in your script. It's best to put the 'exit' right after the header() function. Since you know that you want to redirect, why then have any more code following the header() other than an 'exit'?

    I don't know why this works, but if I had to guess; I would say that the 'exit' makes PHP call all the necessary internal cleanup functions. One of those being responsible for saving the current session data. Whereas just having your script end without an 'exit', seems to not call all the same internal cleanup functions. This is only my opinion and is not based on fact. This may very well be a PHP bug.
  • You still need to do a session_start() first even when you're planning on doing a session_destroy().
  • The keys in the $_SESSION associative array are subject to the same limitations as regular variable names in PHP, i.e. they cannot start with a number and must start with a letter or underscore (no spaces). For more details see the section on variables in the PHP manual. Although, in real life use, I've found that this rule doesn't really apply (isn't enforced), I would nevertheless recommend you conform to it in the event that PHP is modified in the future to restrict this in some way (or rather finally enforce it).
  • Under the Windows platform, the use of certain software such as Norton Internet Security or Personal Firewall, McAfee Personal Firewall Plus, GhostSurf Pro, and ZoneAlarm may block cookies from being created. Turn these types of software off or adjust their settings to allow cookie generation. ZoneAlarm has caused problems for two people in this post:
    http://www.phpfreaks...ndpost&p=185104
  • There's been reports of session cookies not being saved (or not saved correctly) on IIS server (version 5 & 6). By converting to Apache, hopefully you should have less headaches.
  • If you're having problems passing sessions between your domain and sub-domains (or vice-versa) then set the 'session.cookie_domain' to '.example.com'. Notice there's a dot before the domain name. This allows the session cookie to be used at www.example.com or anysubdomain.example.com. You can use ini_set() or session_set_cookie_params() to set it. See this topic.
  • See this post if you're having problems passing sessions from a non-secure (http:) page to a secure (https:) page. This post shows you how to know whether you're on a secure page or not.
  • Courtesy of member mlange: If you are experiencing sessions being lost or another user is getting sessions of another person, then it could be because your web host provider is using a load balancing cluster architecture. Basically it means that when one server is being bombarded with too many requests, the system balances the requests over to another server (automatically behind the scenes). The new server that you get switched over to may not have a record of the session (so it's lost), or may coincidently have the same session ID, in which case you would take over someone else's session activity. This could happen on a HTTP request by HTTP request basics. Check with your web host provider if they utilize this type of system balance architecture. Please note that these symptoms may also be the result of just poor programming or bugs in your code.

    It seems the solution to this type of problem is to save your PHP sessions in a database. That way the servers can do all the load balancing they want, and your code will still find the sessions because they'll be in a centralized table (assuming that no matter which server you're on, you'll still have access to the database server). Saving PHP sessions in a table involves using the session_set_save_handler() function to make PHP utilize your own custom written session handling functions. This could get a little complicated. I've written a PHP 4 class that uses MySQL to save PHP sessions. Please do not contact me about my DB_eSession class because it comes with no support whatsoever.





0 user(s) are reading this topic

0 members, 0 guests, 0 anonymous users