### Setting up our database tables

Once you have a database set up, you can add tables to it, via PhpMyAdmin. Just go into your database and run the following SQL.

This creates the table structure required for storing articles and users. We store things like the plain text and HTML, creation date, etc. for articles, and users consist simply of a username, password and email. Take a look at the created table for more information.

### Redirecting all requests to the main index file

Now we're all set: when you load the website everything is prepended, defined, included, connected and so on, but before we move on, I want to add some .htaccess magic to make sure that no matter what URL is entered, index.php is loaded.

The reason for this is because I plan on each article having a URL like this: http://bonsaiwriter.com/8h3ef/ Since I don't want to create directories and index files for all the billions of possibilities I'll just forward all requests to one file and deal with them there. The result of this is that, if you go to http://bonsaiwriter.com/i2e23e/23e23/e23e2/23e23/, you will not get an error page, the contents of index.php will be shown. We will obviously need to remedy this for cases where a page clearly doesn't exist, but more on that in a bit!

To make sure that all your requests are handled by one file, open your .htaccess file and paste in the following lines under the existing prepend rule.

This is where things may be a bit different depending on your setup. If you are using a virtual host, a dedicated domain or a sub-domain, this should work. If you are using a sub directory, you will need to modify the last line, like so:

Once this has been put into place, you should be able to type anything into the URL bar after your base domain and it all should still be well - you should see index.php being loaded.

## Showing the Right Views

Our index.php file will be our "routing" file. It will determine what you want to see and show it to you. It will know that http://bonsaiwriter.com/about/ exists but http://bonsaieriter.com/aboutus/ does not. It will know that there is an article at http://bonsaiwriter.com/334Dr/ and it will show you the app with the article, however it will detect that there is no article at http://bonsaiwriter.com/wr4rD/, so it will display an error page.

Let's look at the pages we will have first, and then determine how to direct users there. Here's a quick breakdown:

• Landing page (http://bonsaiwriter.com)
• Contact, about and legal pages (http://bonsaiwriter.com/contact/)
• Create a new article (http://bonsaiwriter.com/new/)
• Article pages (http://bonsaiwriter.com/r4J2w/)

Now all we have to do is write rules for these cases and make sure that users are sent to the correct places. Let's start by capturing the page we are on, and stripping out the parts of the URL we don't need.

The above code should be placed at the top of the index.php file, and will return the portion of the URL we need. If you go to http://bonsaiwriter.com/about/ it will return "about;" if you go to http://bonsaiwriter.com/this/is/a/page/, it will return "this/is/a/page".

The method above will also need to be modified a bit if you are using subdirectories, but this can easily be done by stripping it out from the URL using the str_replace() function or something similar.

If the $page variable is empty, we are on the main page. If its value is "new," we want to create a new article. If it is contact, about or legal we want to show the respective pages. In all other cases, we will check if an article exists at the given URL. If it does, then we show the article. If it doesn't, we have a 404 error so an error is shown. Let's look at the code which does all this. Firstly, we check if the $page variable is empty. If it is, we include the index.php from our site folder, since we want to show the front page.

If the $page variable is "new," we want to create a new article. To accomplish this, we generate a unique article identifier, henceforth called a uri. We then insert a new article into the database with that uri and redirect the user to the article's page. We will discuss these specific functions further down. The next section deals with our predefined pages. I added a simple array to config.php, which contains the pages that we want to have: If the current page is amongst these, and the file to present the page exists (site/pagename.php), we include that file, otherwise we move on to the next condition. If the code gets to this next block, we have determined the following: • We are not showing the main page • We do not want to create a new article • We are not showing any predefined page All that is left is either an article page, or we have an error. In this block, we check if we have an article that has a uri which is the same as the data contained in our $page variable. We use a separate function for that which returns true if an article does exist, and false if it doesn't (more on this soon). If the article does exist, we include the index.php file from the app folder.

If none of the above conditions have been met, all we are left with is that this must be an error page so we display the 404.php file.

With that complete, we have accounted for all the possibilities that can happen while viewing our little web app. We've defined the set of pages that can be viewed and have said that all other pages are error pages.

## Functions for our App

Let's continue by defining and writing some of the functions that our application will need. I started out with the following six functions - three of which we've used already:

• article_exists - When passed a uri as an argument this function will tell us if it exists
• generate_article_uri - Generates a random and unique 5 character string to identify an article
• insert_article - Add an article to the database
• get_article - Retrieves a single article from the database based on its uri
• save_article - Saves the details of an article
• !convert_plain_to_html - Method for converting raw text to HTML

### Checking for an existing article

The function is extremely simple. We pass it a uri, and determine the database to make sure an article with that uri does not exist.

We create a result set which consists of all the articles with the given uri. If the number of rows returned is 0, we are fine, the article does not exist. Otherwise, at least one article has been found, so we need to return true - the article exists.

### Generating a unique uri

Generating a unique uri is an integral part of the application. Whenever someone creates a new article, it needs to have a unique identifier, but we don't want extremely long urls either and we don't want to take tons of time finding a unique one. Here is how Bonsai Writer does it.

First, we define all the characters we will allow. I have allowed all upper and lower case characters and all the numbers. This will give us 42 to the power of 42 number of variations - we should be safe for a while.

I have given all the allowed characters in the form of a string, and then I split it up into an array using the str_split() function. I then created a which will run five times, choosing a random member of the allowed characters array (by shuffling it on each pass and selecting the first value), adding it to our array of chosen characters. I then implode this chosen array to arrive at the final string.

As you can see, all this is in a do-while loop. This works just like a regular while loop, except that the loop is executed at least once, no matter what. In regular while loops the condition is examined first and, if it is true, the loop is run once followed by the condition being examined again. In do-while loops, the loop is run once, only then is the condition examined.

This way we can create a uri, and then check it against the database using the article_exists() function. As long as that function returns true (which means we have randomly generated a uri which exists) the loop will run again, generating another uri and checking it.

It might seem surprising, but this method is less than great if you have a huge volume website. 49 to the power of 49 is a lot, but let's look at how this could be a problem with a smaller set. Suppose you want to assign people 4 digit unique pin codes. This gives you 10,000 variations. Your site is visited by 20 people a day so 10,000 is fine for a while.

In a year's time, about 7,300 pin codes will be taken so you still have ages to implement a new system. However, since 73% of the pin codes are taken, your random number generator will spit out a taken pin code 73% of the time (essentially 2 out of 3 times). If I went to your website, it may take the system several tries before it finds a unique pin. This equates to extra database queries.

Choosing a right scheme here is important and I think with 49 characters available for 5 spots (that gives you 6 with 83 zeros after it options), we really are safe for a while.

### Inserting an article

Initially, when someone creates an article, it has no data - just a uri - so inserting it is rather easy:

I do want to mention an important note about the uri here. Since we specifically allowed upper and lower case letters "abcde" should not be the same as "Abcde". While this is obvious on the PHP level, we need to make sure that the uri field in the database has a case sensitive collation. In my case, all data receives "latin1_swedish_ci" as its default collation which is case insensitive - indicated by the "ci" at the end. For the uri field, I chose "latin_general_cs" to make sure we can check for uris properly.

### Getting a single article

When retrieving an article, we simply want to have all its details available to work with so all we need to do is query its row from the database.

Passing this function a uri is optional. The reason for this is that on single article pages, we usually have a uri available in the url anyway. So if the uri is not given, we just parse it from the url.

The body of the text is everything except the title; so we use substr() again to put the body text into the $body variable. For now, the value of our $html variable is set to be the same as the value of the $body variable. I have created a separate function which will take care of this but for now it just returns the plain text back. We will change this in a second, we just want to make sure this all works. If you type at least 30 characters into your texture and reload the page, the saved text should be pulled into the textarea from the database. ### Converting the data Now its time to modify the value of the $html variable to get the actual HTML. When planning out how this should work, I laid down three guidelines for myself.

• The basis of converting the text into HTML will be the new line character. I will split the whole text into chunks separated by new lines.
• I will convert these chunks to whatever is needed (a list element, a pre code block, etc.), everything else will be converted to a paragraph.
• These chunks can contain additional markup for inline elements like links, code elements, bold text, etc.

With that in mind, let's give this a go. First, let's separate our text by the new lines, and make each chunk created a paragraph.

Initially, we use explode to split our text into an array. Each line will be in a separate member in the array. Now let's go through each member of the array and add some paragraph tags. If the line is empty, we unset that member since we don't want to have empty paragraph tags messing up the flow of our document. Otherwise we add a paragraph tag before and after the text.

Notice that I have added newlines before and after the text and after the closing paragraph tag. This is to ensure that the source code looks nice. Instead of having paragraphs one after another in the code, they will be a bit more manageable. Later on I will add tabs as well to make this all indented. This is not essential for our app to work but in many cases authors will have to paste the source code into the WordPress backend for example, so having it nicely presented is a great bonus.

### A better system

The login system is also somewhat rudimentary and not unhackably safe. I would prefer to use more secure \$_COOKIES or some newer methods available, but this was good as a quick placeholder to test functionality. There is no indication here of any standardization to accommodate for additional login methods such as oAuth or integration with services such as Twitter and Facebook.

## Wrapping up the Website

There were a number of other techniques utilized in this app that I haven't covered here but you should be able to find all of them by looking into the files provided. For example, the CSS font-face property is used to embed three fonts to make the website look nice, CSS is used to create the round icons at the top bar in the app and so on.

Colorbox, an excellent jQuery plugin is used to create the modal windows, which appear when you click on the icons, and Elastic is used to make our textarea grow dynamically as we type into it.

A wonderful .htaccess ruleset is in the htaccess file which I retrieved from Perishable Press. This will help keep evil hackers out of your site.

A great number of features can be added as well. This is just the initial incarnation - a test version if you will - of this application. It will support custom CSS embedding, the definition of custom rules and many handy functions to help authors and editors do their job. My goal is to have an instant preview of an article in its native environment (whichever online website I am writing for).

## Final Thoughts

While this is in no way an extensive article on how to create a web service or a website, I hope it has provided some insight on the workflow and the logic behind building something for the web. Remember, you don't have to get things right in the first round. You just need to be able to make it better and better!

The block level replacement handling is needs refactoring, but not to worry, I will get in there and overhaul it in the next few weeks to make it leaner and the app will be that much better. This iteration of the app will enable me to test the functionality, find the flaws, gauge the requirements of users and make it better bit by bit. The underlying logic of how I do things will not really change, however I will probably add more planning to the next release.

In this tutorial we've learned how to put a rudimentary website together which is a skill all in itself. I see a lot of people who know PHP, HTML, CSS, Javascript; the only thing they are missing is the ability to put it all together on their own. Keep in mind that this is only one way of doing things. In many cases, it is better to go with popular frameworks and pre built templates, but it is always nice to know how to do it yourself.

Advertisement
Advertisement
Looking for something to help kick start your next project?
Envato Market has a range of items for sale to help get you started.