Archive for the ‘mysql’ Category

Class 8 – Using phpMyAdmin to administer a database

Tuesday, July 21st, 2009

For our assignment today, we will need to set up a table in the database where the information about all the products in our e-commerce site will be stored.  This post outlines the steps necessary to create a table in the database.

All administration of databases for our class will be handled through phpMyAdmin, a web-based database administrative tool written in PHP and published for free by an altruistic development team.  phpMyAdmin allows us to easily do common database tasks using a (relatively) intuitive graphical interface.

The first thing we will be doing is setting up a table in the database.  Database servers can hold more than one database.  To create a table in the database, we need to first select which database we want to use.  On the left side of phpMyAdmin, select “classdb”: this is the database for this class.

Select database

Select database

Selecting the database will bring up a list of all the tables that already exist in that database.  At the bottom of this list, you will see a space in which we can create a new table on database “classdb”.  Enter in the name of your table, and the number of fields it will hold.  The name should be your first initial followed by your last name, followed by an underscore, followed by the name you want to give the table.  So, for example, my table would be “abloomberg_products”.  The number of fields in this example is 5.

Create new table

Create new table

Once we click “Go”, we are brought to a page that asks us to indicate what fields we would like the table to have, and what type of data will be stored in these fields.

  • For any table we ever make, the first field will always be called “id”, and will be of type “Integer”, and have an extra property called “auto_increment”.  It will also be selected as being the “Primary Key”.
  • Likewise, all tables we make will have the last field named “created”, which will be of type “Timestamp”, and will have the CURRENT_TIMESTAMP checkbox selected.

The other fields that go between “id” and “created” will depend upon the table.  In this case, they are:

  • “title” of type “Varchar” – this will hold the title of any products in our table
  • “description” of type “Text”, and length 255 – this will hold the description of any products in our table
  • “price” of type “Float” – this will hold the price of any products in our table

Make sure your table has the same settings as the following:

Set fields for new table

Set fields for new table

Once you click “Save”, you should see your table name show up in the left navigation area in phpMyAdmin:

Verify new table created

Verify new table created

If you click the tab named “Structure”, you will see the structure of the table you just created.  Yours should look like this:

Table structure

Table structure

If you click the tab named “Insert”, you will be able to insert a few rows into this table.  Type the following two rows of data, and click the “Go” button.  Notice that we are leaving the “id” field blank – the id for any row will be automatically created because we selected the “auto_increment” extra when we created the table.

Insert rows into table

Insert new rows into table

At any time, you can browse the rows you have stored in your table by clicking the “Browse” tab.  This will show you a paginated list of data that is stored in the table.

Browse existing rows in table

Browse existing rows in table

The “SQL” tab allows you to run arbitrary SQL commands on the table.  This is an example of asking for the database to show you a list of all the data in the table:

SELECT * FROM abloomberg_products WHERE 1
Run SELECT query on table

Run SELECT query on table

And this is an example of inserting a new row into the table:

INSERT INTO abloomberg_products (title, description, price) VALUES ('Another great cookie', 'This one has ginger schnapps in the mix', 7.49)
Run INSERT query on table

Run INSERT query on table

The following is how you would update an existing row in the table:

UPDATE abloomberg_products SET title='Dark Chocolate Cake', description='Only the finest 85% cocoa goes into each hand-made cake.', price=19.99 WHERE id=1
Run UPDATE query on table

Run UPDATE query on table

And this shows how you would delete a row from the table, depending on the value stored in its id field:

DELETE FROM abloomberg_products WHERE id=1
Run DELETE query on table

Run DELETE query on table

Class 12 – Exporting & Importing Database Tables

Thursday, May 14th, 2009

Now that the course is over, you are free to keep using the class database at your own risk for as long as you like.  However, I will be making changes on the server in preparation for the next course, and these will most likely affect your database tables.  So I recommend you make a backup of your database tables, as explained here.  If you eventually set up your own hosting account with your own domain, you will be able to import these tables into the MySQL server, as detailed below.

Exporting your tables

To export a copy of your tables from the database, follow these steps:

Step 1. Select the database that holds the tables you want to export.

Do this by selecting “classdb” in the top left of the page.  This will take you to the “Database View” that will show you a list of all the tables in that database.

select database

select database

Step 2. Select the “Export” tab at the top of the “Database View” page

insert tab

export tab

Step 3. Select the tables you want to export

Do this by holding down the Control key and clicking the name of each database you want to select in the list. (On Mac, hold down the Command key instead of the Control Key).

select tables to export

select tables to export

The default settings should be fine for the rest of the controls on this part of the page.  The important points are to make sure both the Structure and the Data of your tables are getting exported.  So the checkboxes next to the words “Structure” and “Data” should be checked.

make sure Structure and Data are both selected

make sure Structure and Data are both selected

Step 4. Click the “Save as file” checkbox

At the bottom of the “Export” page, there is a checkbox next to the words, “Save as file”.  Make sure this is checked.

In this same area, you can optionally select to have the database export file compressed into a zip or gzip file.  This will make the file smaller, which is perfectly okay, but not necessary.  It’s your choice whether to compress the file or not.

save settings

save as file settings

Step 5. Click “Go” to export

At the bottom right of the “Export” page is the submit button with the word, “Go”.  Click it to complete the export.

go!

go!

Step 6. Save file

After a few seconds, you may see a dialog box asking you whether you want to “Open” or “Save” the file.  Make sure you select “Save”, and as always, make sure you remember which folder the file is getting saved into on your hard drive.

save file

save file

Congratulations!  You have successfully exported your tables.

Importing your tables

Assuming you have exported your tables from the classdb database, you may one day want to import them your own database on your own server.  Doing this is even simpler than exporting was.

Before you begin, you must have a database set up.

It’s important to remember that we only exported the tables, not the actual database.  So before you can import your tables, you will have to first create a database in which to import them.  You can call this database any name you want.  It does not have to be named, “classdb”, like the original database.

Most web hosts will have a control panel that allows you to create databases on your server.  Usually they disable this feature from phpMyAdmin.  As an example, here’s a screenshot of what the “Create a database” control panel looks like with Dreamhost, the host for the server we used in class.

create database in Dreamhost control panel

create database in Dreamhost control panel

Assuming you have created a database on your server, or you are using an existing database, here are the steps necessary to import your tables.

Step 1. Select the database that you want to import the tables into

Do this in phpMyAdmin by selecting your database name in the top left of the page.  This will take you to the “Database View” that will show you a list of all the tables in that database, if any exist.

select database

select database

Step 2. Select the “Import” tab at the top of the “Database View” page

import tab

import tab

Step 3. Select the file with the tables you want to import

The “Import” page will ask you for the “File to import”.  Click the “Browse” button to browse your hard drive for the file you exported.  Once that file is selected, you can leave all the other settings at their defaults.

file to import

file to import

Step 4. Click “Go” to import

Click the “Go” button to complete the import.

go!

go!

Congratulations!  You have imported tables into your database.

As a confirmation, you should now see the new table names show up on the left side of the page, where all tables are listed that are contained within the selected database.

list of tables

updated list of tables

Class 11 – Search in MySQL

Monday, May 4th, 2009

As we discussed in class, there are two ways of implementing search functionality on your sites using built-in MySQL commands.

The first technique takes advantage of the WHERE LIKE clause in SQL.  The second technique takes advantage of the FULLTEXT search feature built into MySQL.

Both these methods, of course, presume that the content you want to be searching is stored in a MySQL database.  If the content you want to search is hard-coded in an XHTML page, rather than stored in a database, then these methods will not be useful to you, and you would do better to use Google Custom Search, Yahoo Search, or some other service that provides search functionality for regular XHTML documents.

Search using WHERE LIKE

This is the simplest form of MySQL search. You can see this example live in your browser here.

Let’s assume that we have a table, called “abloomberg_blogposts” that stores a bunch of blog posts.  The table has the fields, “id”, “title”, “message”, and “created”.

As you know, the SQL query to read all the rows from the table would be:

SELECT * FROM abloomberg_blogposts WHERE 1

The “WHERE 1″ part of the query tells MySQL to return all the rows in the table.

To read only those rows that had the title “cat”, we could run this query:

SELECT * FROM abloomberg_blogposts WHERE title LIKE '%cat%'

In this case, the “WHERE title LIKE ‘%cat%’” part of the query tells MySQL to return only those rows in the table where the “title” field contains the string, “cat”.  The “%” percent signs indicate wild card that matches any character or bunch of characters.

Because of the use of the wild cards before and after the search term, this query will match any of the following strings:

cat
catamaran
bobcat
concatenate

If we only wanted to match those rows where the “title” field began with the word, “cat”, we could use the following query with only a wild card after the search term:

SELECT * FROM abloomberg_blogposts WHERE title LIKE 'cat%'

Likewise, if we wanted to only match those rows where the “title” field ended with the word, “cat”, we could use this query:

SELECT * FROM abloomberg_blogposts WHERE title LIKE '%cat'

Finally, if we wanted to search more than one field, we can combine multiple queries together using the UNION keyword in SQL.  For example, if we wanted to search both the “title” and the “message” fields at once, we could use the following query:

SELECT * FROM abloomberg_blogposts WHERE title LIKE '%cat%' UNION SELECT * FROM abloomberg_blogposts WHERE message LIKE '%cat%'

We could chain together as many queries as we like using the UNION keyword, and MySQL will return the combined results of all of them.

Assuming you are running queries like this in PHP, rather than directly in SQL, you will probably want to store the search term in a variable rather than hard-code it in the SQL command.  Replacing the search term with a PHP variable called $searchTerm will make your queries look something like this:

$myQuery = "SELECT * FROM abloomberg_blogposts WHERE title LIKE '%{$searchTerm}%' UNION SELECT * FROM abloomberg_blogposts WHERE message LIKE '%{$searchTerm}%'";

Search using FULLTEXT search

The alternative method of searching in MySQL is to use the FULLTEXT search feature built into MySQL. You can see this example live in the browser here.

This method allows you to search more than one field in a single query.  It also allows you to be a bit more flexible with your search, and it is smart enough to ignore common words like “a”, “the”, “of”, etc.

Here is an example of using MATCH AGAINST to search for the word “cat” in both the “title” and “message” fields of our “abloomberg_blogposts” table:

SELECT * FROM abloomberg_blogposts WHERE MATCH (title, message) AGAINST ('+"cat"' IN BOOLEAN MODE)

As you can see, the fields you want to search go inside the MATCH(…) section, and the search term you want to find goes inside of the AGAINST(…) section of the query.

The plus sign, “+”, in the query indicates that you want to search for all rows that contain the word “cat”.  If you replaced this with a minus sign, “-”, the query would return all rows that did not contain that word.

Assuming you are running this query in PHP, rather than directly in SQL, you will most likely want to replace the search term with a variable.  And your PHP code would look something like this:

$myQuery = "SELECT * FROM abloomberg_blogposts WHERE MATCH (title, message) AGAINST ('+\"{$searchTerm}\"' IN BOOLEAN MODE)";

Important Note: In order to use this FULLTEXT search feature, MySQL requires you to create a FULLTEXT index on any text field (including varchar and text fields) that you want to use in your search.  The FULLTEXT index is a way of optimizing those fields for search.

If you look at the structure of the abloomberg_blogposts table in phpMyAdmin, you will see that there is a FULLTEXT index on the title and message fields, which allows this example search to work.

Indexes used by the abloomberg_blogposts table

Indexes used by the abloomberg_blogposts table

Creating a FULLTEXT index in phpMyAdmin

You must create such an index on the fields you intend to search in your own code in order to use the FULLTEXT search technique.   Creating such an index is simple in phpMyAdmin.  First go to the “Structure” tab of the table you will be searching.  In the Indexes box on that page, in the “Create an index on … columns” text field, fill in how many fields you wish to create the index for (i.e. how many fields you will be searching), and then click Go.  The next page will ask you which fields you want to index (i.e. which fields you will be searching), and it also asks you to name this index.  You can name the index anything, but it’s probably best to use a name that includes the field names the index uses.  In my example, the index is named, “title_message”.

More information on FULLTEXT search
http://www.onlamp.com/pub/a/onlamp/2003/06/26/fulltext.html

http://dev.mysql.com/doc/refman/5.0/en/fulltext-search.html

http://dev.mysql.com/doc/refman/5.1/en/fulltext-boolean.html

Class 9 – Pagination in PHP

Saturday, May 2nd, 2009

Here is an example of how to do pagination of data in PHP.

Let’s say you have a database table full of animals.  You only want to show 10 animals per page, with “previous” and “next” buttons to allow users to go to the previous or next page of results.

There are a few different things we need to keep track of in our code to make this type of pagination work.  Here’s a quick run-down of the most important pieces of code in the controller:

  • $pageNum = the page number of the page the user is viewing
  • $numRowsPerPage = the number of results we want to show on each page
  • $startIndex = the index of the first row we want to display on this page
  • $endIndex = the index of the last row we want to display on this page
  • $numRowsTotal = the total number of results in the database
  • $numPagesTotal = the total number of pages of results

The current page number

The current page number is retrieved from the query string of the URL using the ubiquitous $_REQUEST variable.

//FIGURE OUT WHICH PAGE OF RESULTS TO SHOW
$pageNum = $_REQUEST['page']; //which page to show
//if no page requested, load the first page
if (empty($pageNum)) {
	$pageNum = 1;
}

This code checks for the page number in the query string.  If there is no page number there, it defaults to page 1.

The number of results to show on each page

The $numResultsPerPage variable is just hardcoded to some value:

//PAGINATION SETTINGS
$numRowsPerPage = 10; //how many results to show per page

The index of the first row to show

If the user is viewing page 1, and there are 10 rows per page, then the first row we want to show them is row 1, and the last row is row 10.  If they are on page 2, then the first row we want to show them is row 11, and the last is row 20… because they have already seen 1-10.

The general formula for this is:

//calculate the start index of the rows to show on this page
$startIndex = ($pageNum-1) * $numRowsPerPage;  // get the starting index number of the first item to show on this page

The index of the last row to show

In general, the index of the last row on the page is just the index of the first row, plus the number of rows on the page.

//calculate the end index
$endIndex = $startIndex + $numRowsPerPage;

However, on the very last page, it may be that there are fewer than 10 results.  This means that the index of the last row may not be just the index of the start row plus 10.  So we need to check to make sure that if we are on the last page, the value we calculated for the index of the last row is not greater than the total number of rows in the table.

//make sure on the last page that we don't have an end index that is greater than the total number of rows
if ($endIndex > $numRowsTotal) {
	$endIndex = $numRowsTotal;
}

The total number of rows

The total number of rows is just how many rows there are in the database table.

$numRowsTotal = sizeof(getAnimals()); //get the total number of animals in the database

This function getAnimals() returns an array with the full list of animals, and we use PHP’s built-in sizeof() function to get the number of elements in that array.

The total number of pages

The total number of pages is just the total number of rows, divided by the number of results per page.  That’s the math.

$numPagesTotal = ceil($numRowsTotal / $numRowsPerPage); //get the total number of pages

Display the number of results

Assuming the aforementioned variables have all been set up properly in the PHP in your controller script,  you will probably want to display the indexes of the results shown on any given page, as well as the total number of results somewhere in the XHTML template you are using for the view of your application.

The following bit of XHTML interspersed with “template-style” PHP will display the start and end number of the results on the page, as well as the total number of results in a nicely formatted, “normal” way that is commonly used by search engines:

<span>Displaying <?php echo $startIndex + 1 ?>-<?php echo $endIndex ?> of <?php echo $numRowsTotal ?> results</span>

This will output something like this in the browser,

Displaying 1-10 of 35 results

Display links to other pages

Let’s say you have 10 pages of results.  The first time a user comes to your site, they will see page #1.  So obviously, in your XHTML templates, you will also want to dislpay links to the other pages of results.  To do this, you will make use of some of the other variables we have set up in the PHP controller script.

Here is an example of how to use the PHP variables to output a very ordinary set of links to other pages:

<?php if ($pageNum > 1) : ?>
<a href="index.php?page=<?php echo $prevPage ?>">Prev</a>
<?php endif ?>
<?php if (($pageNum-1) * $numRowsPerPage + $numRowsPerPage < $numRowsTotal) : ?>
<a href="index.php?page=<?php echo $nextPage ?>s">Next</a>
<?php endif ?>
<?php for ($i=1; $i<=$numPagesTotal; $i++) : ?>
<a <?php if ($pageNum == $i) : ?>class="selected"<?php endif ?> href="index.php?page=<?php echo $i ?>"><?php echo $i ?></a>
<?php endfor ?>

Let’s take this code line-by-line.  The first three lines here display the “Prev” link to the previous page:

<?php if ($pageNum > 1) : ?>
<a href="index.php?page=<?php echo $prevPage ?>">Prev</a>
<?php endif ?>

If the user is on the first page, it doesn’t make sense to have a link to the previous page since there is no previous page, so we check to make sure the user is not on the first page before displaying this link.

The next three lines of code display the link to the “Next” page:

<?php if (($pageNum-1) * $numRowsPerPage + $numRowsPerPage < $numRowsTotal) : ?>
<a href="index.php?page=<?php echo $nextPage ?>s">Next</a>
<?php endif ?>

This code is basically just making sure that there is a next page before outputting the link.  It doesn’t make sense to show a link to the next page if we’re already on the last page.

And these last three lines display the page numbers of all the pages as links:

<?php for ($i=1; $i<=$numPagesTotal; $i++) : ?>
<a <?php if ($pageNum == $i) : ?>class="selected"<?php endif ?> href="index.php?page=<?php echo $i ?>"><?php echo $i ?></a>
<?php endfor ?>

The for loop here loops through from the first to the last page, and displays each page number as a dynamic link to that page of results.  It highlights the current page by adding a CSS class called “selected” to the link tag.

Class 10 – Debugging PHP and MySQL

Thursday, April 23rd, 2009

PHP debugging is an art-form.  Here are some common tricks of the trade.

Indent your code properly

If you do not properly indent your code so that you can visually see the hierarchical relationships in it, you will never be able to successfully debug it.  Furthermore, you will never become a successful developer.  It’s that simple (almost).  This applies to all XHTML, CSS, Javascript, and PHP code you will ever write.

Before you do anything else, indent your code.  You will be amazed at how many errors you will see immediately.

The rule: Something that is “inside of” something else should be indented one level to the right.  For example:

function doSomething($indented) {
  $futureSuccess = false;
  if ($indented) {
    $futureSuccess = true;
  }
  return $futureSuccess;
}

Notice that all code “within” the function is indented to the right, relative to the opening and closing of the function.  Further note that the code within the “if statement” is also indented one more level to the right.  This makes the code easy to read, and so stupid errors, such as missing brackets, become easier to spot.

Foreach statement errors

If you encounter an error that looks like this, the problem is simple:

Picture 1

Let’s say your foreach statement looks like this:

foreach ($someArray as $someElement) {
   ///some stuff here
}

The error: This error is telling you that the variable $someArray is not actually an array.  Don’t argue… PHP is always right about this.

The solution: make sure the variable you think is an array really is an array. You can see the contents of the array by printing out the raw contents of the array using the print_r() function like this:

print_r($someArray); //dump out the raw data in the array
foreach ($someArray as $someElement) {
   ///some stuff here
}

Hint: you can make sure your array is aways an array by declaring it as an array before you start using it.

$someArray = array(); //set the variable to a blank array
//do some stuff to put data into the array here
foreach ($someArray as $someElement) {
   ///some stuff here
}

This hint is especially useful if you are populating the array with data pulled from a database. For example, let’s say that you are running a query to load all of the comments for a blog post and put them into an array called $comments:

$result = mysql_query($myQuery); //run the query
while($row = mysql_fetch_array($result)) {
  $comments[] = $row; //put the current row into the comments array
}

If, as is perfectly common, the blog post in question does not have any comments associated with it, the while loop will never loop, because there are no rows in the result variable.  This means the $comments array will never have any data put into it, which is fine since there are no comments.

But if you later try to loop through all the elements in the comments array like this:

foreach ($comments as $comment) {
  //do something
}

You will get this error because you have not said that $comments = array();  So make sure you always specify that an array is an array:

$comments = array(); //make this variable a blank array
$result = mysql_query($myQuery); //run the query
while($row = mysql_fetch_array($result)) {
  $comments[] = $row; //put the current row into the comments array
}

Unexpected $end error

You will most likely come upon this error at some point:

Picture 2

This is equally simple.  It means that you are missing an ending bracket on some block of code.  For example:

while ($something == true) {
  //do something

The error: If you do not have a closing “}” at the end of the while loop, it will cause this error.  The same is true for closing brackets on any kind of block statement, like for loops, if statements, while loops, switch statements, function definitions, class definitions, etc.  Anywhere you have an opening bracket, you must eventually have a closing bracket:

while ($something == true) {
  //do something
}

Hint: By the way, this same error is produced if you are missing a closing heredoc tag, or if the heredoc tag is not all alone on a line with no spaces before or after it.  Here is an example of a heredoc tag with some spaces on the same line as the END; tag: this will produce the error.  The END; tag must be the only thing on the last line.

print <<<END
this is some text I want to print to the page
  END;

Can’t connect to local MySQL server

If you see an error that looks like this, it means that your script did not successfully connect to the database:

Picture 3

First debugging step: First, make sure you are including the script that has all the database information in it at the top of your script:

//require database connection info
require_once("dbinfo/db.php");

Second debugging step: Make sure the db.php file has the correct username, password, hostname, and database name in it.

$dbServer = "mysql.fakedomain.com";
$dbUser = "amos";
$dbPass = "noneofyourbusiness!";
$dbName = "exampledb";

Third debugging step: Make sure that you are connecting to the database at the top of your script, and disconnecting at the bottom:

//require database connection info
require_once("dbinfo/db.php");

//connect to database
$cxn = @ConnectToDb($dbServer, $dbUser, $dbPass, $dbName);
//do something interesting
//disconnect from database
$cxn = @DisconnectFromDb($dbServer, $dbUser, $dbPass, $dbName);

MySQL query not working as expected

It happens every class that someone has a problem where the data they were expecting to store in the database does not seem to be getting stored there.   Or the rows they were trying to read with a SELECT statement are not getting read.  MySQL queries are extremely simple things to debug.

Let’s say you have a query statement like this, but it’s not working.

$myQuery = "INSERT into abloomberg_posts (user_id, title, body) VALUES ({$userId}, '{$title}', '{$body}')";
$result = mysql_query($result);

Before you start: Before you even bother debugging, you should have phpMyAdmin open in a browser tab so that you can easily browse the contents of the table you are trying to insert data into.  Clicking the “Browse” tab in the “table view” for the table you are dealing with is easiest way of checking to see if data is getting stored in your table.

First MySQL debugging step: First, you want to make sure that the command to query the database is actually getting executed the way you think it is.  Maybe the variables you are using, $title, and $body do not have what you think they have inside them.  So add a little echo statement that outputs the query you are trying to run.

$myQuery = "INSERT into abloomberg_posts (user_id, title, body) VALUES ({$userId}, '{$title}', '{$body}')";
echo $myQuery;
$result = mysql_query($result);

You will be surprised at how often this simple echo statement will show you the problem. For example, if this code outputs something like the following:

INSERT into abloomberg_posts (user_id, title, body) VALUES (, '', 'this is the body')

That would indicate that the $userId and $title variables do not have anything in them, which is why they are showing up blank when you echo the query.

Second MySQL debugging step: the second easiest debugging step is to output any errors that MySQL is encountering.  These won’t be output by defuault, so you must specify that you are interested in seeing them.  Use the mysql_error() function after you run the query:

$myQuery = "INSERT into abloomberg_posts (user_id, title, body) VALUES ({$userId}, '{$title}', '{$body}')";
$result = mysql_query($result);
echo mysql_error(); //output any MySQL errors

If this produces an error on the page, it will indicate if your MySQL query syntax has something wrong with it.  Check the syntax of the query you are running by echoing it as we did in the first step, and make sure it looks correct:

$myQuery = "INSERT into abloomberg_posts (user_id, title, body) VALUES ({$userId}, '{$title}', '{$body}')";
echo $myQuery . "<br />"; //echo the query to the page
$result = mysql_query($result);
echo mysql_error() . "<br />"; //output any MySQL errors

Create a custom error handler

It is possible to handle errors in a customized way.  I do not recommend you do this in PHP, but I’m including it here to be thorough about the topic.  Feel free to skip the rest of this blog post.

You can choose to ignore some errors and respond to others as you see fit.  To do so, you will need to create an error handler.  This is conceptually similar to how we created event handlers in Javascript to respond to onclick events, etc.

First of all, you must specify which errors you want to see using PHP’s built-in error_reporting() function.  You can see the full list of possible errors on the PHP reference page for this function.  Here are the most common ones you’ll be interested in:

error_reporting(E_USER_ERROR | E_USER_WARNING | E_USER_NOTICE);

Then you specify which function gets called when an error of any of those types is encountered using the set_error_handler() function.  This function takes one parameter: the name of the function that gets automatically called when an error occurs.

$errhandle = set_error_handler("myErrorHandler");

And of course, this means you must also define the function, in this case “myErrorHandler” that you specified just now.  When an error occurs, this function will get called and automatically passed four parameters: the “error number”, the error message, the file that caused the error, and the line number in the code that produced the error.  Here is a simple error handler that just detects which type of error occured, and outputs some text for each of them:

function myErrorHandler($errno, $errstr, $errfile, $errline)  {
  switch ($errno) {
    case E_USER_ERROR:
      echo "<b>My ERROR</b> [$errno] $errstr<br />n";
      echo "  Fatal error in line $errline of file $errfile";
      echo ", PHP " . PHP_VERSION . " (" . PHP_OS . ")<br />n";
      echo "Aborting...<br />n";
      exit(1);
      break;
    case E_USER_WARNING:
      echo "<b>My WARNING</b> [$errno] $errstr<br />n";
      break;
    case E_USER_NOTICE:
      echo "<b>My NOTICE</b> [$errno] $errstr<br />n";
      break;
    default:
      echo "Unkown error type: [$errno] $errstr<br />n";
      break;
  }
}

Suppressing errors

As an alternative, if you just wanted to suppress all errors, you could make a function like this instead:

function myErrorHandler($errno, $errstr, $errfile, $errline)  {
  //suppress all errors
  return true;
}

And you can probably see that if you wanted to handle some types of errors in a custom way and you wanted to suppress others, you would create a function like the first example handler above, but “return true;” for those types of errors that you wanted to suppress.

Class 8 – Making Timestamps User-Friendly

Saturday, April 18th, 2009

When we set our MySQL tables to have a “created” field of the type TIMESTAMP with the CURRENT_TIMESTAMP option selected, this records the exact date and time that each row is created in the table.

The format that MySQL uses to record this data is “YYYY-MM-DD HH:MM:SS”. However, this is not usually the format that you want to use to display the data on the web page. It’s not so easy to read, and definitely is not how most people think of dates.

In order to convert the MySQL TIMESTAMP to a more user-friendly date format, you want to use PHP’s built-in date() function. However, PHP’s date() function only allows you to change the format of dates that are in Unix Timestamp, which is significantly different from MySQL’s TIMESTAMP format.

So, in order to get PHP’s date() function to work with MySQL’s TIMESTAMP, you first have to convert MySQL’s TIMESTAMP format to Unix Timestamp format. To do that, you use PHP’s strtotime() function.

Here’s the code that does this, from my blog example:

<p>posted <?php echo date("F j, Y, g:ia", strtotime($post['created'])) ?></p>

This displays on the page as, for example, “posted November 8, 2008, 12:19pm”. You can use the date() function to format the date in a wide variety of other formats.

The php.net reference page for the date() function has some easy examples somewhere halfway down  the page.

Class 9 – In-Class Assignment

Saturday, April 18th, 2009

Your assignment today is to complete a blog with comments.  This should be based off of your assignments from last week, where you created a blog where users were required to register and login before they could post to the blog.

There will be changes to two pages in your blogs.

index.php

The home page will show all the blog posts, as well as all of the comments associated with each blog post.  There will also be a link to “Add a comment” to any blog post.

Home Page

Home Page

I recommend you study what I wrote about SELECT statements in an earlier post, especially the last bit about joining two tables together.  It would be nice if you could join the users and posts tables together when doing a query for all the blog posts to show on the home page.  This would allow you to get all the data about the post, as well as the data about the user who posted it in one fell swoop.  Something like this:

$myQuery = "SELECT abloombert_posts.*, abloomberg_users.username FROM abloomberg_posts, abloomberg_users WHERE abloomberg_posts.user_id = abloomberg_users.id ORDER BY created DESC";
$result = mysql_query($myQuery); //run query
if ($result) {
  //loop through each post
  while ($row = mysql_fetch_array($result)) {
    //get this post's id, title, body, and username of the user who posted
    $userId = $row['user_id'];
    $username = $row['username'];
    $title = $row['title'];
    $body = $row['body'];
    $created = $row['created'];
    //etc...
  }
}

The link to “Add a comment” has to somehow pass the id of the blog post to which the comment should be associated to the comment.php script.  This can be done by passing that data in the url of the link.  For example

<a href="comment.php?post_id=<?php echo $postId ?>">Add a comment</a>

comment.php

The comment page will have a form that users can fill out to submit a comment.  This page should show the user the title and author of the blog post they are about to comment on.

Comment Page

Comment Page

In other words, this page will have to take the post_id that was passed to it from index.php, and do a read from the posts database table to get the information for the post with that id.

You will probably use code similar to this:

$postId = $_REQUEST['post_id']; //get the post id that was passed from index.php

$myQuery = "SELECT * from posts where id={$postId}";
$result = mysql_query($myQuery);
//... loop through each row of the results and get the data about this post

The form where the user fills in the comment will also need to pass the post_id to the script that processes the comment so it can store the post_id in the comments table.

Assuming you have the blog post “id” field in a variable called $postId, the code for the form will probably look something like this:

<form action="process_comment.php">
  <input type="hidden" name="post_id" value="<?php echo $postId ?>" />
  <label for="comment">Comment:</label>
  <textarea name="comment" id="comment"></textarea>
  <input type="submit" value="Post Comment!" />
</form>

Notice the hidden input that has the value of the post’s “id” field.  This means that when the user clicks the submit button, the form sends two pieces of data to the process_comment.php script: the post_id and the comment the user entered.

process_comment.php

The script that processes the comment the user entered must take the blog post id, the id of the current user, and the comment the user entered, and store this info in a new row in the “comments” table.

To get the necessary data, you will need to retrive it from the $_REQUEST and $_COOKIE variables.  The post_id and comment will be in the $_REQUEST variable, and the user_id will be in the $_COOKIE variable, assuming you stored it in a cookie when the user logged in.

$userId = $_COOKIE['user_id'];
$comment = $_REQUEST['comment'];
$postId = $_REQUEST['post_id'];

So make sure you are storing the user’s id in a cookie when they login, or else this obviously won’t work.

Once you have that info, put together a SQL query that inserts this data into a new row in the “comments” table.

$myQuery = "INSERT INTO abloomberg_comments (user_id, post_id, comment) VALUES ({$userId}, {$postId}, '{$comment}')";
$result = mysql_query($myQuery); //run the query

Then redirect the user back to the home page.

header("Location: index.php");