21
Jan 14

Launching a new website

I live in a little city called Newry. People say nothing happens in Newry but i don’t think that is true. So i took it upon myself to build a new website as a side project.

So today I am announcing Events In Newry which i hope event organisers and people who run clubs will add their events to.

Its built on laravel 4.0 which is my current weapon of choice when it comes to developing with php. I haven’t used codeigniter in months to develop anything new with. Its also hosted on fortrabbit which is also a new experience. The front end is bootstrap 3 which would also make this the first po\roject that i have used the latest bootstrap with.

Let’s see how it goes.


21
Jun 11

Posting to linkedin from php and codeigniter

I recently got tasked with posting offline messages to twitter, i.e when a user completes an action on my application, there would be a message posted to linkedin.

I looked at the many oauth libraries about on the web for php and codeigniter and couldn’t find one that worked perfectly for my situation so i mashed a few together and ended up with this- and i learnt a few lessons on the way.

Where I got the php libraries that where built around the linkedin api, nothing was clean and coherent.. and simple so I found a twitter library and modified it to my needs- both linkedin and twitter are built around OAUTH (so is facebook) and this made it super easy to change a few urls and directories and have a working library.

The source for my derived work came from this library listed here - https://www.packtpub.com/article/user-authentication-with-codeigniter-1.7-using-twitter-oauth if you check my code you will see i edited slightly to change it for use with linkedin. If your using this library you will also need the PHP oauth Library which is listed here- http://oauth.googlecode.com/svn/code/php/

The library- save this as linked.php in your application/libraries folder- also save your “OAuth.php” in there as well

The llibrary

 
<?php
 
require_once("OAuth.php");
 
class linkedin
{
 var $consumer;
 var $token;
 var $method;
 var $http_status;
 var $last_api_call;
 var $callback;
 
	function linkedin($data)
	{
		$this->method = new OAuthSignatureMethod_HMAC_SHA1();
		$this->consumer = new OAuthConsumer($data['consumer_key'], $data['consumer_secret']);
		$this->callback = $data['callback_url'];
 
		//print_r($data);
 
 
		if(!empty($data['oauth_token']) && !empty($data['oauth_token_secret']) && !empty($data['callback_url']))
		{
			$this->token = new OAuthConsumer($data['oauth_token'],$data['oauth_token_secret']);
 
 
		}
		else
		{
			$this->token = NULL;
		}
 }
 
 function debug_info()
{
 echo("Last API Call: ".$this->last_api_call."<br />\n");
 echo("Response Code: ".$this->http_status."<br />\n");
 }
 
 function get_request_token()
{
	 $args = array('scope' => 'r_basicprofile,r_network,rw_nus');
 
	 $request = OAuthRequest::from_consumer_and_token($this->consumer,
		 $this->token, 'GET',
		  "https://api.linkedin.com/uas/oauth/requestToken", $args);
 
	$request->set_parameter("oauth_callback", $this->callback);
	$request->sign_request($this->method, $this->consumer,$this->token);
	$request = $this->http($request->to_url());
 
	 parse_str($request,$token);
 
	 $this->token = new OAuthConsumer($token['oauth_token'],$token['oauth_token_secret'],$this->callback);
 
	 return $token;
 }
 
	function get_access_token($oauth_verifier)
	{
		$args = array();
 
		$request = OAuthRequest::from_consumer_and_token($this->consumer, $this->token, 'GET', "https://api.linkedin.com/uas/oauth/accessToken",$args);
		$request->set_parameter("oauth_verifier", $oauth_verifier);
		$request->sign_request($this->method, $this->consumer,$this->token);
		$request = $this->http($request->to_url());
 
		echo $request ;
 
		parse_str($request,$token);
		//echo $oauth_verifier;
 
		$this->token = new OAuthConsumer($token['oauth_token'],
		$token['oauth_token_secret'],1);
 
		return $token;
	}
 
	 function parse_request($string)
	 {
		 $args = explode("&", $string);
		 $args[] = explode("=", $args['0']);
		 $args[] = explode("=", $args['1']);
 
		 $token[$args['2']['0']] = $args['2']['1'];
		 $token[$args['3']['0']] = $args['3']['1'];
 
		 return $token;
	 }
 
	function parse_access($string)
	{
		$r = array();
 
		foreach(explode('&', $string) as $param)
		{
			$pair = explode('=', $param, 2);
			if(count($pair) != 2) continue;
			$r[urldecode($pair[0])] = urldecode($pair[1]);
		}
		return $r;
	}
 
	function get_authorize_URL($token)
	{
		if(is_array($token)) $token = $token['oauth_token'];
		return "https://api.linkedin.com/uas/oauth/authorize?oauth_token=" .
		  $token;
	}
 
	function http($url, $post_data = null)
	{
		$ch = curl_init();
 
		if(defined("CURL_CA_BUNDLE_PATH"))
		curl_setopt($ch, CURLOPT_CAINFO, CURL_CA_BUNDLE_PATH);
 
		curl_setopt($ch, CURLOPT_URL, $url);
		curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, 30);
		curl_setopt($ch, CURLOPT_TIMEOUT, 30);
		curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
		curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, 0);
 
		if(isset($post_data))
		{
			curl_setopt($ch, CURLOPT_POST, 1);
			curl_setopt($ch, CURLOPT_POSTFIELDS, $post_data);
		}
 
		$response = curl_exec($ch);
		$this->http_status = curl_getinfo($ch, CURLINFO_HTTP_CODE);
		$this->last_api_call = $url;
		curl_close($ch);
 
		return $response;
	}
 
 	function share($comment, $title, $url, $imageUrl, $description, $access_token) {
		$shareUrl = "http://api.linkedin.com/v1/people/~/shares";
 
		$xml = "<share>
		      <comment>$comment</comment>
		      <content>
		         <title>$title</title>
		         <submitted-url>$url</submitted-url>
		         <submitted-image-url>$imageUrl</submitted-image-url>
		         <description>$description</description>
		      </content>
		      <visibility>
		         anyone
		      </visibility>
		    </share>";
 
		$request = OAuthRequest::from_consumer_and_token($this->consumer, $access_token, "POST", $shareUrl);
		$request->sign_request($this->method, $this->consumer, $access_token);
		$auth_header = $request->to_header("https://api.linkedin.com");
 
 
		$response = $this->httpRequest($shareUrl, $auth_header, "POST", $xml);
 
		return $response;
	}
 
 
	function httpRequest($url, $auth_header, $method, $body = NULL) {
 
		if (!$method) {
			$method = "GET";
		};
 
		//echo $url. " " .$method. " " .$body;
 
		//echo $auth_header;
 
		$curl = curl_init();
		curl_setopt($curl, CURLOPT_URL, $url);
		curl_setopt($curl, CURLOPT_HEADER, 0);
		curl_setopt($curl, CURLOPT_RETURNTRANSFER, 1);
		curl_setopt($curl, CURLOPT_HTTPHEADER, array($auth_header)); // Set the headers.
 
		//echo $auth_header;
 
		if ($body) {
			curl_setopt($curl, CURLOPT_POST, 1);
			curl_setopt($curl, CURLOPT_POSTFIELDS, $body);
			curl_setopt($curl, CURLOPT_CUSTOMREQUEST, $method);
			curl_setopt($curl, CURLOPT_HTTPHEADER, array($auth_header, "Content-Type: text/xml;charset=utf-8"));  
 
 
		}
 
		$data = curl_exec($curl);
		echo curl_getinfo($curl, CURLINFO_HTTP_CODE);
		//if ($this->debug) {
			//echo "bla";
			echo $data . "\n";
		//}
 
		curl_close($curl);
 
		return $data; 
	}
}
?>

I have commented the code more so than giving a run through of how it works.

The codeigniter stuff :)

<?php
session_start();
 
class User extends controller {
 
 
	var $data;
 
	function user(){
 
		parent::Controller();
 
		parse_str(substr(strrchr($_SERVER['REQUEST_URI'], "?"), 1), $_GET);
		$this->load->helper('url');
		$this->load->library('session');
 
		$this->data['consumer_key'] = "";
		$this->data['consumer_secret'] = "";
		$this->data['callback_url'] = "yourcallback";
 
	}
 
	function index(){
 
 
 
 
	}
 
 
	function linkedin(){
 
 
		$this->load->library('linkedin', $this->data);
		$token = $this->linkedin->get_request_token();
 
		$_SESSION['oauth_request_token'] = $token['oauth_token'];
		$_SESSION['oauth_request_token_secret'] =   $token['oauth_token_secret'];
 
		$request_link = $this->linkedin->get_authorize_URL($token);
 
		$data['link'] = $request_link;
 
 
		header("Location: " . $request_link);
	}
 
 
	function linkedin_submit(){
 
 
 
		$this->data['oauth_token'] = $_SESSION['oauth_request_token'];
		$this->data['oauth_token_secret'] = $_SESSION['oauth_request_token_secret'];
 
		//
		//laod the library with the variables defined in the constructor
		//
		$this->load->library('linkedin', $this->data);
		//echo $_REQUEST['oauth_verifier'];
 
		$_SESSION['oauth_verifier']     =  $_REQUEST['oauth_verifier'];
 
		/* Request access tokens from linkedin */
		$tokens = $this->linkedin->get_access_token($_SESSION['oauth_verifier']);
		/*Save the access tokens.*/
		/*Normally these would be saved in a database for future use. */
		$_SESSION['oauth_access_token'] = $tokens['oauth_token'];
 
		$_SESSION['oauth_access_token_secret'] = $tokens['oauth_token_secret'];
 
 
 
		//store your user info
		//if your going to store the tokens you will need to serialise in and out of the db
		//
		// you will need to write your own models- simple storage- serialization done here in the controller
 
		$this->load->model('muser');
		$data_id = array('linked_in' => serialize($this->linkedin->token),'id' => $user_id,'oauth_secret' => $_REQUEST['oauth_verifier']);
 
		//i used this to store the link_in tokens in the db
 
		if(!$this->muser->store_id($data_id)){
 
			//error
 
		}
 
 
	}
 
	function linkedin_post(){
 
		$id = $this->input->get('id');	
 
		//
		//this is the get from db
		//
		//you will have to make your own models
		//
 
 
		$row = $this->muser->get_by_id($id);
 
		$linked_in = $row['linked_in'];
 
 
		//
		//setup the post info
		//
 
		$comment = "message";
		$title = "story title";
		$targetUrl = "http://link";
		$imgUrl = "image title";
 
		//
		//
		//load the library for linkedin with the variables defined in the constructor 
		//
 
		$this->load->library('linkedin', $this->data);
 
 
		$apiCallStatus    =   $this->linkedin->share($comment, $title, $targetUrl, $imgUrl,unserialize($linked_in));
 
	}
 
?>

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


16
May 11

facebook marketing strategy to increase business page fans/likes

Introduction- this is for both consumer and business brands/pages

I was recently requested to quote for a project for a potential client who had a major brand on their books and they wanted a flash game developed in a very short time. Not only did they have an unrealistic time frame to have the game developed (a week) but they had no experience with facebook games and to top it of they didn’t even have an idea of what game they wanted.
I suggested a cheaper solution (which I am going to detail below) that developing a game but they didn’t want to listen, therefore I quote an expensive price, if they wanted me to develop anything for them, they were going to have to pay for the headaches as well as my time..

What did I suggest ? -> “The gated competition”

The gated competition, bends facebook’s terms of service but is very much a common practice now on facebook.

The gated competition is where a user has to “like” (pass through the gate) in order to take part in a competition. Once the user has liked the page, they are then presented the next stage, which is usually to enter their details to be entered into a draw or presented with a download link to download the “prize”. You can see a page I made for a client-

So how do I win friends and influence people.. via facebook for my page

Firstly- this isn’t a “free” solution- you need to spend time/money advertising your page to seed the campaign. The value in this strategy is- that I can not find any strategy which returns the most return on investment which can scale in terms of developping new likes/leads on facebook

There are three elements that make up this process-

  1. The page
  2. The prize
  3. The advertising

Without all three of these elements your campaign will not work fully

The page-

  • The tab must be set as your default landing tab when someone visits your facebook page
  • The tab must be gated- the user can only interact with the tab if they have “liked” the page
  • The unlike tab must inform the user why they should like the page- your sales text
  • The tab must perform relevant task- allow data collection or generate download link
  • Once user has completed the task of the tab, they a presented to post to their wall that they have participated.
  • A privacy policy should be used to tell users why your collecting their data.

The prize

  • Give to receive. The prize is the incentive of why someone should come and like your page and enter for a chance to win the item.
  • Pick a prize that matches what the target demographic of your product or service that your potential customer. would be interested in. The person who contacted me to in enquire about developing game had very specific demographic information- 18-24 years old and mainly male, I suggested a gaming console with the latest guitar hero, plus a hamper of the product they where advertising.
  • If your a business to business page- give away a service or a product that matches what your business offers-

The advertising

Without advertising the strategy doesn’t work to its full potential- if you have a few thousand likes already it may increase your likes by 0%-10%-20% over a monthly time frame but with advertising it can see even greater returns. Advertise the competition and the prize!

Where to advertise

  • Facebook adverts allow you to advertise by demographic information and interests- this can be more advantageous when advertising consumer products
  • Google adwords can be used t target users with very specific key terms which can be more advantageous for companies advertising business to business products/services
  • Offline- if your business has premises- having the facebook icon dotted about the place with the URL can help- include your facebook URL in all print – on the back of business cards right through to product packaging.

The why

  • You can collect email addresses- you may not be able to get users to buy on facebook but people still buy from upselling in emails- groupon has seen their business explode with daily emails
  • You can collect likes within a targeted demographic/interest
  • You get most return on your investment. Instead of just advertising a facebook page- you can now collect email addresses and also encourage users to share content to their wall by making it the “next step” in the competition process
  • Once you have people like your page, you can create shareable branded content

The formula

If you are not receiving enough likes from this strategy here are two points to consider
Your advertising spend is not high enough, increase your advertising spend and you will see increased date collected
If this didn’t work, maybe the prize was not a big enough fruit. Try the competition again with a larger prize.

The trial-

If you want to see how It looks- check out http://www.facebook.com/newyorkcolor which now use the competition software

The software

If you fancy using this strategy that has seen great returns – here’s what the software does

  • Checks if the user has liked the page or not
  • Validates and collects the data from the facebook tabs
  • Has a separate admin to view the collected data.
  • Separate Admin allows the export as csv to export data to an email marketing solution

05
Apr 11

Checking in to facebook using the graph api and php

When a client contacted me last week to implement facebook checkins into an existing application i had to go searching for information. The only information i could get was from the API, there was no real tutorial out there explaining each step of the process- hopefully I address this issue.

firstly we need the user to accept the application- we do this by bouncing them off to facebook – you need to include the facebook php library – you can find it here

 
<?php $facebook = new Facebook(array( 'appId' =>"YOURAPPID",
	  'secret' => "APPSECRET",
	  'cookie' => false
	));
 
 
if ($me) {
	$logoutUrl =   $facebook->getLogoutUrl();
} else {
	$loginUrl   =   $facebook->getLoginUrl(array(
		   'canvas'    => 0,
		   'fbconnect' => 1,
		   'req_perms' => 'publish_stream,status_update,offline_access,publish_checkins'
		   ));
}
?>
<? if ($me){?>
	Thanks- application has been accepted
<? }else{ ?>
 
	<a href="<?= $loginUrl; ?>">
	Login into Facebook to accept applicatioon
	 </a>
 
<?}?>
 
 
<?   $url = "https://graph.facebook.com/oauth/access_token"; 		 
	 $client_id = "client_id"; 		  
	 $client_secret = "app_id"; 		  
	 $postString = "client_id=$client_id&client_secret=$client_secret&type=client_cred&scope=email,publish_stream,offline_access,publish_checkins"; 		 
//This first bit of code is to get the application a access token.
$curl = curl_init(); 		  curl_setopt($curl, CURLOPT_URL, $url); 		  curl_setopt($curl, CURLOPT_FAILONERROR, 1); 		  curl_setopt($curl, CURLOPT_RETURNTRANSFER, 1); 		  //curl_setopt($curl, CURLOPT_FOLLOWLOCATION, 1); 		  curl_setopt($curl, CURLOPT_POST, 1); 		  curl_setopt($curl, CURLOPT_POSTFIELDS, $postString); 		  $response = curl_exec($curl); 	 		 		 $url = "https://graph.facebook.com/".$FBID."/checkins"; 		 $token = substr($response,13); 		   		  $attachment = array( 		   'access_token' =-->  $token,
		   'place' => 'place_ID',
		   'message' =>'I went to placename today',
 
		   'picture' => 'http://logo for post/',
		   'coordinates' => json_encode(array(
			'latitude'  => 'lat',
			'longitude' => 'long',
			'tags' => "")));//tag a user to be tagged in as well
 
		$attachment =	$attachment;
		  print_r($attachment);
 
		  $ch = curl_init();
		  curl_setopt($ch, CURLOPT_URL,$url);
		  curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, FALSE); // This i added as the URL is https
		  curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, 2);      // This i added as the URL is https
		  curl_setopt($ch,CURLOPT_RETURNTRANSFER,1);
		  curl_setopt($ch, CURLOPT_POST, true); // Do I need this ?
		  curl_setopt($ch, CURLOPT_POSTFIELDS, $attachment);
		  $result= curl_exec($ch);
		  curl_close ($ch);
		  print_r($result);// some debug info
 
?>

The main problem i had with the code was to get the location details- the longitude and latitude had to be encoded as json- luckily php has a handy little tag for this which can turn a php array into json- you do not need to encode the whole attachment just the location details.

You can see with the post below- its a pretty normal post but it has tagged on the back of a map of the location. you can check out the docs here for adding more info to the post- Facebook checkin API DOC


29
Mar 11

How to target potential clients using seo

The idea for this blog post came from me looking through the search terms that my website was receiving traffic from and i thought I would create an article to match the term- seems with a bit of research there is an poorly written article already out there, this post is going to share my knowledge and how I have gone about trying to get clients using SEO.

I am not going to give you basic SEO information like keyword research or where to put keywords, this post is more a strategy in how to target specific customers.

Step one- Identify what you offer and what services your looking clients for

What works best in SEO is highly targeted key term selection- if you are an accountant looking new clients- “accountant” would be a very competitive term rather than a specific service “Sole Trader Income Tax Preparation” which is a specific term and would be less competitive.

When you know specifically what services you offer the next step is to research which key terms to target. You can type the services you offer into somewhere like Google Keyword Tool which will give you an idea of what people are searching for and give you some idea of terms you should be targeting. Every key term should then be put into a google search to identify how competitive the term is

Step two- Build Pages

The next step in the process is to take your key services key term and build pages explaining the service you offer and why a potential client should use your organisation.

I did this with justni.com and specifically a page like facebook apps developer which targets the service I offer. My Ideal client for this is a design agency who may not have the technical skills that facebook apps require but have a client interested in developing an app.

Step Three – Setup a blog and write about your sector/area

As you can see, I have setup this blog on the sub domain of this website, but every post and page still links back to my main site, therefore any Google juice or burst in traffic I get to the blog is fed on to the main website. You do not have to write about your sector- you can post videos or pictures- an excellent example of a success story of this is wine library tv where @garyvee made 1000 videos about wine and became  an internet celebrity (having almost 900k followers on twitter) while starting out with a camera and nothing else.

Step four- Include a call to action

When a user is browsing your page they should see something to click on where they can either contact you or find your contact details. I created a bold black button for this website on the right hand side which directs people to my contact page.

Do not leave it up to the user to find your contact details, make it bold, make it call out at the user- this will increase your conversion rate and in turn increase your leads generated.

Step five- KILLER no1 TIP for SEO-

Create great content! that’s it… if you can create great content that people want to share, thats 90% of the battle- if your rinsing other peoples content and trying to take the copy and paste approach- it will not work. Users/consumers like new, fresh and innovative ideas, that’s why the godfather isn’t stuck at Amazon’s no.1 spot all the time- people like new things! Gary Vaynerchuck won because he created fun and innovative content around wine which people perceive as a stuck up sector. My favourite episode was where Gary compared what wine went with breakfast cereal- see it here- There ya go.. a point just proved.

Step six – Persist and Persevere

SEO is a slow process- like life, the older the person the wiser the person is (meant to be). Google ranks content using this same principle, as your domain/content ages it will rank higher than new or fresh content. Unless your domain carries a lot of authority, new content will take a while to rank.

If you add one post a week for a year, you will have 52 posts by a year end- if each posts receives 4 hits a week = that’s 208 a week! For my business, one enquiry a week would keep my business going, usually much less than this. For any small business 1000/hits per month to their Blog is an ample amount of traffic to keep them going

Fine me on twitter at @yrecruit_chris


14
Mar 11

Making your Facebook shares better/prettier

If your running a website and actively encourage users to share ccntent across facebook, it may be a good idea to control what way its being shared. Facebook includes graph meta tags which allow you to default to a certain image for the post on facebook and what title.

Add these tags between the <head> tags on your page

1
2
3
4
<meta property="og:type" content="blog" />
<meta property="og:url" content="http://blog.yrecruit.com/2011/03/the-state-of-online-recruitment-websites-in-ireland/" />
<meta property="og:site_name" content="Yrecruit Blog" />
<meta property="og:image" content="http://yrecruit.com/imgs/yrecruit_share.png"/>

This is the content for the tags on one of my new sites which enables a logo to be displayed along with the title, if i didnt have that tag included, the logo would not be displayed at all.

Now my post looks like this without the logo

Having added in the tags now i get a pretty branded logo included with my blog post

Plugins for wordpress

Manually putting this on every page would be tedious and time consuming, luckily i use wordpress to power my blogs and it comes with a handy tool to include the tags.

The plugin i use is listed below-
Open Graph
Add Open Graph metadata to your pages.

I added in my own image tag to the header file of my theme and made sure the image worked with the posts

For more info

Check out the page on facebook.com about sharing content


21
Feb 11

Facebooks best kept secret- insights for domain

Facebook launched insights for domains external to Facebook last June and people are still not using them, very few people I know are using them and I thought I would share.

Why use facebook insights for you domain?

If you blog or own a domain with sharable content such as video and mp3’s facebook insights for your domain will allow you see analytics on what is the most shared content and provide an insight into your content in a dashboard like styley..

Setting up Facebook insights for your domain

You need to move over to facebok - http://www.facebook.com/insights/ And at the top of the page you will see the green button for “Insights for your domain”. And you should be presented with the following popup box which will display a little meta tag that should be added to your domains index page <head> tag.

Place this meta tag into your html document- this is mine- excluding my FB id of course. Place it somewhere between your <head> tags -

<meta property=”fb:admins” content=”yourfbid” />

Now click on “check domain” button and Facebook will grab your domain to see if there is a corresponding admin ID, if it matches yours, you will be granted full insights into your domains

Facebook will let view how many impressions your links/flash files/images got when they were shared, this is vital if your website is built around sharing and social media.


14
Feb 11

Web Application Development for Ferrari

I recently completed an web application for Ferrari in conjunction with Jason Dean at TheMews.tv for his client Pierce SmartFusion NewYork. This was a demanding app due to the quick turnaround time required and feature specification changes but its great to work on something that was so intricate and mission critical (a lot of people will be using the application)

What it was for

The main core of the application was to allow potential Ferrari customers to book a test drive and experience a new car that Ferrari was launching. A mailing list was already build that had the web address of the application where a user could import the code that they where suplied with and booking a time slot that they where free on a specific date to test drive the car.

The main features of the application

  • Allow people who were identified to book a car at a specific time and venue.
  • Allow Ferrari to track who made bookings and where
  • Allow Ferrari to rate the customers on the likelihood of the participant in making a purchase.
  • Allow participants to register when they arrived using an ipad version of the website

This doesn’t sound complicated at all but with only 4 cars available, at certain dates, multiple venues and thousands of potential users the system cant get very complicated very quickly.

Build process

The normal build process that most applications whether it be for web, mobile or even facebook is that I am supplied with images of the layout and specification document then it is up to me to turn these two pieces in to a work application.

With the client on Skype liaising with myself and the Ferrari guys, we were able to test the application thoroughly and make the feature requests and changes the same day.

Tools and technology used

To complete this project the basic stack that was used for the web application was-

  • php/mysql combo
  • codeigniter 1.7
  • Blueprint (css for the admin)
  • I also used simplesecurelogin for user login management with CI

As always my development environment is -

  • 2 machines, one running windows 7 and one running windows xp
  • Notepad++
  • Xampp
  • photoshop /filezilla

Other tools include Gmail and skype for communications and to do lists. I also use synergy across my two machines, it allows me to run a 3 monitor setup using the same keyboard and mouse for all three, freeing up desk space

Obstacles Overcome

There was quite a few obstacles to overcome in this project and i have listed them below and how the project was successfully delivered.

  • User experience- a lot of the time, no one plans what an admin section is to have, there is a lot of data in this system and a lot to be viewed. The original designs worked well but limited the user experience, I suggested a few tweaks and the user experience for the user was improved
  • Multiple sources of data, The importation of the customer lists came from multiple different sources with varying formatting. Using php’s inbuilt functions, code could be written quickly to overcome this obstacle.
  • Dates, times and cars. This was a major problem, it was a mission critical kind of problem where you couldn’t have multiple bookings more than 4 as there was only 4 cars available. With multiple cars available at multiple times on multiple dates at multiple venues the system could have easily got out of hand but with continual testing something similar to TDD, iterations were made quickly to build a scalable application
  • iPad view. I do not own many apple products and I certainly do not use an ipad, but one of the requirements was to allow users to register when they arrive at their specified time slot. I had never done an IPad application but I took the original design and scaled it to match the screen resolution provided by the iPad and the client reported back that the application worked well.
  • Speed of delivery. Accommodating tight deadlines is always troublesome when your a freelance solo developer. I put a lot of time in to the development of this application and often worked late to accommodate changes, I enjoy what I do therefore its not often a problem. The advantage in this project was that it was going to be used in California and since I live in Ireland, i can almost get a full days work in before the guys in California are even out of bed!

Conclusions

Although this project was stressful, its good to see something that I built from scratch being used by such a huge brand name. Its great to look out a dreary, miserable, window in Ireland and look back at your machine to input details of Beverly Hills and Ferraris :)

If you have a web application requirement email me chris@justni.com


19
Jan 11

Facebook applications case study

Got sent this by a potential client today who wants something very similar,  I thought I would share it  It’s one of the best case studies I have seen for Facebook application development and user adoption of a branded application.

I have pitched this idea before to clients and they havent gone for it. Now i have this case study to back up the idea!

I have built similar applications in the past to client specification which didn’t have as many features. If you are a brand would like to work with me on something like this- email me- chris@justni.com I would love to build something like this for a big brand.