Wednesday, November 16, 2011

Trials and tribulations with HTML5 Canvas on Android

You may not be aware but I recently released a mobile web app called leftanote.com. It is a neat little application that lets you post notes about someones driving abilities based on their license plate number. It leverages several technologies: jquery, jquerymobile, jqScribble (my custom canvas drawing tool), as well as some other things I will get into shortly.

The coolest part of my app, in my opinion, is the jqScribble drawing tool. It is touch enabled, so it will let you draw with either a mouse or your finger. It then provides hooks to let you specify how you want the image saved. In my case I send the image data string to my webservice which creates the image file. To do this the tool leverages the toDataURL function available on the HTML 5 canvas element. Basically toDataURL converts the canvas image as a 64bit string. This canvas feature is amazing and super fast, which I love.

Nearing the final days before my official "launch" one of my co-workers wanted to use the app. It just so happens he has an Android phone. I believe his OS version is 2.2 (not sure which dessert that is). Anyway he wanted to use the drawing tool, which I was expecting to work perfectly, the drawing part worked fine, but the saving part failed. After some research I discovered that up until version 2.3 of Android the toDataURL functionality of canvas was nothing more than an empty function with a comment to the tune of "I don't know what this is supposed to do".

After some obvious ranting and Google cursing, I came across this post by Hans Schmucker. He was having the exact same issue as me and developed his own PNG encoder, which he used to replace toDataURL on Android devices. So I went to work attempting to implement what he did with my code, unfortunately I was never able to get it to work. However he did get me thinking down the right track. This lead me to the realization that toDataURL can be set to return either PNG or JPG formatted data. Now the only trick was finding a JPEG encoder written in javascript. Well that wasn't tough, a good one exists here (Thanks to Arizona for finding a new link after the old one was removed). All that was left was to add some simple detection and execute if the stock toDataURL doesn't work properly.

Here is my code:

var tdu = HTMLCanvasElement.prototype.toDataURL;
HTMLCanvasElement.prototype.toDataURL = function(type)
{
 var res = tdu.apply(this,arguments);
 //If toDataURL fails then we improvise
 if(res.substr(0,6) == "data:,")
 {
  var encoder = new JPEGEncoder();
  return encoder.encode(this.getContext("2d").getImageData(0,0,this.width,this.height), 90);
 }
 else return res;
}

The first line puts the toDataURL function into a variable so that if it works correctly we don't blow it away on the next line where we override toDataURL with our own custom function. The custom function will attempt to call the original toDataURL, then checks the returned value. If it doesn't have the correct header information, we know that the original toDataURL failed, so it creates a new JPEGEncoder instance and encodes, then returns the canvas data.

Is this the best way of doing things? Probably not, it is never a good idea to muck around with stock functionality, but I didn't want to go back and change my code that already used toDataURL, so I made a judgement call.

Finally to break it down for you: If you need to support the toDataURL function of canvas in an Android device < 2.3. You should take a similar approach.

1) Download a JPEG Encoder.
2) Add in your own custom toDataURL handler which will use the Encoder if the original toDataURL fails.

The drawing tool works like a charm, and saving images is still reasonably fast. Although I am dealing with fairly small images.

Wednesday, October 12, 2011

Dropbox Updates Have Landed

Just wanted to let you guys know that I have made some updates to the Dropbox API Library. These changes are in reaction to the new functionality available in the new Dropbox API. There are a few new methods and I removed the link method. I will outline the changes below.

Here is the Github Repo

I did make some changes to some of the existing methods. The now accept an array of parameters so that you can specify different parameters that can be passed to the API. There were a few new methods that were added, they are as follows:
revisions($path, array $params = array(), $root='dropbox')
restore($path, $revision, $root='dropbox')
search($path, $query, array $params = array(), $root='dropbox')
shares($path, $root='dropbox')
media($path, $root='dropbox')
The revisions method
revisions($path, array $params = array(), $root='dropbox')
Will return an array of revisions for a particular file or the revisions of files in a particular folder.

The restore method
restore($path, $revision, $root='dropbox')
Will roll a particular file back to a previous revision. Specify the revision by using the 'rev' hash that is returned when you make a call to the revisions method.

The search method
search($path, $query, array $params = array(), $root='dropbox')
Will search a particular path in your dropbox folders for any files that match the query.

The shares and media methods have replaced the link method.
shares($path, $root='dropbox')
media($path, $root='dropbox')
Both methods link to a file in dropbox the difference is that media links directly to the file and should be used for things link streaming. Shares creates a new link to a file and is more geared towards publicly displaying your content. Both calls also return an expiration date which indicate when the link will become invalid.

As always if you have any questions or problems post them in the comments but as it stands right now things seem to be pretty stable.

Sunday, October 2, 2011

Probably bad timing but here is the netflix API I promised.

Well I finally finished the netflix api I promised. Sorry for the delay it just took time to get motivated to finish it. Since I waited it probably doesn't have near the interest that it might have, had netflix not made the silly choices they did.

Anyway without further ado here is the netflix api.

Here is the github repo for it.

As with the other APIs you need to have a developer key for your application so head over to the netflix development docs to register an account and get an API key and secret. Put those values into a config so that they can be included when you initialize the library. Next download the api files and put them in your application directory.

Once they are in place you need to authenticate the API with a netflix account. We do this using OAuth. Checkout the included example controller for how to implement your request and access methods.

Use the oauth access token and token secret to make authenticated requests to the api. This token is a long lived token so you should only need to generate one per netflix user.

Now you can use every method in the library, but I have to warn you the Netflix API responses are XML and are complex. It is by far the most difficult API to work with as many of the requests require data from other requests in order to function properly. We will start with some of the most basic.

$this->netflix->search_title('Jurassic Park');

This command will do a search on the specified title which in this case is the amazing movie "Jurassic Park". No further parameters are needed but the returned data isn't all that useful.

Next we will look at the command to get data on the currently authenticated user.

$this->netflix->get_user();

This command is very important as it will return the ID netflix provides for each user. This ID can be used in future API calls for tasks like managing the users queue. Using this ID we can now make a call to:

$this->netflix->get_queues($id, $type);

This will return all of the titles in the users queue. Use the $type parameter to specify if you want the instant queue or the disc queue. One thing to really keep track of when you are working with a users queue is the returned etag. This is a value that is returned in the XML response that is used to maintain concurrency when managing the queue. Every call to a queue management function will have an etag in the response.

Say you want to add a title to your queue.

$this->netflix->add_queue_entry($id, 'disc', 'http://api.netflix.com/catalog/titles/movies/60002360', $etag);

This will add the title Jurassic Park to your disc queue provided to specified the correct $id for the user and the correct $etag value. There is an optional 5th parameter that lets you specify the position in the queue of the movie.

Now I know what you are thinking: 'Where the crap does he get Jurassic Park from that URL?' Well you have to get that data from another request like search_title. Like I said Netflix doesn't make it easy to use their API.

That is just a taste of what this library can do, it isn't the easiest API to work with unfortunately but it is functional and you can get around in it if you know what you are doing. Now because of that I highly recommend reading the Netflix API documentation you can find it here. It outlines all of the methods this library uses as well as all of the additional parameters you can specify for each call.

Here is a list of all of the currently available methods in the library.

$this->netflix->search_title($title, array $params = array());
$this->netflix->search_title_autocomplete($title);
$this->netflix->all_titles(array $params = array());
$this->netflix->get_title_details($id, $type, $season = false);
$this->netflix->get_title_similars($id, $type, $season = false, array $params = array());
$this->netflix->search_people($name, array $params = array());
$this->netflix->get_person_details($id);
$this->netflix->get_user($id = 'current');
$this->netflix->get_user_feeds($id, array $params = array());
$this->netflix->get_user_title_states($id, array $params = array());
$this->netflix->get_queues($id, $type = '', array $params = array());
$this->netflix->get_queue_state($id, $type, $state, $entry = '', array $params = array());
$this->netflix->remove_queue_entry($id, $type, $state, $entry);
$this->netflix->add_queue_entry($id, $type, $title_ref, $etag, $position = '1');
$this->netflix->get_rental_history($id, $instant_watched = false, array $params = array());
$this->netflix->get_title_rating($id, $title_refs, $predicted = false);
$this->netflix->set_title_rating($id, $title_ref, $rating, $ratingId = false);
$this->netflix->get_recommendations($id, array $params = array());

As always if you have any questions just leave a comment and I will do my best to help you out.

Friday, September 30, 2011

Posting to a facebook page as an admin AKA WHY IS THIS SO DIFFICULT!?

Tonight I have wasted the better part of 6 hours trying to figure out how to post to a facebook page I administer. Just thinking about that, it seems incredibly easy, after all, I wrote a twitter api class in about 30 minutes that sends out tweets. This should be cake.

It is not.

I had never delved too deeply into the facebook developers API, oddly enough called the "graph" api (don't understand that one Zucks). Though deeply you must delve in order to understand the convoluted and flat out missing parts of these docs. What should take an hour or two tops is complicated by navigating the insane twists and turns of this documentation. However I did ultimately surface and figure out what I needed to do which I will now share with you.

Step 1) Create a new application.

Really the only reason we do this is to get the app id and secret I wouldn't worry too much about the details here this thing is merely a face to our api calls. You most likely wont be promoting it too much if at all.

Step 2) Add your info to this link.

https://www.facebook.com/dialog/oauth?client_id=YOUR_APP_ID&redirect_uri=YOUR_URL&scope=manage_pages,publish_stream,offline_access&response_type=token

YOUR_APP_ID is obviously the id of the app you just created and YOUR_URL should be the url your app is associated with (urlencoded of course). Finally the thing that was missing from all the documentation and what I had to piece together is the scope parameter. Notice how I added the publish_stream portion to it which is missing from any references to the "Authentication" for pages. Why is it missing? Because we are authenticating the application with our account NOT the pages. Yep you heard right in order to write to a PAGE we have to authenticate an app for our personal facebook account. The offline_access value will make a long lived access token so you shouldn't have to worry about authenticating again.

Step 3) Add your info to this link.

https://graph.facebook.com/me/accounts?access_token=TOKEN_FROM_ABOVE

After you accept the application for your own account you will be redirected back to the url you specified with a shiny new access_token. Place the access token in the TOKEN_FROM_ABOVE position and make sure you do it quickly those things don't last long in OAuth 2.0.

Step 4) Copy what you need.

The link above should return a bunch of JSON showing all the pages you administer with access_tokens for each. I suggest you copy them all because they don't expire and you wont have to go through this crap again if you want to add the same functionality to another site you admin.

Step 5) Download the facebook SDK and add your stuff

Once you have downloaded the SDK (alter my code to fit your language) then copy your info as follows:

$facebook = new Facebook(array(
  'appId'  => 'YOUR_APP_ID',
  'secret' => 'YOUR_APP_SECRET',
));

try
{
  // Proceed knowing you have a logged in user who's authenticated.
  $fields = array (
    'message' => 'Hello World',
    'access_token' => urlencode('YOUR_PAGE_ACCESS_TOKEN')
  );

  $facebook->api('/me/feed', 'post', $fields);
}
catch(FacebookApiException $e)
{
  print_r($e);
  $user = null;
}


There are a few things to note here. The first is that you want to make sure you copy the page access token which is what you got from all that JSON in the previous step. The second is that you want the uri to be '/me/feed' because you are authenticating as the page.

Follow those steps and you should be able to post to your facebook pages without any trouble, at least until they decide to change something like they always do.

Sunday, August 28, 2011

Sparks flew and emotions ran high.

Considering I just found out about this project a few days ago, I will assume that some may not be familiar with Sparks. Sparks is a new command line tool for CodeIgniter. For those familiar with Drush for drupal this seems very similar except not quite as complex. Sparks basically takes all of the leg work out of installing third party add-ons to CI. With a single command you can install libraries and have them ready to use.

If you haven't already I suggest going to http://getsparks.org/ and checking out the sparks that are available. Also if you have some good libraries consider porting those to sparks so that others can enjoy them. I have created sparks for both the youtube and dropbox api libraries. Once you have sparks installed it will be as simple as installing the youtube or dropbox spark then loading the spark and loading the library.

I would really like to see this project get even more notoriety than it already has so check out sparks.

Youtube API Changes (It's for the better trust me)

This weekend I updated the youtube API. Now most methods accept an array of parameters instead of only specifying the start and count. To clarify $start and $count are out, long live array()!

To give you an example of what I am talking about here is how a called to getUserUploads used to look if you were showing 10 videos per page and were on the second page.

$this->youtube->getUserUploads('default', 11, 10);

This is how the call will looks now.

$this->youtube->getUserUploads('default', array('start-index'=>11, 'max-results'=>10));

This gives way more flexibility, we can now use any of the parameters outlined here. Now using things like the alt parameter you could specify your return data as JSON for easier parsing and usage if XML isn't your thing.

Look through that list and see if any query parameters catch your eye but going forward this will be how to add additional parameters to your api calls.

Thursday, July 21, 2011

API Library Suggestions

My plans are to continue developing API libraries for CI in my free time. One thing I am going to do is combine the YouTube and Dropbox libraries into the same github repo since they do share some common code in oauth_helper. That would mean only having to update things in one place as opposed to several in the current repo structure.

That being said, I am starting to run out of decent API ideas. I think the next one I will tackle is the NetFlix API but beyond that I am really not sure.

What API libraries would you like to see implemented in CodeIgniter?

Tuesday, July 19, 2011

CodeIgniter Dropbox API.

Well folks, I have done it again. You guys seem to enjoy my YouTube API and now I officially present my CodeIgniter Dropbox API.

Here is the github repo for it.

Now for some documentation.

As with the YouTube API the first step in getting this sucker setup is getting a developer key by visiting https://www.dropbox.com/developers/apps. There you will setup your new application and they will give you an 'App Key' and 'App Secret'. Put these values into a config file so that we can reference them later. Now download the API files from my github repository and place them into your application folder.

  1. My trusty oauth_helper.php file belongs in the helpers directory
  2. dropbox.php is the API file and belongs in the libraries directory

Once they are in place we need to authenticate the API with your dropbox account. We do this using OAuth so you will need to create a controller and add the following methods.

public function request_dropbox()
{
   $params['key'] = $this->config->item('dropbox_key');
   $params['secret'] = $this->config->item('dropbox_secret');
       
   $this->load->library('dropbox', $params);
   $data = $this->dropbox->get_request_token(site_url("welcome/access_dropbox"));
   $this->session->set_userdata('token_secret', $data['token_secret']);
   redirect($data['redirect']);
}
    
public function access_dropbox()
{
   $params['key'] = $this->config->item('dropbox_key');
   $params['secret'] = $this->config->item('dropbox_secret');
       
   $this->load->library('dropbox', $params);
       
   $oauth = $this->dropbox->get_access_token($this->session->userdata('token_secret'));
       
   $this->_store_in_db($oauth['oauth_token']);
   $this->_store_in_db($oauth['oauth_token_secret']);
}

Now a few lines there need some explanation. In request_dropbox my get_request_token call should have a URL to the access_dropbox method right below. Basically we want the dropbox site to redirect there once the request step is finished. On the next line we store the token secret because we will need that in the access_dropbox method later. Finally we redirect to the provided redirect (this will take the user to the dropbox site).

In the access_dropbox method not too much is different. Make the get_access_token call and pass in the token secret. You should get back an array with an 'oauth_token' value and an 'oauth_token_secret' value. You should store those with your user as they are what you will use to make authenticated request on that users behalf.

Provided those went well we can begin actually fiddling with the API (it should be noted that most calls from the API will return PHP objects as a response). Here is an example of how to load the API with all of the data we have generated.

$params['key'] = $this->config->item('dropbox_key');    
$params['secret'] = $this->config->item('dropbox_secret');
$params['access'] = array('oauth_token'=>urlencode($this->_get_from_db()),
                          'oauth_token_secret'=>urlencode($this->_get_from_db()));
       
$this->load->library('dropbox', $params);

Note that the access parameter is an array with keys 'oauth_token' and 'oauth_token_secret' and that the value of each of these keys is urlencoded. Make sure you mimic this same layout otherwise you risk running into issues with your authenication. Finally load the library with the parameters.

Once the library is successfully loaded you can now make some calls. There are several to choose from the simplest is 'account', so calling:

$this->dropbox->account();

Should return a php object with various account data in it. Most of the methods return a php object there are only two that do not.

$this->dropbox->thumbnail($destination, $path, $size='small', $format='JPEG', $root='dropbox')
$this->dropbox->get($destination, $path, $root='dropbox')

The reason these don't return an object is because they actually write a file to the $destination path. The only time these will return anything useful is if an error has occurred.

Another useful method is the add method which will add a file to your dropbox.

$this->dropbox->add($dbpath, $filepath, $root='dropbox');

Here $dbpath is the path within your dropbox (including file name) where the file will go, and $filepath is the path to the file on your server. Unless you know what the $root parameter is for I would just leave it alone.

To finish things off here is the list of the remaining methods. Most are simply for manipulating files in your dropbox folder a few are for getting information on files in your dropbox.

$this->dropbox->metadata($path, $root='dropbox');
$this->dropbox->link($path)
$this->dropbox->copy($from, $to, $root='dropbox');
$this->dropbox->create_folder($path, $root='dropbox');
$this->dropbox->delete($path, $root='dropbox');
$this->dropbox->move($from, $to, $root='dropbox');

That's it every one of those should be decently documented in the code. I should point out that I am not doing anything specatular with CodeIgniter so the library should work with 2.0 and the old 1.7.2. I hope you guys enjoy, it was a lot of fun writing it. Let me know in the comments or post on the github repo if you have any problems.

[EDIT] Here is the link to the Dropbox web api: https://www.dropbox.com/developers/web_docs

Saturday, June 25, 2011

A CMS that doesn't suck. (Or maybe it does I dunno)

In my time as a web developer. (10 years or so) I have worked with a multitude of frameworks and CMSs. Some nice, many not so much.

I could talk at length about all the different CMSs and frameworks I have dealt with and why they do or don't suck. Instead though I will focus on 3 major ones that are probably the industry leaders.

  1. Drupal. I know you've heard of it, who hasn't? It is capable of maintaining some massive sites, and seems to do so without breaking a sweat. However it is incredibly complicated and seems to have a problem with modules being behind the core release cycle. Let's face it the core drupal install is pretty weak. You have to have third party modules to glean the true power of drupal and so far most of them are not ready for the current release (which has been out for several months).
  2. ExpressionEngine. This nice CMS is built off CodeIgniter which makes it incredibly easy to develop for. The 'Channel' implementation is very easy to understand and use, and I love how there are no stock templates. Yet unlike the others in this list it is not free. Also checkout it's database structure, what a mess. Basically the EE db architect guaranteed that EE could never be used for any kind of major website. In other words: No significant scalability without heavy caching and beefy database servers. Also it has been my experience that if you are using a part of EE that doesn't involve channels it becomes an immense pain in the ass.
  3. WordPress. Lovely admin features make this CMS unbelievably easy to manage and the simplicity lets anyone with a computer generate content. Lets be honest though this is still very much a blogging tool, yeah sure you can hack at it and get it to be some kind of non-blog site but that isn't what it was really designed to do. Also as with drupal finding nice working plugins can sometimes be a challenge.

That is my quick run down of 3 major CMSs on the market and some of their benefits and flaws. That being said what am I gonna do about it. Well my plan is to shove another CMS down your throat. One that hopefully will take the benefits of all of the ones listed above and fix all of their short comings. 

With that I introduce Feed Forge. https://github.com/jimdoescode/feedforge

This is a CMS I am working on (built off CodeIgniter of course). My goal with this project is to utilize the nice Channel setup that EE has with templates, yet still keep the nice database structure of drupal, and have an incredibly easy to use admin feature like wordpress. I do want to mention that this is still very much in an Alpha stage with a ton of work left to do. As the project matures though I hope it will garner more attention for it's elegance and ease of use.

I just want to say this is more a sneak peak at the project if you are interested download the source and play around with it but I warn you this is not a finished product and is absolutely not ready for a live website.

Sunday, May 29, 2011

Git Support in Komodo Edit.

Been awhile since I posted in here. Thanks for sticking around.

First here is the link to the GitHub Project

I have some great news. I have finally been getting around to updating all of my code and getting it into public source control, namely GitHub. The other day I moved over the youtube api files (as well as updated them). Check the original blog post for links to that repo if you are interested.

All this updating and source control got me thinking that I should make some Git Komodo Edit tools just like the subversion tools. This task wasn't too difficult as git and svn aren't that different from each other. I will outline them for you.

First is "Git Add All New". It's purpose is to add any new files you created to your repository. It is worth noting that adding != committing. When you add a file to git you are simply telling it to put that file into source control on the next commit. This is exactly the same way the subversion control works.

Next is "Git Checkout" which as you might expect is for checking out (git calls it cloning) a repository. One thing to note here, you need to have a komodo project already open otherwise the files will be checked out into your root directory instead of a projects root directory.

"Git Commit" is what makes all the magic happen it will commit all of your changed files and add any new files to the repository.

"Git Diff" will diff the currently viewed file with the version of that file stored in the repository. The output is the standard console diff format so if you aren't real familiar with that you might have some trouble spotting changes.

"Git Init" will create a new empty repository in the root of the currently active project.

"Git Push Remote" lets you push your local repository changes out to a remote repo like GitHub.

Finally there is "Git Update" which updates your project files with the most current version stored in the repository.

While I was working on the "Git Diff" tool I realized that the same tool could be created for my subversion tools so I went ahead and took the liberty of creating that.

"Subversion Diff" diffs the currently viewed file with the version that is stored in the repository. Again it uses the standard console diff syntax.

There you have it all those tools seem to work correctly for me if you have any difficulties let me know in the comments.

Here is the link to the GitHub Project

As a side note since this stuff is now in GitHub I wont be hosting it in drop box.

Tuesday, January 18, 2011

CodeIgniter and Caching, a love hate relationship

As I am sure you have realized by now I am a huge fan of CodeIgniter. I find it amazingly easy to work with and feel that it really stays out of my way when I need it to. That being said one of its few weak spots is caching. Lets be clear I am talking about page caching now query caching which has its own short coming but in general can be useful.

Page caching in CodeIgniter is an all or nothing affair. Meaning that you either cache a full page or you don't cache anything. This might have been useful in the 90's when websites were far less interactive than they are today. However in the modern age of web design pages often have dynamic content that changes on a per user basis. For instance showing a users name at the top of a page when they are logged in, or providing an administration option if someone has the proper security clearance. These things would cause a page to look different from one user to the next. This simply isn't possible with the default implementation of caching, the last thing we need is having someone without clearance to be able to know more about our sites administration area.

Many people have written caching libraries for CI and I am sure there are some good ones. All of them lack the shear simplicity of CI's implementation, so here is my stab at it.

The name of this library is called scache for s(imple)cache it has one relatively small library file and a config file. If you would prefer you can combine the config file with CI's config file.

This library lets you cache whatever you need whether that be a full page or a small page segment. You define the unique key used to retrieve the cache file.

The library methods are as follows:


$this->scache->clear($key);
$this->scache->read($key);
$this->scache->write($key);


The clear method should generally be used to clear a cache file if you cannot wait for it to expire normally. Say for example you allow commenting on a page you obviously don't want your users to have to wait several minutes before they can view what they posted. Speaking of expiration, remember that config file I told you about? It only has a single line which defines how long to cache a file in minutes here are its contents:


$config['cache_expiration'] = 1;


Let's see this sucker in action now.


if(!$cache = $this->scache->read($key))
{
    //Build your view data array here
    //
    //
    //
    $cache = $this->load->view('page_segment', $data, true);
    $this->scache->write($key, $cache);
}
$this->load->view('full_page', array('segment'=>$cache));


Somethings to keep in mind looking at this implementation:
  1. The key value can be whatever you want, as long as it is always unique to that particular page segment. The key is how the library will name and find the cache file so it needs to be unique.
  2. In this setup I have a wrapper called "full_page". This file would include things like the main nav the logo the footer etc. Where as "page_segment" is only meant to contain something that will remain static like an 'About Us' paragraph or something.
  3. Remember the data contained in "page_segment" should not change between users or at least not change much.
Below is a link to a zip of both the library and the config file. Please let me know if you have any issues.

http://dl.dropbox.com/u/13081549/Scache.zip

Tuesday, January 4, 2011

Some CodeIgniter Constants

As a CI dev I am sure you have seen these before, and they are pretty useful once defined. The problem is that the CI docs don't really tell you what they are, and their names are only descriptive once you know what they do. To the new guy these may seem to have some kind of mystical powers.

Here is a link to the docs that outlines the constants listed below.
http://codeigniter.com/user_guide/general/reserved_names.html

The first constant is APPPATH (thats 3 'P's ). This variable is initialized in the root index.php file and is the path to the application folder of your CI installation. Pretty straight forward.

BASEPATH is the path to the system folder of you CI application. This is defined in the root index.php file.

CI_VERSION as I am sure it is obvious, is the version of CodeIgniter you are running.

DIR_READ_MODE, DIR_WRITE_MODE these values are used when dealing with files in CI. Namely when checking and setting read write modes of directories. These values reside in the constants config file of CI.


EXT refers to a file extension which would typically be ".php". This is defined in the root index.php file.

FCPATH is the full server path to the root index.php file. This is defined in the root index.php file.
FILE_READ_MODE, FILE_WRITE_MODE same as DIR_READ_MODE, DIR_WRITE_MODE except these deal with files instead of directories.

Next are a bunch of FOPEN constants which as the name implies deal with using fopen and popen in CI. These also reside in the constants config file if you want to take a peak at them.

SELF refers to the name of the root index.php file and usually has a value of "index.php". This is defined in the root index.php file.

Really the only constants that would be used with any kind of regularity are APPPATH and BASEPATH. The others are more involved in the internals of CI, but I am sure they are useful in some circumstances.

Hopefully that gives you a better idea of what these suckers do.