PHP


25
May 11

Quick web application development with fuelphp tutorial

Project description

I have been assigned the task of building a data collection tool which will be used on a website which has been built to target certain keyword terms- you can view the website and the finished product at Debt Solutions Ireland

Website description

Debt problems can lead to many sleepless nights and a very stressful living. There are many services out there that can help consolidate debts and reduce payments.

The problem

We need a tool that we can use to collect leads (user information)

What you need

Let’s get started

1 . First step is to visit http://fuelphp.com/

2. Download and unzip – I used winrar to unzip into a new folder in my xampplite htdocs folder- lets call it debt3

3. Time to configure some of the files. All the files for your application will be contained in the fuel/app/ folder. We need to set ourselves up a database to start with, if oyur using xampplite like I am just start xampp up (theres a shortcut in the start menu) and load up http://localhost/phpmyadmin into your browser. From here there will be an option to create a new database, I called my fuel_dev to match up :) You can now go to the database config file which is locate din the fuel/app/config folder add in your details

4.Next job is to do some configuration in the main config file, on line 22 we’ll remove the index.php so we get nice clean looking URL’s. Then we will add in the two packages we are going to use into our packages array- this is located on line 135 ‘orm’,'auth’

5. Thats the configuration done now, next job is to move the assets and configure the paths. Since I will be uploading only the application files to my webserver when I’m deploying I’m going to move the contents of the /public folder into the root directory- This will allow me to open my browser and pump in http://localhost/debt3 and see my application. (when we upload i’ll remove oil.php so it can’t be run on the server). The folder should now look like this

6. Any images, javascript files or css files will now go in the /assets folder, were we can reference them in our code using one of the classes. Next job is to edit the paths in the index.php so it matches up with our new directory structure. On line 14 I have removed ../ from the directory structure and the following two lines as well.

$app_path		= '../fuel/app/';

becomes

$app_path		= 'fuel/app/';

7.You can see what all three of my paths now look like-

8. Once you have swapped the paths out- open your browser and load your install (mine is located at http://localhost/debt3/ )- this is what mine looks like :)

9. Locate your fuelphp folder and open a command prompt folder into the root directory of the unzipped files now located in your htdocs folder- mine is – C:\xampplite\htdocs\debt3- to get to the directory open a dos prompt by typing command into the run tab on the start menu then typing cd c:\folder

10. From here, we are going to start to code! We are going to start by scaffolding our lead administration interface, we are going to have 3 controllers and 3 tables in our database. The 3 controllers are leads, users and the default welcome controller. The three tables are going to be- leads, migrations and users.
11. The process to create our application will be to create all the appropriate data capture mechanisms then lock down the correct controllers with the authentication library
12. To scaffold our leads controllers we want to store the following information

Total_debt We want to be able to sort the leads that we generate
Creditors We want to know if a lead is suitable by the amount of creditors they have
Employment We would like to know their employment status
first_name Obviously we need to know their name
last_name As above
Email We need details in case we can’t get in contact with them over the phone
Suitable A suitable time to contact the lead
Dated A date of when they submitted the request for information form
Phone A phone number to contact them with

13. Once we have this done we can now run the migration- you can open your migrations folder located in /fuel/app/migrations and it should be called 001_create_leads.php 001 represents it being our first migration

This is what my file looks like. Now lets run the migration by typing in php oil refine migrate
into our dos window. If you get an error you probably do not have your database configured correctly.

We now should have a working application, fire up your web browser again and navigate over to the url of your app- mine is http://localhost/debt3/ (if you get an class not found error you probably never loaded the orm library in step 4, go back and revise). If everything worked correctly then you should have a nice screen like this one below- which lets you add/delete and update current leads

Go ahead and add a new lead to test it out, you deserve this little reward.

14.Next step is to setup our welcome controller to post the leads from the home page, I have designed my home page and have already built the form- the form is basically the following elements

<form action="<?=Uri::create('welcome/submit');?>" name="lead_form" accept-charset="utf-8" method="post" onsubmit="return validateForm()" >
<table align="center" width="500" cellpadding="5" s>
	<tr>
		<td>Total Unsecured Debt</td>
		<td>
			<select name="total_debt" style="width:160px">
			<option value="">Please Select</option>
			  <option value="under 2k">under €2000</option>
			  <option value="2k-5k">€2000 -> €5000</option>
			  <option value="5k-15k">€5000-€15000</option>
			  <option value="15k+">€15000+</option>
			</select>
 
		</td>
	</tr>
	<tr>
		<td>Creditors</td>
		<td><select name="creditors" style="width:160px">
			<option value="">Please Select</option>
			  <option value="2">2</option>
			  <option value="3">3</option>
			  <option value="4">4</option>
			  <option value="5+">5</option>
			</select>
		</td>
	</tr>
	<tr>
		<td>Employment Status</td>
		<td><select name="employment" style="width:160px">
			 <option value="">Please Select</option>
			  <option value="Employed Fulltime">Employed Fulltime</option>
			  <option value="Employed Parttime">Employed Part Time</option>
			  <option value="Self Employed">Self Employed</option>
			  <option value="Unemployed">Unemployed</option>
			  <option value="Retired">Retired</option>
			  <option value="Student">Student</option>
 
			</select>
 
		</td>
	</tr>
	<tr>
		<td>First Name</td>
		<td><input type="text" name="first_name"></td>
	</tr>
	<tr>
		<td>Last Name</td>
		<td><input type="text" name="last_name"></td>
	</tr>
	<tr>
		<td>Email</td>
		<td><input type="text" name="email"></td>
	</tr>
	<tr>
		<td>Contact Number</td>
		<td><input type="text" name="phone"></td>
	</tr>
	<tr>
		<td>Suitable time to call</td>
		<td>
			<select name="suitable" style="width:160px">
				<option value="">Please Select</option>
				<option value="Now">Call Now</option>
				<option value="9am-12pm<">9am-12pm</option>
				<option value="12pm-2pm">12pm-2pm</option>
				<option value="2pm-6pm">2pm-6pm</option>
				<option value="6pm-9pm">6pm-9pm</option>
			</select>
		</td>
	</tr>
	<tr>
		<td></td>
		<td><INPUT TYPE="image" SRC="<?= Asset::find_file('button_2.png','img')?>"/></td>
	</tr>
</table>

I have used limited fuelphp classes as I usually design the forms out html first and then move into programming them. I used the Asset::find_file(‘button_2.png’,'img’) to locate the submit button in the assets/img folder I also used the <?=Uri::create(‘welcome/submit’);?> to create the location for where the form will be submitted. Also I used javascript to do the validation of the form on the client side rather than the server side.

This is what the controller looks like- firstly the index function to load the home page

public function action_index()
	{
 
		$this->response->body = View::factory('welcome/index');
	}

A very simple function is all thats needed- our index html page is the file named index.php and located in the fuel\app\views\welcome folder- just replace the index.php file thats there- our form is now submitting to welcome/submit which corresponds to action_submit function in our welcome controller, listed below

public function action_submit(){
 
		$val = Validation::factory();
 
 
		$val->add('first_name', 'First Name')->add_rule('required');
 
		if (Input::method() == 'POST' && $val->run())
		{
			$lead = Model_Lead::factory(array(
				'total_debt' => Input::post('total_debt'),
				'creditors' => Input::post('creditors'),
				'employment' => Input::post('employment'),
				'first_name' => Input::post('first_name'),
				'last_name' => Input::post('last_name'),
				'phone' => Input::post('phone'),
				'email' => Input::post('email'),
				'suitable' => Input::post('suitable'),
				'dated' => date('y-m-d'),	
			));
 
			if ($lead and $lead->save())
			{
				//Session::set_flash('notice', 'Added lead #' . $lead->id . '.');
 
				$this->response->body = View::factory('welcome/success');
			}
 
			else
			{
				Session::set_flash('notice', 'Could not save lead.');
				Response::redirect('welcome');
			}
		}
 
		$this->template->title = "Leads";
		$this->template->body = View::factory('leads/create');
 
 
	}

Just to explain some of the code, firstly we are testing to make sure the information was posted and it was someone just “getting the page- this could fill our database with dodgy 0 value inputs since we are doing the validation on the client side. I have included one validation rule just to make sure nothing empty is being post on the first_name.

Once we have our array of input items- made out, its easy enough just to create a new lead object with the model and then lead->save() saves it- without even the need to go and write a function in our model to this.

If you now submit the form you should see a record appear in the database- check out the leads scaffold. You may need to add in the success view.

Once we have this tested and working, we are now going to lock down the leads controller so that only authorised users can view it

15. Create the user controller- Next thing to do is to go back to our command prompt and use oil to generate our controllers- type in the following command “php oil g controller users login logout” and this will generate our users controller with login and logout functions and views, although we will only be using the login view

16. Load up your controller and we are going to add to our controller functions- this what it currently looks like

class Controller_Users extends Controller_Template {
 
	public function action_login()
	{
		$this->template->title = 'Users &raquo; Login';
		$this->template->content = View::factory('users/login');
	}
 
	public function action_logout()
	{
		$this->template->title = 'Users &raquo; Logout';
		$this->template->content = View::factory('users/logout');
	}
}

and now we are going to replace the action_login and action_logout with our own code

public function action_login()
    {
        if(Auth::check())
        {
            Response::redirect('leads'); // user already logged in
        }
 
        $val = Validation::factory('users');
        $val->add_field('username', 'Your username', 'required|min_length[3]|max_length[20]');
        $val->add_field('password', 'Your password', 'required|min_length[3]|max_length[20]');
        if($val->run())
        {
            $auth = Auth::instance();
            if($auth->login($val->validated('username'), $val->validated('password')))
            {
                Session::set_flash('notice', 'FLASH: logged in');
                Response::redirect('leads');
            }
            else
            {
                $data['username'] = $val->validated('username');
                $data['errors'] = 'Wrong username/password. Try again';
            }
        }
        else
        {
            if($_POST)
            {
                $data['username'] = $val->validated('username');
                $data['errors'] = 'Wrong username/password combo. Try again';
            }
            else
            {
                $data['errors'] = false;
            }
        }
        $this->template->title = 'Login';
        $this->template->errors = @$data['errors'];
        $this->template->content = View::factory('users/login', $data);
    }
    public function action_logout()
    {
        Auth::instance()->logout();
        Response::redirect('/users/login');
    }

In the login function you can see that we are checking against whether the user is already holding a session- if they are just redirect them to the leads controller, remember we have already auto loaded the auth library.

The next part is the validation of our login fields, which is pretty straightforward. We then call if($auth->login($val->validated(‘username’), $val->validated(‘password’))) to check the login, if its successful we then redirect the user to the leads controller, calling this function starts a session for the user. The rest of the controller is simply to validate the user information, load the login form and deal with any errors-

Our login form is pretty simple, we replace our login.php view with this code-

<h2>Login</h2>
<p>Login to your account using your username and password.</p>
 
<?php echo isset($errors) ? $errors : false; ?>
<?php echo Form::open('users/login'); ?>
 
<div class="input text required">
    <?php echo Form::label('Username', 'username'); ?>
    <?php echo Form::input('username', isset($username) ? $username : false, array('size' => 30)); ?>
</div>
 
<div class="input password required">
    <?php echo Form::label('Password', 'password'); ?>
    <?php echo Form::password('password', NULL, array('size' => 30)); ?>
</div>
 
<div class="input submit">
    <?php echo Form::submit('login', 'Login'); ?>
</div>

This is using some of the fuelphp form class. This is how it looks in the browser

In order to use this we must create a user account.

Go ahead and generate a migration by typing this into the command prompt again

php oil g migration create_users username:varchar[50] password:varchar[50] email:varchar[70] profile_fields:text group:int[11] last_login:int[20] login_hash:varchar[255]

and dont forget to run the migration once its created-

php oil refine migrate

One bit of configuration is required, we need to change the table name from simpleusers to users in fuel\packages\auth\config\simpleauth.php on line 24 it says

'table_name' => 'simpleusers',

change this to

'table_name' => 'users',

We now need to create our admin account, we are going to do this manually since there will be only one login, I’m going to create a temporary function which I will delete after I run it from the browser.

The function looks like this

public function action_create(){
 
		$create_user = Auth::instance()->create_user('admin','password','chris@justni.com','100');
 
		if( $create_user )
		{
			echo "User created";			
		}
		else
		{
			echo "not created";
		}
 
	}

I just ran it there- of course you going to change the email address and password to match your own, but when your run it, it should say “User created” (you may get and error from the template but don’t worry about that) Now go back and remove the function as this application is only going to be used by the on person there is no need for the signup forms.

Next we are going to add some code to the before function in the leads controller. After you declare the class and before the rest of your functions add in the following function

function before(){
 
		parent::before();
 
		if (! Auth::check())
        {
            Response::redirect('/users/login');
        }
	}

This will check if the person is logged in and if not- redirect to the login page. And we’re done- you can see the site I built this for live now at Debt Solutions Ireland

Summary

To finish with, I made some pointers on why to use fuelphp and why not-

Why not to use fuelphp

  • API changed in 2 months since I started using it, its not dramatic but its annoying
  • There is a few errors I came across while developing and some simple features are just not there
  • The documentation is nowhere near complete never mind at the level of codeigniter. There are parts of the documentation with just the headers
  • I was looking for a low cost web hosting solution that supported the features of php 5.3 in Ireland, I wasn’t going to pay more than €5 or about $8 and I couldn’t find anyone, everyone kept trying to flog me dearer services or up sell vps which I didnt really want. I just wanted a cheap host with its services in Ireland, I couldn’t find anyone.
  • Magic migrations at the time of writing didn’t work completely

Why to use fuelphp

  • It has everything that you need out of the box, Auth/ACL and ORM- these items are what I miss the most from codeigniter
  • PHP 5.3, it uses namespaces and anonymous functions which will come into great use as more php coders get to grips with them.
  • It still has small footprint which is always a winner, some frameworks come out with little features and lots of code that doesnt do much, which makes it hard to learn, fuelphp is lightweight and feature rich- win/win in my books

But, if FuelPHP was developed and commented thoroughly over the next 6-12 months I could be a great piece of kit, its already quite clean.


Thanks to bravosms in the comments for pointing out a typo


3
Mar 10

Creating a short URL service using PHP and MySQL

Hey guys, time to get deep, i thought i would create a short tutorial on creating a URL shortening service. We have all seen them, there are tonnes out there, the most famous one would be tinyurl.com which isnt actually that short as there are plenty out there that are shorter- i own folo.me which is my personal contribution and this a tutorial on what i went throught to create that site. TinyUrl.com is the default one used on Twitter.

In this tutorial am going to discuss several topics-

  • php
  • mysql
  • abstraction of code from design
  • string manipulation
  • mod_rewrite

So lets get started!..

So where to start? Firstly we must setup a database, on your web host or local machine. i would advice setting up a webserver with php and mysql, theres many packages that do this automatically for you including xampp which can be found by clicking here


We must create a database, load up phpmyadmin and typpe a name for your database into where it says create  you can change the collation if you need to but since where just dealing with URL’s there should be a need to so just click create and accept the default collation. (Your phpmyadmin may differ from mine since am using an older version)

creating a database with phpmyadmin
creating a database with phpmyadmin

Once you have your shorter_urls databse created, its time to add some tables to the database, i always assign the first field to be an identifier field with the name ID, even if i dont plan on using the table in relationships i may do so later so its good to name the first field as a primary key. This should be of type integer and set to auto increment and also set as the primary key.

The second field will be the “short” part of the short url, for my site it wil be folo.me/xxxxxx where the xxxxxx would be the short part. This could a varchar and we should define the size as 6 as this would leave us with plenty of room- we are going to use letters and numbers- that gives us 36 charachters to use therefore 36 to the power of 6 would give us 2,176,782,336 which is plenty of space to store URLs.

The next field will be the actual URL that is being shortened- URLS can vary in size, and its safe to say 1000 length would be enough room and as we are going to use varchar for the field as well, varchar doesnt store white space in database we should be fine.

The next field will be a timestamp, a simple datetime field type which we will populate when we insert queries. this will allow us to compile stats and issue querys to see what was popular on certain days.

So this is how our create statement will look like.

CREATE TABLE `short_urls` (
`id` int(11) NOT NULL auto_increment,
`short` varchar(6) NOT NULL,
`url` varchar(1000) NOT NULL,
`stamped` datetime NOT NULL,
PRIMARY KEY  (`id`),
KEY `short` (`short`)
) ENGINE=MyISAM  DEFAULT;

I also defined an index on the short field to speed up searching.

Now that we have the database setup we need to create some php! I like to create my HTML templates first in a nice wysiwyg program like dreamweaver. All you need to do is create a index.php file and insert the following form.

&lt;form id="shorten_form" name="shorten_form" method="post" action="shorten.php"&gt;
&lt;label&gt;
&lt;div align="center"&gt;
&lt;input type="text" name="url" id="url" /&gt;
&lt;/div&gt;
&lt;/label&gt;
&lt;label&gt;
&lt;div align="center"&gt;
&lt;input type="submit" name="submit" id="submit" value="Shorten" /&gt;
&lt;/div&gt;
&lt;/label&gt;
&lt;/form&gt;

This form now gives us this-

creating a database with phpmyadmin

Now to create the functions, there are a few we will use-

  • We need a function open the database connection and select the database
  • We need a function to generate our short url
  • We need a url to check if the shortened url is unique or not and if it is then insert the url into the database and return it to the user

So now create your second PHP  file and calll it shuffle.php and insert the following code

function dbconnect(){
   $link = mysql_pconnect('Your_DB_HOST', YOUR_DB_USERNAME', 'YOUR_PASSWORD');
   $db_selected = mysql_select_db('YOUR_DB', $link);
}

This function opens a persistent connection to the database server with your username and password, usually the default username for mysql is “root” and the password is left blank. The persistent conenct is closed when the script is executed.

The next function is to generate the url/xxxxx bit- the actual shortened bit.

function generateurl($numAlpha=6)
{
   dbconnect();
   $listAlpha = 'abcdefghijklmnopqrstuvwxyz0123456789';
   return str_shuffle(
      substr(str_shuffle($listAlpha),0,$numAlpha)
  );
}

In this function, we have defined a parameter $numAlpha equal to 6, this is the length of the string we are looking to generate, the next line is the dbconnect function we defined previously, the next like is a list the charachters that are allowed to be used in the short URLS. Then the return statement which returns the generated string but also does the generating of the string. It uses the php function str_shuffle to randomnize the list defined in $listAlpha, but since it is inside the substr function which is used to cut strings to the length defined in $numAlpha. The return statement in this line – randomnizes the list of charachters, cuts 6 out of the string and then returns it.

function geturl($in)
{
   dbconnect();
 
   do{
     $out = generateurl();
     $query = "SELECT short  FROM `short_urls` WHERE `short` = '$out'";
	 $result = mysql_query($query);
   } while (mysql_num_rows &gt;1);
 
   $insert_query = "INSERT INTO `short_urls` (`id`, `short`, `url`, `stamped`) VALUES (NULL, '$out', '$in', NOW());";
   $result = mysql_query($insert_query);
 
   return "http://YOUR.COM/".$out;
}

This is another nifty little function first in the parameter is the $in parameter, this is the unshortened URL that your are going to send to the function and it will return the shortened url after it has been inserted into the db. The next line of course is our dbconnect function from above. The next this is the do… while loop which will create a shortened url with the generateurl(); function then create a query to check that the generated short url hasnt been taken already, thanks to the do… while loop, if thay short url has been used before it will just generate another one until it finds a short url that hasnt been inserted into the database. Then the next line in the function will be that query that actually insert the generated short_url into the database, then the following line will be the mysql query which will insert it into the database. Then the return statement returns the short plus whatever url you wish, dont forget the trailing slash after your domain!

Thats nearly all the php we need! Three simple functions a bit of html! Well just some more php… To handle the redirect that you need so that yourdomain.com/xxxx redirects to the original long url.

Putting it all together!

Now that we have all our functions is its just a matter of sticking the function calls into the html.

Now create your third php page! We will call it forward.php.

First thing to do in this file is open the php file with the usual

include 'shuffle.php';

Then this-

$i = $_SERVER['QUERY_STRING'];
 
if (preg_match("/^[0-9a-z]{6}$/", $i)) {
    dbconnect();
 
    $result = mysql_query("SELECT short, url FROM `short_urls` WHERE `short` = '$i'") or die(mysql_error());
 
    if (mysql_num_rows($result) &lt; 1) {
        header("Location: http://yourdomain.me");
        exit;
    }else
	{
            $row = mysql_fetch_row($result);
	    header("Location: ".$row[1]);
	}
 
}
else
{
   header("Location: http://yourdomain.com");
}

First line assign the query string to a variable which is just everything that appears after the slash of a domain example.com/querystring. Then the next line is a regular expression to make sure its a short url and not one of your other files on the server. Then as before we connect to the database with our function, then we pass the short url into a mysql query to check if the short url actually exists, and if it does what it corresponds to. Then we do some error checking, if the short url doesnt exist we direct the user to yourdomain using the header function but if it exist we use the header function to redirect the user to the long url that matches the short in the database.

You need to upload the following as the .htaccess file on your server

XBitHack      Off
RewriteEngine On
RewriteCond   %{REQUEST_URI} \/([0-9a-z]{4})$ [NC]
RewriteRule   ^(.*) http://www.yourdomain.com/forward.php?%1 [L]

This parses the query string from yourdomain.com/xxxxxx to the forward.php which is the bsis of the short url service.

Making the it work!

Next thing is to create the final page and combine it all-

create a file called shorten.php and as before include the shuffle.php -

include 'shuffle.php';

Then we include the functions into your template!

         &lt;p align="center"&gt;Your URL:&lt;/p&gt;
         &lt;p align="center"&gt;&lt;?php echo $_POST['url']; ?&gt;&lt;/p&gt;
         &lt;p align="center"&gt;Has been shortened to:&lt;/p&gt;
         &lt;p align="center"&gt;&lt;?php echo geturl($_POST['url']); ?&gt;&lt;/p&gt;
 
The second line denotes the variable that was posted from the form on the index.php file then on the last line we use our geturl() function to do carryout the generation and insertion of the urls- return is a nicely shortened url! and thats us!

In the next installment-

  • Using ajax to generate shortened urls
  • Improving security to prevent cross site scripting and junk urls being inserted

Any questions post them below!