Saturday, March 22, 2014

Install and Configure MySQL for PHP Applications on IIS 7

Introduction

While Microsoft® SQL Server® 2008 is the recommended database to use when hosting PHP applications on an Internet Information Services 7 (IIS 7) and above Web server, you can also use MySQL as the database. Currently, many popular PHP applications use MySQL Server for data storage. Using MySQL requires hosting providers to include MySQL database support with the hosting packages.
MySQL cannot currently be installed with the Microsoft® Web Platform Installer (Web PI). This article provides guidance for installing MySQL manually.

Install MySQL Server on Windows Server 2008 or Windows Server 2008 R2

It is recommended that you install MySQL on a dedicated server rather than installing MySQL on the same server that is running IIS. The separation of database server and Web server makes overall installation more secure and manageable and avoids resource contentions between the database and Web server processes.
1. Download MySQL Community Server.
a. We recommend downloading Windows® Installer.
2. Start Windows Installer, or extract all the files from the archive, and then start Setup.exe.
3. You can use a Typical Setup or customize the installation to suit your needs.
4. Once the installation wizard is completed, it is recommended that you leave the Configure the MySQL Server now check box selected.

Configure a MySQL Instance

1. Run the MySQL Server Instance Configuration Wizard, and then choose the configurations options that most closely match your environment.
For more information, see the Server Instance Configuration Wizard.
Best practice recommendations are as follows:
a. Click Next in the Instance Configuration Wizard.
b. Select Detailed Configuration, and then click Next.
c. Select a server type that best suits your environment. It is recommended to set up a separate MySQL server; when prompted to select a server type, select Dedicated MySQL Server Machine, and then click Next.
d. Select a database option, and then click Next.
Select either the Multifunctional Database or Transactional Database Only options if you are using the InnoDB storage engine or the high-speed MyISAM storage engine (for example, if the Web applications on your server require multi-statement transactions, advanced isolation levels and row-level locking, foreign key constraints, or atomic, consistent, isolated, and durable [ACID] features). These options provides fully ACID transactional capabilities, but at the cost of more aggressive usage of disk space and memory.
Otherwise, use the Non-Transactional Database Only option, which is optimized for high-performance SELECT operations. It has low overhead, in terms of memory usage and disk utilization, but at the cost of not supporting transactions.
e. Choose the option that sets the number of concurrent connections you need.
Note: Connections require memory; if the number you choose is too big, your server may not have enough memory.
f. You may adjust networking settings to suit your environment or accept defaults, and then click Next.
g. Select the default character set that best suits you, and then click Next.
h. We recommend enabling both Windows options here. Select both check boxes, and then click Next.
i. Type the password you want to use for the root account, and then click Next.
j. Click Execute to apply your settings.
k. Click Finish to close the wizard.
2. For PHP to work with MySQL, it is necessary to perform the following modifications to the Php.ini file:
a. Confirm that the extension_dir points to the folder where all PHP loadable extensions are located, frequently in the Ext folder (for example, extension_dir=”.\ext”).
b. Enable dynamic extension for MySQL by uncommenting the corresponding line for the MySQL extension: extension=php_mysql.dll
c. Save and close the Php.ini file.

Secure MySQL

1. Remove the anonymous database account (if it exists). Open the MySQL command prompt by clicking Start -> All Programs -> MySQL -> MySQL Server 5.1 -> MySQL Command Line Client:
2. Enter the password for the root account.
3. Once logged on to MySQL, use the following sequence of commands:
mysql> use mysql;
Database changed
mysql> DELETE FROM user WHERE user = '';
Query OK, 2 rows affected (0.03 sec)
mysql> FLUSH PRIVILEGES;
Query OK, 0 rows affected (0.05 sec)
4. Next, restrict the root account to log on only from localhost. Open a MySQL command prompt, and use the following sequence of commands:
mysql> use mysql;
Database changed
mysql> DELETE FROM user WHERE user = 'root' AND host = '%';
Query OK, 2 rows affected (0.03 sec)
mysql> FLUSH PRIVILEGES;
Query OK, 0 rows affected (0.05 sec)
5. Change the name of the root user with the following sequence of commands from the command prompt:
mysql> USE mysql;
Database changed
mysql> UPDATE user SET user='johndoe' WHERE user='root';
Query OK, 1 row affected (0.19 sec)
Rows matched: 1 Changed: 1 Warnings: 0
mysql> FLUSH PRIVILEGES;
Query OK, 0 rows affected (0.23 sec)

Provision the User and Database

1. To provision a new user, type the following command from the MySQL command prompt:
mysql>CREATE USER some_username IDENTIFIED BY some_password’;
Query OK, 0 rows affected (0.00 sec)
2. The newly created user does not have any privileges on the MySQL server by default. To create a new database, type the following command:
mysql>CREATE DATABASE IF NOT EXISTS some_database_name;
Query OK, 1 row affected (0.00 sec)
3. To grant access to this database for a particular user, type the following command:
mysql> GRANT ALTER,
-> ALTER ROUTINE,
-> CREATE,
-> CREATE ROUTINE,
-> CREATE TEMPORARY TABLES,
-> CREATE VIEW,
-> DELETE,
-> DROP,
-> EXECUTE,
-> INDEX,
-> INSERT,
-> LOCK TABLES,
-> SELECT,
-> UPDATE,
-> SHOW VIEW
ON some_database_name.* TO 'some_username';

Configure PHP to Access MySQL

1. Open the c:\php\php.ini file with your favorite text editor.
2. Uncomment the following lines by removing the semicolon:
extension=php_mysqli.dll
extension=php_mbstring.dll
extension=php_mcrypt.dll
3. Restart the IIS service by clicking on Start, selecting the Search Field, typing iisreset, and then pressing ENTER.
4. If all went well, you should see the mysqli section on the PHP information page created earlier (http://localhost/phpinfo.php).

Figure 1: The mysqli section on the PHP information page

Best Practices for MySQL

  • Enable TCP/IP Networking
    This is the default. Keep the TCP port that MySQL uses to listen at 3306. If the database will be running on a separate system from the Web server, select the Add firewall exception for this port check box.
  • Include Bin Directory in Windows PATH
    This makes the MySQL utilities available from the command prompt or from Windows PowerShell™.
  • Create an Anonymous Account
    The default is to keep this disabled. Adding anonymous user support may create a security risk for the database; additionally, enabling anonymous users causes the GRANT statements used to set up database to be unreliable.

Create a WordPress blog on Windows Server 2008 R2, IIS 7.5 and MySQL

I think it is fitting that my first ever post on this WordPress Blog would be about setting up a WIMP server (Windows Server 2008 R2, IIS, MySQL & PHP).
Being a former Windows Systems Administrator I wanted to keep as many components running on familiar Microsoft applications (IIS 7.5 & SQL Server 2008 R2) and found this article explaining how to do it. However, at the time of writing this article I found that the WordPress on SQL Server (wp-sqlsrv) distribution was unavailable* so the only option was to use MySQL. In retrospect I am very happy with this outcome as the process of learning about MySQL has been very enjoyable and so far has proven to be a very stable and easy-to-use database application .
* Please note that the WordPress on SQL Server (wp-sqlsrv) distribution is now available.

The Environment

  • Server: Rackspace Cloud VM running Windows Server 2008 R2
  • Web server: IIS 7.5
  • Database application: MySQL
This blog you are reading is running off the environment above. So far I have found it to be an excellent blogging platform.

Install IIS 7.5

Logically, the first step is to install the web server application, IIS 7.5. From this point onwards I will simply refer to it as IIS.  To do so, perform the folowing steps:
1. Click Start > Run then enter servermanager.msc in the Open dialogue box then click OK  to load Server Manager:
C:\>servermanager.msc
2. Once Server Manager has loaded, right-click on Roles and click Add Roles, which initiates the Add Roles Wizard:
3. Click Next in the Before You Begin section:

4. Select Web Server (IIS) on the Select Server Role section and click Next:
20120416220536
5. Select the IIS services to be installed on the Select Role Services page. Keep the defaults but also select the CGI check box under Application Development. This enables both the CGI and FastCGI services which is required to use PHP:

6. Click Next and on the Confirmation page click Install.
7. Once the installation has completed, click Start > Run and then enter inetmgr in the dialogue box then click OK to load Internet Information Services (IIS) Manager. This will fire up IIS Manager and you will see IIS running and configured according to the options you selected earlier:

For more information, this article shows how to install IIS 7.5 with default settings and this article shows how add the CGI feature as described above.

Configure IIS 7.5

We now need to configure IIS in preparation for WordPress:
8. Click Start > Run and enter CMD in the dialogue box and then click OK.
9. At the command prompt enter the following and then hit enter on the keyboard:
md C:\Websites\Wordpress
This creates the directory where the new WordPress site will be located.
10. Open IIS Manager and click on Sites.
11. Right-click on Sites and then click Add Web Site:

In the Add Web Site dialogue box enter these details:
  • Name: WordPress
  • Physical path: C:\Websites\Wordpress
  • Bindings: All Unassigned. If your server has multiple IP addresses and you want the site to listen on a specific IP address select it from the drop-down box.
  • Host name: www.yourdomain.name. This should contain the fully-qualified domain name for your blog site.

Once all the sections have been completed click OK. You will now see the WordPress site under the Sites folder.
12. Click on Application Pools and in the middle pane you will see an application pool named WordPress. Right-click on it and select Advanced Settings:

13. Find the setting Enable 32-Bit Applications and click the drop-down box and click True. Click OK to save the settings:
20120417065550
We will leverage the improved security in IIS 7.5 by utilising ApplicationPoolIdentity. More information about this can be found here.
14. Select the WordPress site in the Connections pane and then double-click Authentication:

15. Select Anonymous Authentication and in the Actions pane on the right side click Edit:

16. Then select Application Pool Identity and click OK:

17. Click Start > Run and then enter CMD in the Open dialogue box then click OK  to load a command prompt enter the following and hit enter:
icacls "C:\Websites\Wordpress" /grant "IIS APPPOOL\Wordpress":(OI)(CI)(RX,W)
This configures the WordPress application pool to have write permissions to the directory where the new WordPress site is located.

IIS is now configured and ready for PHP to be installed!

Install PHP 5.3.10 for Windows

WordPress uses PHP therefore it is the next component to be installed. We require a ‘Non Thread Safe’ version and facilitate the installation we will use the latest version that comes with an ‘Installer’. At the time of writing, version 5.3.10, has an Installer. To proceed, perform the following:
18. Go to http://windows.php.net/download/.  Find version 5.3.10, under VC9 x86 Non Thread Safe, click the Installer version to download it. Click here for a direct download.
19. Once downloaded, run the .msi setup file, click Next at the first screen and accept the EULA (End User License Agreement)  and then click Next again.
20. Keep the default installation directory, which is C:\Program Files (x86)\PHP:

21. At the Web Server Setup step select IIS FastCGI:

22. Install the following features also; Script Executable, Register *.php files to open automatically and PEAR Install:

23. Click Next then Install and then click on Finish to complete the setup:

Install PHP Manager 1.2
PHP Manager is a plugin for IIS that allows you to manage and configure PHP settings and installations.
24. Go to http://phpmanager.codeplex.com/ and click on ‘View all downloads’ and download and install the x64 version.
25. Open IIS Manager and in the Connections pane select the server name. In the middle pane you will see all installed features within IIS. Select and open PHP Manager:

26. Under the PHP Setup section select View Recommendations:

27. Select all of the recommendations and hit the OK button:

Install MySQL

At the time of writing, MySQL 5.5.21, is the most recent version available.
28. Go to http://dev.mysql.com/downloads/mysql/ and download the 64-bit MSI Installer and run the setup (mysql-5.5.21-winx64.msi)
29. Accept the EULA and click Next.
30. In the Choose Setup Type section select Typical and click Next:

31. In the Ready To Install MySQL 5.5 section click Install:

32. When the installation completes ensure Launch the MySQL Instance Configuration Wizard is ticked and then click Finish:

33. Select Standard Configuration as the configuration type and then Next:

34. Select Server Machine as the server type and then click Next:

35. In the Windows Options section ensure the settings match the image below:

36. In the security options section check Modify Security Settings, enter the root password of your choice and then click Next:

37. In the configuration section shown below click Execute:

38. Once the process completes click Finish:

Configure MySQL for WordPress

We will now create the database for WordPress within MySQL. We will do this via the command line client.
39. Click Start > All Programs > MySQL > MySQL Server 5.5 > MySQL 5.5 Command Line Client to open a MySQL command prompt:
40. Enter the root password you chose earlier in the MySQL setup and hit enter:

41. To create the WordPressDB database type the following and hit enter:
CREATE DATABASE WordPressDB;
You will receive a confirmation that the command was successful:
Query OK, 1 row affected (0.00 sec)
41. To create the wp_user and grant it access and requisite permissions to the WordPressDB database type the following and hit enter:
GRANT ALL PRIVILEGES ON WordPressDB.* TO "wp_user"@"localhost" IDENTIFIED BY "password";

Please note that the “;” signals the end of the command. To go to a second line just hit Enter without a “;” at the end of a line.
42. Type Exit and hit enter to exit the MySQL command line client.
The confirugration of MySQL is now complete. We should now have the following information available for the WordPress install:
  • Database Name: WordPressDB
  • Database User: wp_user
  • DB User Password: password

Install WordPress

Go to http://wordpress.org/download/ and download the latest version of WordPress (currently 3.3.1) and then folllow these steps:
43. Extract the WordPress files to the location of the WordPress site we created earlier in IIS - C:\Websites\Wordpress.
44. Navigate to C:\Websites\Wordpress and find the file named wp-config-sample.php and open it with Notepad, as per below:

45. Ammend the following fields in wp-config-sample.php with the MySQL database info we created earlier :
  • DB_NAME: WordPressDB
  • DB_USER: wp_user
  • DB_PASSWORD: password
The screen shot below shows the variables that need to be changed. This is telling WordPress which database (WordPressDB) to store the configuration data in MySQL and also the connection information (wp_user and password) to be used:

46. Save the file as wp-config.php
47. Type in the following into your browser to start the WordPress installation script:
http://www.yourdomain.com/wp-admin/install.php
Be sure to replace www.yourdomain.com with your domain.
48. You will now see the WordPress welcome screen:

You need to configure the following fields with your own personal information:
  • Site Title: My First WordPress Blog
  • Username: choose your username (default is admin)
  • Password: choose your password
  • Your E-mail: email@yourdomain.com
49. Click the Install WordPress button and the setup script will run and you should see the following page soon after:
20120417114254
50. Click Login to go to the Admin Login page then enter your WordPress username and password you created earlier and start blogging!

jQuery - getting custom attribute from selected option

Given the following:

<select id="location">
    <option value="a" myTag="123">My option</option>
    <option value="b" myTag="456">My other option</option>
</select>

<input type="hidden" id="setMyTag" />

<script>
    $(function() {
        $("#location").change(function(){
            var element = $(this);
            var myTag = element.attr("myTag");

            $('#setMyTag').val(myTag);
        });
    });
</script>
That does not work...
What do I need to do to get the value of the hidden field updated to the value of myTag when the select is changed. I'm assuming I need to do something about getting the currently selected value...?

Friday, March 21, 2014

How to get querystring value using jQuery

In this post, I will show you how to get the QueryString variable value using jQuery. I have created a function which returns value of any querystring variable.

Earlier I had posted about Get Page Title and URL using jQuery, Get previous page URL using jQuery, Check for '#' hash in URL using jQuery, Style Hyperlinks based on URL extension and Use protocol less URL for referencing jQuery.

01function GetQueryStringParams(sParam)
02{
03    var sPageURL = window.location.search.substring(1);
04    var sURLVariables = sPageURL.split('&');
05    for (var i = 0; i < sURLVariables.length; i++)
06    {
07        var sParameterName = sURLVariables[i].split('=');
08        if (sParameterName[0] == sParam)
09        {
10            return sParameterName[1];
11        }
12    }
13}​

Thursday, March 20, 2014

How to empty an array in JavaScript?

Is there a way to empty an array and if so possibly with .remove()?

For instance,

A = [1,2,3,4];

How can I empty that?

Monday, March 17, 2014

jQuery Install

Adding jQuery to Your Web Pages

There are several ways to start using jQuery on your web site. You can:
  • Download the jQuery library from jQuery.com
  • Include jQuery from a CDN, like Google

Downloading jQuery

There are two versions of jQuery available for downloading:
  • Production version - this is for your live website because it has been minified and compressed
  • Development version - this is for testing and development (uncompressed and readable code)
Both versions can be downloaded from jQuery.com.
The jQuery library is a single JavaScript file, and you reference it with the HTML <script> tag (notice that the <script> tag should be inside the <head> section):
<head>
<script src="jquery-1.10.2.min.js"></script>
</head>
Tip: Place the downloaded file in the same directory as the pages where you wish to use it.

Note Do you wonder why we do not have type="text/javascript" inside the <script> tag?

This is not required in HTML5. JavaScript is the default scripting language in HTML5 and in all modern browsers!


Alternatives to Downloading

If you don't want to download and host jQuery yourself, you can include it from a CDN (Content Delivery Network).
Both Google and Microsoft host jQuery.
To use jQuery from Google or Microsoft, use one of the following:

Google CDN:

<head>
<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.10.2/jquery.min.js">
</script>
</head>



Note Get the latest available version with Google CDN:

If you look at the Google URL above - the version of jQuery is specified in the URL (1.10.2). If you would like to use the latest version of jQuery, you can either remove a number from the end of the version string (for example 1.10), then Google will return the latest version available in the 1.10 series (1.10.0, 1.10.1, etc.), or you can take it up to the whole number (1), and Google will return the latest version available in the 1 series (from 1.1.0 to 1.10.2).

Microsoft CDN:

<head>
<script src="http://ajax.aspnetcdn.com/ajax/jQuery/jquery-1.10.2.min.js">
</script>
</head>



Note One big advantage of using the hosted jQuery from Google or Microsoft:

Many users already have downloaded jQuery from Google or Microsoft when visiting another site. As a result, it will be loaded from cache when they visit your site, which leads to faster loading time. Also, most CDN's will make sure that once a user requests a file from it, it will be served from the server closest to them, which also leads to faster loading time.

jQuery Selectors

Use our jQuery Selector Tester to demonstrate the different selectors.
Selector Example Selects
* $("*") All elements
#id $("#lastname") The element with id="lastname"
.class $(".intro") All elements with class="intro"
.class,.class $(".intro,.demo") All elements with the class "intro" or "demo"
element $("p") All <p> elements
el1,el2,el3 $("h1,div,p") All <h1>, <div> and <p> elements
:first $("p:first") The first <p> element
:last $("p:last") The last <p> element
:even $("tr:even") All even <tr> elements
:odd $("tr:odd") All odd <tr> elements
:first-child $("p:first-child") All <p> elements that are the first child of their parent
:first-of-type $("p:first-of-type") All <p> elements that are the first <p> element of their parent
:last-child $("p:last-child") All <p> elements that are the last child of their parent
:last-of-type $("p:last-of-type") All <p> elements that are the last <p> element of their parent
:nth-child(n) $("p:nth-child(2)") All <p> elements that are the 2nd child of their parent
:nth-last-child(n) $("p:nth-last-child(2)") All <p> elements that are the 2nd child of their parent, counting from the last child
:nth-of-type(n) $("p:nth-of-type(2)") All <p> elements that are the 2nd <p> element of their parent
:nth-last-of-type(n) $("p:nth-last-of-type(2)") All <p> elements that are the 2nd <p> element of their parent, counting from the last child
:only-child $("p:only-child") All <p> elements that are the only child of their parent
:only-of-type $("p:only-of-type") All <p> elements that are the only child, of its type, of their parent
parent > child $("div > p") All <p> elements that are a direct child of a <div> element
parent descendant $("div p") All <p> elements that are descendants of a <div> element
element + next $("div + p") The <p> element that are next to each <div> elements
element ~ siblings $("div ~ p") All <p> elements that are siblings of a <div> element
:eq(index) $("ul li:eq(3)") The fourth element in a list (index starts at 0)
:gt(no) $("ul li:gt(3)") List elements with an index greater than 3
:lt(no) $("ul li:lt(3)") List elements with an index less than 3
:not(selector) $("input:not(:empty)") All input elements that are not empty
:header $(":header") All header elements <h1>, <h2> ...
:animated $(":animated") All animated elements
:focus $(":focus") The element that currently has focus
:contains(text) $(":contains('Hello')") All elements which contains the text "Hello"
:has(selector) $("div:has(p)") All <div> elements that have a <p> element
:empty $(":empty") All elements that are empty
:parent $(":parent") All elements that are a parent of another element
:hidden $("p:hidden") All hidden <p> elements
:visible $("table:visible") All visible tables
:root $(":root") The document's root element
:lang(language) $("p:lang(de)") All <p> elements with a lang attribute value starting with "de"
[attribute] $("[href]") All elements with a href attribute
[attribute=value] $("[href='default.htm']") All elements with a href attribute value equal to "default.htm"
[attribute!=value] $("[href!='default.htm']") All elements with a href attribute value not equal to "default.htm"
[attribute$=value] $("[href$='.jpg']") All elements with a href attribute value ending with ".jpg"
[attribute|=value] $("[title|='Tomorrow']") All elements with a title attribute value equal to 'Tomorrow', or starting with 'Tomorrow' followed by a hyphen
[attribute^=value] $("[title^='Tom']") All elements with a title attribute value starting with "Tom"
[attribute~=value] $("[title~='hello']") All elements with a title attribute value containing the specific word "hello"
[attribute*=value] $("[title*='hello']") All elements with a title attribute value containing the word "hello"
:input $(":input") All input elements
:text $(":text") All input elements with type="text"
:password $(":password") All input elements with type="password"
:radio $(":radio") All input elements with type="radio"
:checkbox $(":checkbox") All input elements with type="checkbox"
:submit $(":submit") All input elements with type="submit"
:reset $(":reset") All input elements with type="reset"
:button $(":button") All input elements with type="button"
:image $(":image") All input elements with type="image"
:file $(":file") All input elements with type="file"
:enabled $(":enabled") All enabled input elements
:disabled $(":disabled") All disabled input elements
:selected $(":selected") All selected input elements
:checked $(":checked") All checked input elements

starting with HTML + CSS

This short tutorial is meant for people who want to start using CSS and have never written a CSS style sheet before.
It does not explain much of CSS. It just explains how to create an HTML file, a CSS file and how to make them work together. After that, you can read any of a number of other tutorials to add more features to the HTML and CSS files. Or you can switch to using a dedicated HTML or CSS editor, that helps you set up complex sites.
At the end of the tutorial, you will have made an HTML file that looks like this:

The resulting HTML page, with colors and layout, all done with CSS.
Note that I don't claim that this is beautiful ☺
Alert! Advanced: Sections that look like this are optional. They contain some extra explanation of the HTML and CSS codes in the example. The “alert!” sign at the start indicates that this is more advanced material than the rest of the text.

Step 1: writing the HTML

For this tutorial, I suggest you use only the very simplest of tools. E.g., Notepad (under Windows), TextEdit (on the Mac) or KEdit (under KDE) will do fine. Once you understand the principles, you may want to switch to more advanced tools, or even to commercial programs, such as Style Master, Dreamweaver or GoLive. But for your very first CSS style sheet, it is good not to be distracted by too many advanced features.
Don't use a wordprocessor, such as Microsoft Word or OpenOffice. They typically make files that a Web browser cannot read. For HTML and CSS, we want simple, plain text files.
Step 1 is to open your text editor (Notepad, TextEdit, KEdit, or whatever is your favorite), start with an empty window and type the following:
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01//EN">
<html>
<head>
  <title>My first styled page</title>
</head>

<body>

<!-- Site navigation menu -->
<ul class="navbar">
  <li><a href="index.html">Home page</a>
  <li><a href="musings.html">Musings</a>
  <li><a href="town.html">My town</a>
  <li><a href="links.html">Links</a>
</ul>

<!-- Main content -->
<h1>My first styled page</h1>

<p>Welcome to my styled page!

<p>It lacks images, but at least it has style.
And it has links, even if they don't go
anywhere&hellip;

<p>There should be more here, but I don't know
what yet.

<!-- Sign and date the page, it's only polite! -->
<address>Made 5 April 2004<br>
  by myself.</address>

</body>
</html>
In fact, you don't have to type it: you can copy and paste it from this Web page into the editor.
(If you are using TextEdit on the Mac, don't forget to tell TextEdit that the text is really plain text, by going to the Format menu and selecting “Make plain text”.)
Alert! Advanced: The first line of the HTML file above tells the browser which type of HTML this is (DOCTYPE means DOCument TYPE). In this case, it is HTML version 4.01.
Words within < and > are called tags and, as you can see, the document is contained within the <html> and </html> tags. Between <head> and </head> there is room for various kinds of information that is not shown on screen. So far it contains the title of the document, but later we will add the CSS style sheet there, too.
The <body> is where the actual text of the document goes. In principle, everything in there will be displayed, except for the the text inside <!-- and -->, which serves as a comment to ourselves. The browser will ignore it.
Of the tags in the example, <ul> introduces an “Unordered List”, i.e., a list in which the items are not numbered. The <li> is the start of a “List Item.” The <p> is a “Paragraph.” And the <a> is an “Anchor,” which is what creates a hyperlink.
the HTML source shown inside KEdit
The KEdit editor showing the HTML source.
Alert! Advanced: If you want to know what the names in <…> mean, one good place to start is Getting started with HTML. But just a few words about the structure of our example HTML page.
  • The “ul” is a list with one hyperlink per item. This will serve as our “site navigation menu,” linking to the other pages of our (hypothetical) Web site. Presumably, all pages on our site have a similar menu.
  • The “h1” and “p” elements form the unique content of this page, while the signature at the bottom (“address”) will again be similar on all pages of the site.
Note that I didn't close the “li” and “p” elements. In HTML (but not in XHTML), it is allowed to omit the </li> and </p> tags, which I did here, to make the text a little easier to read. But you may add them, if you prefer.
Let's assume that this is going to be one page of a Web site with several similar pages. As is common for current Web pages, this one has a menu that links to other pages on the hypothetical site, some unique content and a signature.
Now select “Save As…” from the File menu, navigate to a directory/folder where you want to put it (the Desktop is fine) and save the file as “mypage.html”. Don't close the editor yet, we will need it again.
(If you are using TextEdit on Mac OS X before version 10.4, you will see an option Don't append the .txt extension in the Save as dialog. Select that option, because the name “mypage.html” already includes an extension. Newer versions of TextEdit will notice the .html extension automatically.)
Next, open the file in a browser. You can do that as follows: find the file with your file manager (Windows Explorer, Finder or Konqueror) and click or double click the “mypage.html” file. It should open in your default Web browser. (If it does not, open your browser and drag the file to it.)
As you can see, the page looks rather boring…

Step 2: adding some colors

You probably see some black text on a white background, but it depends on how the browser is configured. So one easy thing we can do to make the page more stylish is to add some colors. (Leave the browser open, we will use it again later.)
We will start with a style sheet embedded inside the HTML file. Later, we will put the HTML and the CSS in separate files. Separate files is good, since it makes it easier to use the same style sheet for multiple HTML files: you only have to write the style sheet once. But for this step, we just keep everything in one file.
We need to add a <style> element to the HTML file. The style sheet will be inside that element. So go back to the editor window and add the following five lines in the head part of the HTML file. The lines to add are shown in red.
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01//EN">
<html>
<head>
  <title>My first styled page</title>
  <style type="text/css">
  body {
    color: purple;
    background-color: #d8da3d }
  </style>
</head>

<body>
[etc.]
The first line says that this is a style sheet and that it is written in CSS (“text/css”). The second line says that we add style to the “body” element. The third line sets the color of the text to purple and the next line sets the background to a sort of greenish yellow.
Alert! Advanced: Style sheets in CSS are made up of rules. Each rule has three parts:
  1. the selector (in the example: “body”), which tells the browser which part of the document is affected by the rule;
  2. the property (in the example, 'color' and 'background-color' are both properties), which specifies what aspect of the layout is being set;
  3. and the value ('purple' and '#d8da3d'), which gives the value for the style property.
The example shows that rules can be combined. We have set two properties, so we could have made two separate rules:
body { color: purple }
body { background-color: #d8da3d }
but since both rules affect the body, we only wrote “body” once and put the properties and values together. For more about selectors, see chapter 2 of Lie & Bos.
The background of the body element will also be the background of the whole document. We haven't given any of the other elements (p, li, address…) any explicit background, so by default they will have none (or: will be transparent). The 'color' property sets the color of the text for the body element, but all other elements inside the body inherit that color, unless explicitly overridden. (We will add some other colors later.)
Now save this file (use “Save” from the File menu) and go back to the browser window. If you press the “Reload” button, the display should change from the “boring” page to a colored (but still rather boring) page. Apart from the list of links at the top, the text should now be purple against a greenish yellow background.
Screenshot of the colored page in Konqueror
How one browser shows the page now that some colors have been added.
Alert! Advanced: Colors can be specified in CSS in several ways. This example shows two of them: by name (“purple”) and by hexadecimal code (“#d8da3d”). There are about 140 color names and the hexadecimal codes allow for over 16 million colors. Adding a touch of style explains more about these codes.

Step 3: adding fonts

Another thing that is easy to do is to make some distinction in the fonts for the various elements of the page. So let's set the text in the “Georgia” font, except for the h1 heading, which we'll give “Helvetica.”
On the Web, you can never be sure what fonts your readers have on their computers, so we add some alternatives as well: if Georgia is not available, Times New Roman or Times are also fine, and if all else fails, the browser may use any other font with serifs. If Helvetica is absent, Geneva, Arial and SunSans-Regular are quite similar in shape, and if none of these work, the browser can choose any other font that is serif-less.
In the text editor add the following lines:
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01//EN">
<html>
<head>
  <title>My first styled page</title>
  <style type="text/css">
  body {
    font-family: Georgia, "Times New Roman",
          Times, serif;
    color: purple;
    background-color: #d8da3d }
  h1 {
    font-family: Helvetica, Geneva, Arial,
          SunSans-Regular, sans-serif }
  </style>
</head>

<body>
[etc.]
If you save the file again and press “Reload” in the browser, there should now be different fonts for the heading and the other text.
Screenshot with fonts added
Now the main text has a different font from the heading.

Step 6: adding a horizontal line

The final addition to the style sheet is a horizontal rule to separate the text from the signature at the bottom. We will use 'border-top' to add a dotted line above the <address> element:
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01//EN">
<html>
<head>
  <title>My first styled page</title>
  <style type="text/css">
  body {
    padding-left: 11em;
    font-family: Georgia, "Times New Roman",
          Times, serif;
    color: purple;
    background-color: #d8da3d }
  ul.navbar {
    list-style-type: none;
    padding: 0;
    margin: 0;
    position: absolute;
    top: 2em;
    left: 1em;
    width: 9em }
  h1 {
    font-family: Helvetica, Geneva, Arial,
          SunSans-Regular, sans-serif }
  ul.navbar li {
    background: white;
    margin: 0.5em 0;
    padding: 0.3em;
    border-right: 1em solid black }
  ul.navbar a {
    text-decoration: none }
  a:link {
    color: blue }
  a:visited {
    color: purple }
  address {
    margin-top: 1em;
    padding-top: 1em;
    border-top: thin dotted }
  </style>
</head>

<body>
[etc.]
Now our style is complete. Next, let's look at how we can put the style sheet in a separate file, so that other pages can share the same style.

Step 7: putting the style sheet in a separate file

We now have an HTML file with an embedded style sheet. But if our site grows we probably want many pages to share the same style. There is a better method than copying the style sheet into every page: if we put the style sheet in a separate file, all pages can point to it.
To make a style sheet file, we need to create another empty text file. You can choose “New” from the File menu in the editor, to create an empty window. (If you are using TextEdit, don't forget to make it plain text again, using the Format menu.)
Then cut and paste everything that is inside the <style> element from the HTML file into the new window. Don't copy the <style> and </style> themselves. They belong to HTML, not to CSS. In the new editor window, you should now have the complete style sheet:
body {
  padding-left: 11em;
  font-family: Georgia, "Times New Roman",
        Times, serif;
  color: purple;
  background-color: #d8da3d }
ul.navbar {
  list-style-type: none;
  padding: 0;
  margin: 0;
  position: absolute;
  top: 2em;
  left: 1em;
  width: 9em }
h1 {
  font-family: Helvetica, Geneva, Arial,
        SunSans-Regular, sans-serif }
ul.navbar li {
  background: white;
  margin: 0.5em 0;
  padding: 0.3em;
  border-right: 1em solid black }
ul.navbar a {
  text-decoration: none }
a:link {
  color: blue }
a:visited {
  color: purple }
address {
  margin-top: 1em;
  padding-top: 1em;
  border-top: thin dotted }
Choose “Save As…” from the File menu, make sure that you are in the same directory/folder as the mypage.html file, and save the style sheet as “mystyle.css”.
Now go back to the window with the HTML code. Remove everything from the <style> tag up to and including the </style> tag and replace it with a <link> element, as follows:
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01//EN">
<html>
<head>
  <title>My first styled page</title>
  <link rel="stylesheet" href="mystyle.css">
</head>

<body>
[etc.]
This will tell the browser that the style sheet is found in the file called “mystyle.css” and since no directory is mentioned, the browser will look in the same directory where it found the HTML file.
If you save the HTML file and reload it in the browser, you should see no change: the page is still styled the same way, but now the style comes from an external file.
Final result of styling
The final result
The next step is to put both files, mypage.html and mystyle.css on your Web site. (Well, you might want to change them a bit first…) But how to do that depends on your Internet provider.