tag:blogger.com,1999:blog-1915635645120511662024-03-23T06:13:24.482-04:00Programs From My Head//Watch as I wrestle with code.JimDoesCodehttp://www.blogger.com/profile/12997299334521011106noreply@blogger.comBlogger34125tag:blogger.com,1999:blog-191563564512051166.post-46189669225235073952012-10-11T16:26:00.001-04:002012-10-11T16:26:11.250-04:00PHP from the command line using Clip CLI framework<p>Just wanted to post about my latest invention. It's called <a href="https://github.com/jimdoescode/clip">Clip</a> and it's a very simple framework for making PHP CLI applications. I recently got a new job and have been working a lot with several PHP console commands. The problem I found was that there wasn't a good stand alone framework I could use to make creating and editing these commands easy.</p>
<p>Sure there are a lot of great frameworks with some kind of console component to them (Symfony, Yii, Zend, etc.) but I wanted something where the console was the sole focus. So partially for fun and partially to scratch my perceived itch I came up with Clip.</p>
<p>Clip IMO turned out pretty good. It's a single file that comes in at ~130 LOC (as of right now) and packs a few really nice features. First and foremost it's dead simple to use. All you need to do is create a PHP file in the commands directory. In that file you will add a class that shares the same name as the file and implements the Clip Command interface. Here is an example using a file named "Example.php":</p>
<pre class="brush: php">class Example implements \Clip\Command
{
public function run(array $params)
{
/* Do command stuff */
}
public function help()
{
echo 'This is some example help text';
}
}
</pre>
<p>That's it. Now you have a PHP command that can be run via the console. To execute that command all you need to do is open a terminal and type:</p>
<pre class="brush: shell">$ clip Example</pre>
<p>Say you need to pass your command some additional parameters. Those can be passed by just specifying them at the end. They are passed to the run method as the $params array. If the parameters are specified as key=value then $params will be an associative array. For example:</p>
<pre class="brush: shell">$ clip Example test foo=bar</pre>
<pre class="brush: php">$params == array('test', 'foo' => 'bar');</pre>
<p>Finally one of the best parts about Clip is its powerful configuration class. You can easily create and work with config files. To create a new configuration file all you do is add a new PHP file to the "config" directory. In that file you will return an associative array of parameters. For example you could make a config file called "myconfig.php" which looked like this:</p>
<pre class="brush: php">return array(
'param1' => 'foo',
'param2' => 'bar'
);</pre>
<p>Now that the config file is setup to access it in your code you would call the config class like so:</p>
<pre class="brush: php">\Clip\Config::myconfig('param1');</pre>
<p>Which will return the value 'foo' from the config file. If you want to fetch more than one parameter you can specify them and the config class will return an array of the values like so:</p>
<pre class="brush: php">\Clip\Config::myconfig('param1', 'param2');</pre>
<p>If you need to fetch an entire config file as an array you would call the config class without any parameters:</p>
<pre class="brush: php">\Clip\Config::myconfig();</pre>
<p>Take note that the static function being called exactly matches the name of the config file we created (minus the PHP file extension). That will let you create as many config files as you would like.</p>
<p>That is pretty much all there is to Clip it's very simple and easy to use. Check it out by following the link to the repo below.</p>
<br/>
<a href="https://github.com/jimdoescode/clip">Here is the Repo</a>
<br/>JimDoesCodehttp://www.blogger.com/profile/12997299334521011106noreply@blogger.com2tag:blogger.com,1999:blog-191563564512051166.post-51119289256564795722012-07-24T02:35:00.000-04:002012-07-24T02:35:04.367-04:00Ported the CI YouTube library to plain old PHP<p>I finally got around to porting my CodeIgniter YouTube API Library to regular PHP. There honestly aren't that many CI dependencies so it was a fairly easy library to port.</p>
<p>I changed how the constructor is setup so it's a little more descriptive when being instantiated. All of the API calls remained the same so you can checkout the CI library for example calls to make. I included some example code on how to use the API. The example files are index.php and authorize.php they demonstrate how to authenticate with YouTube then make calls. Let me know if you have any issues or questions.</p>
<p>The GitHub repos is: <a href="https://github.com/jimdoescode/Zendless-PHP-YouTube-API" target="_blank">https://github.com/jimdoescode/Zendless-PHP-YouTube-API</a></p>JimDoesCodehttp://www.blogger.com/profile/12997299334521011106noreply@blogger.com9tag:blogger.com,1999:blog-191563564512051166.post-72379205919849584282012-03-15T01:07:00.001-04:002012-03-15T01:26:39.264-04:00Don't Trust the Web of Trust (WOT)<a href="http://www.mywot.com">Web of Trust</a> is a web site dedicated to informing its users about bad web sites that could potentially cause problems. Whether that be spammers, potential malware, or any other danger that lurks on the web. Just one problem though, it doesn't actually work. Well I shouldn't say that, it works, kind of in the same way the A-Bomb works.
<br/><br/>
Allow me to provide some back story.
<br/><br/>
I have been working on a site for doing code reviews called <a href="http://codetique.com">Codetique.com</a>. I purchased the domain through my web host in January of 2011. I held the domain for about a year and finally started working on the actual application at the beginning of 2012. I have done a few minor releases and today came to discover from a helpful redditor, that my site has a terrible reputation with Web of Trust. Which was a bummer but considering I had never heard of it before today I figured it would be fairly easy to fix or ignore. Then several people made similar comments so clearly this WOT reputation holds some merit.
<br/><br/>
It seems that around 2009 the domain was accused of spamming in some variety and blacklisted by a "third-party trusted source". All of that is probably true, I didn't own the domain at that time and I have no way of knowing who did, it was available when I purchased it. Anyway I own the domain now so I created an account on WOT and setup my site to prove that I owned it. If you check out the reputation page for my domain the "third-party trusted source" link doesn't even work!? So not only does your reputation not change even after 3 years but the "third-party trusted sources" that WOT uses don't exist anymore. Yet this tool that supposedly millions of people are blissfully using is passing judgements on domains without any kind of current references.
<br/><br/>
The fact that WOT is using 3 year old sources as Gospel is bad enough, but I can't get any of the past bad reviewers to come back and alter their review. It was 3 years ago they have probably moved on to other things. I did file for a new review and got one person to check it out and leave good feedback but the WOT algorithm is too dumb to properly weigh one current review more than several past ones so the reputation of Codetique.com of WOT is still bad.
<br/><br/>
If the algorithm doesn't work properly for improving reputation I would be very surprised if it worked for hurting reputation either. Meaning if hypothetically Facebook were to go bankrupt in a few years (it's a stretch but stranger things have happened). A malicious site could be put in it's place and WOT would give it an amazing rating and no matter how many times it was marked as bad it would probably still have an amazing rating because of all the prior entries that marked it as good are weighted just as heavily as any current entries that mark it as bad.
<br/><br/>
Bottom line if you are using WOT tools you are a fool. Not only are you letting yourself be frightened away from potentially good sites but you are buying into the mind set that nothing on the web changes.
<br/><br/>
I think the most annoying thing of this whole situation is that there is no one to contact directly to have issues like the non-existing "third-party trusted source" fixed. I just wonder how many other great sites have poor reputations because WOT isn't smart enough to realize that domains can change in an instant.
<br/><br/>
If you want to help me out you can give my site a positive rating at <a href="http://www.mywot.com/en/scorecard/codetique.com">http://www.mywot.com/en/scorecard/codetique.com</a>. But an even better thing to do would be to stop using their tools and tell anyone who does use them what a joke they actually are.JimDoesCodehttp://www.blogger.com/profile/12997299334521011106noreply@blogger.com46tag:blogger.com,1999:blog-191563564512051166.post-22423761741289203312012-02-20T03:56:00.000-05:002012-02-20T16:21:56.633-05:00Keep your CI instances up to date with this handy libIt has been awhile since I last posted on my blog and for that I apologize. I have officially become a freelance developers (which makes that donate button on the right a bit more important). It has given me time to work on some personal ventures which I will announce here in the coming months. Bottom line I can finally write the code I want to write and hopefully can continue to do so for awhile.<br/>
<br/>
Given my free time I have started work on Feed Forge again (which you should check out if you haven't yet) and I decided that I wanted to provide the ability to automatically update Feed Forge without having to bother with all the git commands. The solution for this was to utilize GitHub as a remote update server and write a CodeIgniter library to perform the updates. The library basically keeps a record of the current commit that the files are on, then when the update method is called it contacts GitHub to see if there is any change between the commits. If there isn't it does nothing. If there is then it will pull down and extract a zip file of the new repo from GitHub and compare the two commits removing or replacing any files locally that were removed, added, or modified in the latest GitHub commit. The really cool thing about the library is that it doesn't require a Git instance on the local server. Meaning it should run on just about any *nix based server running PHP.<br/>
<br/>
Let's get down to brass tax here.<br/>
<br/>
The library only has two methods.<br/>
<pre class="brush: php">$this->github_updater->has_update();</pre>
This method indicates if there is an update available. It will return true if there is and false if there isn't.<br/>
<br/>
<pre class="brush: php">$this->github_updater->update();</pre>
This method will actually perform an update if one is available. It will return true on success or false on failure.<br/>
<br/>
And that is all there is to the library. However it also has a companion configuration file. The config file is vitally important to how the library works and needs to be setup properly. I will go over the different options.<br/><br/>
<strong>github_user</strong> - [Required] This is the user name on GitHub of the account that the repo resides in.<br/>
<strong>github_repo</strong> - [Required] This is the name of the repository as it is on GitHub.<br/>
<strong>github_branch</strong> - [Required] This is the branch that you wish to perform updates from.<br/>
<strong>current_commit</strong> - [Required] This is the current commit the local files are set to. Note that you should only need to set this initially. It will be altered by the library as updates are performed.<br/>
<strong>ignored_files</strong> - This is a list of files that you do not want updated. Usually this would be config files that might be different on other servers, but you can specify anything in here.<br/>
<strong>clean_update_files</strong> - This is a flag to indicate if the library should clean up the zip file that it downloads and extracts from GitHub. This can usually be set to true.<br/><br/>
Here is an example of the config file I was using to test with:<br/>
<pre class="brush: php"><?php if ( ! defined('BASEPATH')) exit('No direct script access allowed');
/**
* The user name of the git hub user who owns the repo
*/
$config['github_user'] = 'jimdoescode';
/**
* The repo on GitHub we will be updating from
*/
$config['github_repo'] = 'Test-Auto-Updater';
/**
* The branch to update from
*/
$config['github_branch'] = 'master';
/**
* The current commit the files are on.
*
* NOTE: You should only need to set this initially it will be
* automatically set by the library after subsequent updates.
*/
$config['current_commit'] = 'd2605907262c932035ec16bdd2716bcd163622bb';
/**
* A list of files to never perform an update on
*/
$config['ignored_files'] = array('application/config/config.php',
'application/config/github_updater.php',
'application/libraries/Github_updater.php');
/**
* Flag to indicate if the downloaded and extracted update files
* should be removed
*/
$config['clean_update_files'] = true;</pre><br/><br/>
The library is actually pretty simple and should work well in most circumstances, but I do need to stress that you should always make a backup prior to any upgrade. If used improperly this library is capable of really messing up your CodeIgniter instance so make sure you backup before you update. Also this library does not do any kind of database updates if you want those you need to do them yourself.<br/><br/>
<a href="https://github.com/jimdoescode/CodeIgniter-GitHub-Updater">Here is the link to the github repo.</a><br/><br/>
Well enjoy and if you like this library please consider donating and as always if you have issues let me know in the comments.<br/><br/>
<strong>[EDIT]</strong> I just want to point out that updates can only be applied to files in the webroot. Also the library only works with relative paths so if the GitHub repo references a file in application/controllers then the library will act on the file in application/controllers of the local webroot. This means that your GitHub repo has to be a complete CodeIgniter instance.<br/><br/>
<strong>[EDIT 2]</strong> I updated the library to allow more general ignore statements. Meaning that you can now specify entire directories to be ignored or certain file names that should be ignored. You can even specify file extensions to ignore.<br/><br/>
<strong>[EDIT 3]</strong> Currently the library only works with public github repos. There is no authentication needed for those. If there is demand I can add support for authentication and private repos. You would also have to provide a private repo for me to test with though.JimDoesCodehttp://www.blogger.com/profile/12997299334521011106noreply@blogger.com3tag:blogger.com,1999:blog-191563564512051166.post-4388087747625924872012-01-27T14:42:00.000-05:002012-01-27T14:42:52.870-05:00Feed Forge in the real worldI have quit my job and started freelancing. This meant that I needed a personal site to showcase the work I have done and what I am capable of. Unfortunately jimsaunders.com has been taken for some time, so I had to settle for jimsaunders.net. My original thinking was that this would just be a site with flat HTML 5 pages, but after some consideration I decided I wanted to throw the CMS I have been developing at it to shake out any issues.<br />
<br />
Being an untested CMS obviously there were lots of issues, mainly centered around getting the installer to boot strap itself. Eventually I was able to clean things up and get everything working properly. Now I might be a little biased but Feed Forge is a pretty decent little CMS. Every problem I have come across I feel was solved in very simple and elegant ways. <br />
<br />
Don't get me wrong no one else should be using it on a production site just yet, but hopefully if/when you do, you will see how sweet it really is.<br />
<br />
If you are interested the code can be found at <a href="http://github.com/jimdoescode/feedforge">my GitHub repo</a><br />
<br />
Also if you want to see it in action live on my site visit <a href="http://jimsaunders.net">jimsaunders.net</a><br />
<br />
Play around with it and let me know if you come across any issues or would like to see a new feature.JimDoesCodehttp://www.blogger.com/profile/12997299334521011106noreply@blogger.com6tag:blogger.com,1999:blog-191563564512051166.post-60558320244197391052012-01-07T17:36:00.000-05:002012-01-07T18:13:14.388-05:00Dropbox API Library changes<p>
Just wanted to let you guys know about some small changes that I made to the dropbox library. I received an email from someone using the library. He wasn't having any issues really but there was having a minor annoyance. That annoyance was having to define the sandbox root for each method call.
</p>
<p>
He made a very good point, so I added a const variable at the top of the library called "DEFAULT_ROOT". All methods will use that value as the default root, but you still have the flexibility of specifying the root on each method call should you need it.
</p>
<p>
Check out the updated library at the <a href="https://github.com/jimdoescode/CodeIgniter-Dropbox-API-Library">github repo</a>.
</p>
<p>
I have been neglecting this blog lately. My new years resolution is to be more vocal about what I am working on and hopefully help you guys out.
</p>JimDoesCodehttp://www.blogger.com/profile/12997299334521011106noreply@blogger.com3tag:blogger.com,1999:blog-191563564512051166.post-78373698286890150942011-11-16T23:57:00.001-05:002013-03-18T17:59:22.006-04:00Trials and tribulations with HTML5 Canvas on Android<p>You may not be aware but I recently released a mobile web app called <a href="http://leftanote.com">leftanote.com</a>. 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: <a href="http://jquery.com">jquery</a>, <a href="http://jquerymobile.com">jquerymobile</a>, <a href="http://jimdoescode.github.com/jqScribble/">jqScribble</a> (my custom canvas drawing tool), as well as some other things I will get into shortly.<br/><br/>
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.<br/><br/>
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".<br/><br/>
After some obvious ranting and Google cursing, I came across <a href="http://forum.xda-developers.com/showthread.php?t=1251575">this post</a> 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 <a href="https://github.com/owencm/js-steg/blob/master/jpg_encoder.js">here</a> (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.
</p>
<p>Here is my code:</p>
<pre class="brush: js">
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;
}
</pre>
<p>
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.
<br/><br/>
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.
<br/><br/>
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.
<br/><br/>
1) Download a JPEG Encoder.<br/>
2) Add in your own custom toDataURL handler which will use the Encoder if the original toDataURL fails.
<br/><br/>
The drawing tool works like a charm, and saving images is still reasonably fast. Although I am dealing with fairly small images.
</p>JimDoesCodehttp://www.blogger.com/profile/12997299334521011106noreply@blogger.com22tag:blogger.com,1999:blog-191563564512051166.post-17190486852822329332011-10-12T11:05:00.000-04:002011-11-17T00:33:49.952-05:00Dropbox Updates Have LandedJust 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.
<br/><br/>
<a href="https://github.com/jimdoescode/CodeIgniter-Dropbox-API-Library">Here is the Github Repo</a>
<br/><br/>
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:
<pre class="brush: php">
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')
</pre>
<strong>The revisions method</strong>
<pre class="brush: php">
revisions($path, array $params = array(), $root='dropbox')
</pre>
Will return an array of revisions for a particular file or the revisions of files in a particular folder.
<br/><br/>
<strong>The restore method</strong>
<pre class="brush: php">
restore($path, $revision, $root='dropbox')
</pre>
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.
<br/><br/>
<strong>The search method</strong>
<pre class="brush: php">
search($path, $query, array $params = array(), $root='dropbox')
</pre>
Will search a particular path in your dropbox folders for any files that match the query.
<br/><br/>
<strong>The shares and media methods have replaced the link method.</strong>
<pre class="brush: php">
shares($path, $root='dropbox')
media($path, $root='dropbox')
</pre>
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.
<br/><br/>
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.
<br/><br/>JimDoesCodehttp://www.blogger.com/profile/12997299334521011106noreply@blogger.com12tag:blogger.com,1999:blog-191563564512051166.post-33106004831386246492011-10-02T20:11:00.000-04:002011-10-02T20:43:51.625-04:00Probably 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.<br />
<br />
Anyway without further ado here is the netflix api.<br />
<br />
<a href="https://github.com/jimdoescode/CodeIgniter-Netflix-API-Library">Here is the github repo for it.</a> <br />
<br />
As with the other APIs you need to have a developer key for your application so head over to <a href="http://developer.netflix.com/">the netflix development docs</a> 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. <br />
<br />
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.<br />
<br />
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.<br />
<br />
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.<br />
<br />
<pre class="brush: php">$this->netflix->search_title('Jurassic Park');
</pre><br />
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.<br />
<br />
Next we will look at the command to get data on the currently authenticated user. <br />
<br />
<pre class="brush: php">$this->netflix->get_user();
</pre><br />
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:<br />
<br />
<pre class="brush: php">$this->netflix->get_queues($id, $type);
</pre><br />
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. <br />
<br />
Say you want to add a title to your queue. <br />
<br />
<pre class="brush: php">$this->netflix->add_queue_entry($id, 'disc', 'http://api.netflix.com/catalog/titles/movies/60002360', $etag);
</pre><br />
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. <br />
<br />
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. <br />
<br />
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 <strong>I highly recommend reading the Netflix API documentation</strong> you can find it <a href="developer.netflix.com/docs/REST_API_Reference">here.</a> It outlines all of the methods this library uses as well as all of the additional parameters you can specify for each call.<br />
<br />
Here is a list of all of the currently available methods in the library.<br/><br/>
<pre class="brush: php">
$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());
</pre><br/>
As always if you have any questions just leave a comment and I will do my best to help you out.JimDoesCodehttp://www.blogger.com/profile/12997299334521011106noreply@blogger.com5tag:blogger.com,1999:blog-191563564512051166.post-63863632711817440992011-09-30T03:19:00.001-04:002011-09-30T04:17:14.491-04:00Posting 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. <br />
<br />
It is not.<br />
<br />
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.<br />
<br />
<strong>Step 1)</strong> Create a new application.<br />
<br />
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.<br />
<br />
<strong>Step 2)</strong> Add your info to this link.<br />
<br />
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<br />
<br />
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.<br />
<br />
<strong>Step 3)</strong> Add your info to this link.<br />
<br />
https://graph.facebook.com/me/accounts?access_token=TOKEN_FROM_ABOVE<br />
<br />
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.<br />
<br />
<strong>Step 4)</strong> Copy what you need.<br />
<br />
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.<br />
<br />
<strong>Step 5)</strong> Download the facebook SDK and add your stuff<br />
<br />
Once you have downloaded the SDK (alter my code to fit your language) then copy your info as follows: <br />
<br />
<pre class="brush: php">$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;
}
</pre>
<br />
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. <br />
<br />
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.JimDoesCodehttp://www.blogger.com/profile/12997299334521011106noreply@blogger.com0tag:blogger.com,1999:blog-191563564512051166.post-10188880885362044122011-08-28T22:31:00.000-04:002011-08-28T22:31:46.283-04:00Sparks 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.<br />
<br />
If you haven't already I suggest going to <a href="http://getsparks.org/">http://getsparks.org/</a> 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 <a href="http://getsparks.org/packages/youtube/versions/HEAD/show">youtube</a> and <a href="http://getsparks.org/packages/dropbox/versions/HEAD/show">dropbox</a> 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.<br />
<br />
I would really like to see this project get even more notoriety than it already has so check out <a href="http://getsparks.org/">sparks</a>.JimDoesCodehttp://www.blogger.com/profile/12997299334521011106noreply@blogger.com0tag:blogger.com,1999:blog-191563564512051166.post-89508928727616537542011-08-28T20:17:00.000-04:002011-08-28T20:17:03.867-04:00Youtube 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()!<br />
<br />
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.<br />
<br />
<pre class="brush: php">$this->youtube->getUserUploads('default', 11, 10);</pre><br />
This is how the call will looks now.<br />
<br />
<pre class="brush: php">$this->youtube->getUserUploads('default', array('start-index'=>11, 'max-results'=>10));</pre><br />
This gives way more flexibility, we can now use any of the parameters outlined <a href="http://code.google.com/apis/youtube/2.0/reference.html#Query_parameter_definitions">here</a>. 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.<br />
<br />
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.<br />
JimDoesCodehttp://www.blogger.com/profile/12997299334521011106noreply@blogger.com0tag:blogger.com,1999:blog-191563564512051166.post-70484772286648374012011-07-21T09:38:00.000-04:002011-07-21T09:38:37.887-04:00API Library SuggestionsMy 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. <br />
<br />
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. <br />
<br />
What API libraries would you like to see implemented in CodeIgniter?JimDoesCodehttp://www.blogger.com/profile/12997299334521011106noreply@blogger.com1tag:blogger.com,1999:blog-191563564512051166.post-86677831701512987782011-07-19T02:07:00.000-04:002011-07-22T10:46:18.713-04:00CodeIgniter 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. <br />
<br />
<a href="https://github.com/jimdoescode/CodeIgniter-Dropbox-API-Library">Here is the github repo for it.</a><br />
<br />
Now for some documentation.<br />
<br />
As with the YouTube API the first step in getting this sucker setup is getting a developer key by visiting <a href="https://www.dropbox.com/developers/apps">https://www.dropbox.com/developers/apps</a>. 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.<br />
<br />
<ol><li>My trusty oauth_helper.php file belongs in the helpers directory</li>
<li>dropbox.php is the API file and belongs in the libraries directory</li>
</ol><br />
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.<br />
<br />
<pre class="brush: php" style="">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']);
}
</pre><br />
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).<br />
<br />
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.<br />
<br />
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.<br />
<br />
<pre class="brush: php">$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);
</pre><br />
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.<br />
<br />
Once the library is successfully loaded you can now make some calls. There are several to choose from the simplest is 'account', so calling:<br />
<br />
<pre class="brush: php">$this->dropbox->account();
</pre><br />
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.<br />
<br />
<pre class="brush: php">$this->dropbox->thumbnail($destination, $path, $size='small', $format='JPEG', $root='dropbox')
$this->dropbox->get($destination, $path, $root='dropbox')
</pre><br />
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.<br />
<br />
Another useful method is the add method which will add a file to your dropbox.<br />
<br />
<pre class="brush: php">$this->dropbox->add($dbpath, $filepath, $root='dropbox');
</pre><br />
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.<br />
<br />
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.<br />
<br />
<pre class="brush: php">$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');
</pre><br />
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.<br />
<br />
<strong>[EDIT]</strong> Here is the link to the Dropbox web api: <a href="https://www.dropbox.com/developers/web_docs">https://www.dropbox.com/developers/web_docs</a>JimDoesCodehttp://www.blogger.com/profile/12997299334521011106noreply@blogger.com184tag:blogger.com,1999:blog-191563564512051166.post-29845116269466415422011-06-25T02:33:00.000-04:002011-06-25T02:33:53.685-04:00A 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.<br />
<br />
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.<br />
<br />
<ol><li style="margin-bottom: 10px;">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).</li>
<li style="margin-bottom: 10px;">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. </li>
<li>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.</li>
</ol><br />
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. <br />
<br />
With that I introduce Feed Forge. <a href="https://github.com/jimdoescode/feedforge">https://github.com/jimdoescode/feedforge</a><br />
<br />
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.<br />
<br />
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.JimDoesCodehttp://www.blogger.com/profile/12997299334521011106noreply@blogger.com3tag:blogger.com,1999:blog-191563564512051166.post-12418358002737547572011-05-29T03:31:00.000-04:002011-06-02T17:29:51.882-04:00Git Support in Komodo Edit.Been awhile since I posted in here. Thanks for sticking around.<br />
<br />
First here is the link to the <a href="https://github.com/jimdoescode/Komodo-Edit-Source-Control-Tools">GitHub Project</a><br />
<br />
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.<br />
<br />
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.<br />
<br />
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.<br />
<br />
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.<br />
<br />
"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.<br />
<br />
"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.<br />
<br />
"Git Init" will create a new empty repository in the root of the currently active project.<br />
<br />
"Git Push Remote" lets you push your local repository changes out to a remote repo like GitHub.<br />
<br />
Finally there is "Git Update" which updates your project files with the most current version stored in the repository.<br />
<br />
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.<br />
<br />
"Subversion Diff" diffs the currently viewed file with the version that is stored in the repository. Again it uses the standard console diff syntax.<br />
<br />
There you have it all those tools seem to work correctly for me if you have any difficulties let me know in the comments.<br />
<br />
Here is the link to the <a href="https://github.com/jimdoescode/Komodo-Edit-Source-Control-Tools">GitHub Project</a><br />
<br />
As a side note since this stuff is now in GitHub I wont be hosting it in drop box.JimDoesCodehttp://www.blogger.com/profile/12997299334521011106noreply@blogger.com11tag:blogger.com,1999:blog-191563564512051166.post-45164991489859440612011-01-18T11:10:00.000-05:002011-07-20T13:01:50.843-04:00CodeIgniter and Caching, a love hate relationshipAs 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.<br />
<br />
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.<br />
<br />
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.<br />
<br />
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.<br />
<br />
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.<br />
<br />
The library methods are as follows:<br />
<br />
<br />
<pre class="brush: php">$this->scache->clear($key);
$this->scache->read($key);
$this->scache->write($key);
</pre><br />
<br />
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:<br />
<br />
<br />
<pre class="brush: php">$config['cache_expiration'] = 1;
</pre><br />
<br />
Let's see this sucker in action now. <br />
<br />
<br />
<pre class="brush: php">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));
</pre><br />
Somethings to keep in mind looking at this implementation:<br />
<ol><li>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.</li>
<li>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.</li>
<li>Remember the data contained in "page_segment" should not change between users or at least not change much.</li>
</ol>Below is a link to a zip of both the library and the config file. Please let me know if you have any issues.<br />
<br />
<a href="http://dl.dropbox.com/u/13081549/Scache.zip">http://dl.dropbox.com/u/13081549/Scache.zip</a>JimDoesCodehttp://www.blogger.com/profile/12997299334521011106noreply@blogger.com9tag:blogger.com,1999:blog-191563564512051166.post-87556304879144855932011-01-04T16:36:00.000-05:002012-01-13T14:29:18.942-05:00Some CodeIgniter ConstantsAs 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.<br />
<br />
Here is a link to the docs that outlines the constants listed below. <br />
<a href="http://codeigniter.com/user_guide/general/reserved_names.html">http://codeigniter.com/user_guide/general/reserved_names.html</a><br />
<br />
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.<br />
<br />
BASEPATH is the path to the system folder of you CI application. This is defined in the root index.php file.<br />
<br />
CI_VERSION as I am sure it is obvious, is the version of CodeIgniter you are running.<br />
<br />
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.<br />
<br />
<br />
EXT refers to a file extension which would typically be ".php". This is defined in the root index.php file.<br />
<br />
FCPATH is the full server path to the root index.php file. This is defined in the root index.php file.<br />
FILE_READ_MODE, FILE_WRITE_MODE same as DIR_READ_MODE, DIR_WRITE_MODE except these deal with files instead of directories.<br />
<br />
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.<br />
<br />
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.<br />
<br />
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. <br />
<br />
Hopefully that gives you a better idea of what these suckers do.JimDoesCodehttp://www.blogger.com/profile/12997299334521011106noreply@blogger.com0tag:blogger.com,1999:blog-191563564512051166.post-74533733067805832292010-12-11T12:54:00.000-05:002011-07-20T13:04:32.428-04:00Updates to my bread and butter.I just updated my YouTube library to incorporate a suggestion to allow direct uploading from your server to the YouTube servers. The new method is called "directUpload" and takes 4 parameters. The first is the path to the file to upload from your server. The second is the mime-type of the video (video/mp4, etc.). The third is the XML meta data that goes with this video, you can learn what this is <a href="http://code.google.com/apis/youtube/2.0/developers_guide_protocol.html#Sending_a_Browser_Upload_API_Request">here</a> but it is essentially the same as what you would do for a form upload token. The final parameter is optional and defines the user whose account this belongs to, if you leave it blank it will go to the currently authenticated user. <br />
<br />
Here is a sample call with the video to upload in the CI root directory:<br />
<br />
<pre class="brush: php">$xml = '<?xml version="1.0"?><entry xmlns="http://www.w3.org/2005/Atom" xmlns:media="http://search.yahoo.com/mrss/" xmlns:yt="http://gdata.youtube.com/schemas/2007"><media:group><media:title type="plain">Test Video</media:title><media:description type="plain">This is a direct upload test</media:description><media:category scheme="http://gdata.youtube.com/schemas/2007/categories.cat">People</media:category><media:keywords>test, upload</media:keywords></media:group></entry>';
$this->youtube->directUpload("test.3gp", 'video/3gp', $xml);
</pre><br />
You may wish to note that uploading a large file could take awhile and this library doesn't currently support resumable uploads so you just have to wait it out if things are taking awhile. As always you can turn on the DEBUG flag at the top and watch your error log for more info on what is going on. <br />
<br />
While I was in there I took the liberty to fix a bug where only a response of 200 was deemed success by the library now any 200 level response is considered successful as it should be. <br />
<br />
Here is the updated library: <a href="http://dl.dropbox.com/u/13081549/youtube.php">http://dl.dropbox.com/u/13081549/youtube.php</a><br />
<br />
If you are new here consult my other posts for more information.JimDoesCodehttp://www.blogger.com/profile/12997299334521011106noreply@blogger.com4tag:blogger.com,1999:blog-191563564512051166.post-26034794458641931112010-11-22T01:17:00.000-05:002010-11-24T12:24:20.574-05:00Neglected blog but not neglected codeBeen awhile since I posted on here. Just been busy supporting my own sites as well as all the sites I have done for work. Any way I just wanted to point out that I have made an update to the youtube library I wrote for CodeIgniter. Apparently there was an issue with larger responses from YouTube not being handled properly. Basically for larger requests the data is broken into chunks with a specified size. The problem was that my read method was only reading the first chunk. Which wasn't a problem for me until I finally went over the one chunk threshold and was losing data. Anyway that is fixed and should now correctly get all chunks of data. (Though I could only test with 2 as that is my current threshold)<br />
<br />
Also I added a new api method to that library which will allow you to post comments on a video or reply to a comment thread for a video. The method is called addComment and it accepts 2 parameters with an optional 3rd if you are replying. The first is the videoId which is the video to post the comment on, the next is the comment text, and the optional 3rd parameters is the commentId if you are responding. <br />
<br />
I also updated the wiki post on the codeigniter site <a href="http://codeigniter.com/wiki/YouTube_API_for_CodeIgniter/">here</a><br />
And placed the latest version in my dropbox share <a href="http://dl.dropbox.com/u/13081549/youtube.php">here</a><br />
<br />
One thing to note I think I left the code in debug mode, which shouldn't do anything really, it will just write out a bunch of stuff to your php error log. You can turn it off by setting the DEBUG flag to false.<br />
<br />
[EDIT] Looks like there was another bug. If a youtube response had newlines in it, maybe in a description field or something, then we would only read to the new line and stop. I fixed this as well the updated version is on the drop box share. Also updates are on the wiki.JimDoesCodehttp://www.blogger.com/profile/12997299334521011106noreply@blogger.com0tag:blogger.com,1999:blog-191563564512051166.post-42763805486540967062010-10-19T16:31:00.000-04:002010-10-19T16:31:07.410-04:00Support your developersFor a long time now I have used a number of free and/or open source applications. In fact I prefer them generally to paid applications for many reasons but namely because they are free. Lately though I have felt that the great folks who contribute these excellent software packages need and should see the support that they deserve. So I have begun contributing small donations to many of the products I use on a regular basis. I figure for something like Cyberduck which I use daily there is absolutely no reason to ignore their requests for donations. This program is indispensable in my day to day.<br />
<br />
Please don't construe this as me requesting any kinds of donations from anyone I personally don't feel I have written anything worth any monetary value. But I do ask that you support the creators of the free applications that you use regularly, and make a small donation to them.JimDoesCodehttp://www.blogger.com/profile/12997299334521011106noreply@blogger.com0tag:blogger.com,1999:blog-191563564512051166.post-53579673647508381792010-10-13T14:30:00.002-04:002011-08-13T15:18:12.334-04:00Twitter OAuth CodeIgniter Library, That was easy.<div class="separator" style="clear: both; text-align: center;"><a href="http://twitgoo.com/images/oauth-icon.png" imageanchor="1" style="clear: left; float: left; margin-bottom: 1em; margin-right: 1em;"><img border="0" height="198" src="http://twitgoo.com/images/oauth-icon.png" width="200" /></a></div>After spending months scratching my head and wondering if OAuth even works at all. I was able to crank out a library that will do OAuth for twitter in about 2 hrs. Yeah you are right I probably should have been actually doing my job but this is way more fun. It also gave me the opportunity to revisit my google OAuth library and fix the issues it had with HMAC signing.<br />
<br />
Basically HMAC-SHA1 signing was impossible in the old google library, so I fixed that and it should still work the same if you are using RSA so don't worry about updating. If you want HMAC though you will need to jump through a few more hoops (nothing too serious) mainly involving keeping and using a token_secret value. I outline everything in the CI wiki if you are interested in how to use it and how it works.<br />
<br />
Anyway back to the library I just finished. This library works pretty much the same exact way as the google library the only difference is twitter only lets you use HMAC signing. This means that you need to maintain a token secret value. Not a huge deal but one more thing to keep track of. If you want a more technical look at the implementation check out the CI wiki post I made <a href="http://codeigniter.com/wiki/OAuth_for_Twitter/">here</a><br />
<br />
Otherwise if you would rather just download the file you can get it from my dropbox account:<br />
<a href="http://dl.dropbox.com/u/13081549/twitter_oauth.php">http://dl.dropbox.com/u/13081549/twitter_oauth.php</a><br />
<br />
You also need the oauth_helper I wrote you can get it from dropbox here:<br />
<a href="http://dl.dropbox.com/u/13081549/oauth_helper.php">http://dl.dropbox.com/u/13081549/oauth_helper.php</a><br />
If you want to see what it does then visit the wiki page <a href="http://codeigniter.com/wiki/OAuth_Helper/">here</a><br />
<br />
Using this library is very similar to using the google oauth library here is an example:<br />
<pre class="brush: php">function request_token()
{
$params = array('key'=>'CONSUMER_KEY', 'secret'=>'CONSUMER_SECRET');
$this->load->library('twitter_oauth', $params);
$response = $this->twitter_oauth->get_request_token(site_url("site/access_token"));
$this->session->set_userdata('token_secret', $response['token_secret']);
redirect($response['redirect']);
}
function access_token()
{
$params = array('key'=>'CONSUMER_KEY', 'secret'=>'CONSUMER_SECRET');
$this->load->library('twitter_oauth', $params);
$response = $this->twitter_oauth->get_access_token(false, $this->session->userdata('token_secret'));
$this->_store_in_db($response);
}
</pre>The response array returned from the get_access_token call contains the access token, the access token secret, the twitter user id, and twitter screen name. You can do what you want with the last two values but you need to store the access token and token secret as these are how you authenticate with twitter.<br />
<br />
[EDIT]<br />
It was pointed out to me that once you have an OAuth access token it isn't exactly clear what you do with it. The OAuth portion of your API requests goes in the Authorization section of the header. The oauth_helper provides a nice function that will create the desired Authorization section. <br />
<br />
<pre class="brush: php">$access = array('oauth_token'=>urlencode($this->session->userdata('oauth_token')), 'oauth_token_secret'=>urlencode($this->session->userdata('oauth_token_secret')));
$extra = array('status'=>rawurlencode('Tweeting from my API'));
$authhdr = get_auth_header('http://api.twitter.com/1/statuses/update.json', 'CONSUMER KEY', 'CONSUMER SECRET', array_merge($access, $extra), 'POST', OAUTH_ALGORITHMS::HMAC_SHA1);
</pre><br />
The rest of the header is up to you. Make sure you include the values you are posting in the get_auth_header extra field, and that it is rawurlencoded.<br />
<br />
[EDIT 2]<br />
I also ran into an issue where I did not specify a callback when I registered the application with twitter. If you don't specify a callback, there is a bug with the registration process that will force your application to be set as a desktop application. If you are getting an index out of bounds exception when you make your first request make sure you have a callback set for your application on twitter. <br />
JimDoesCodehttp://www.blogger.com/profile/12997299334521011106noreply@blogger.com20tag:blogger.com,1999:blog-191563564512051166.post-56846198339662835182010-10-12T13:02:00.000-04:002011-12-24T11:40:14.727-05:00CodeIgniter and the YouTube API. This is a triumph<div style="font-family: Georgia,"Times New Roman",serif;"><div class="separator" style="clear: both; text-align: center;"><br />
</div><span style="font-size: small;"> <b>Please note that the code for this has been moved to</b> <a href="https://github.com/jimdoescode/CodeIgniter-YouTube-API-Library">GitHub Here</a></span><br />
<br />
<br />
<span style="font-size: small;">I just want to make a note here, 'huge success'.</span></div><div style="font-family: Georgia,"Times New Roman",serif;"><span style="font-size: small;"><br />
</span></div><div style="font-family: Georgia,"Times New Roman",serif;"><span style="font-size: small;">I finished work on my youtube API library for CodeIgniter. This will let you connect to youtube and make requests without having to load any Zend GData libraries. It is written exclusively for CodeIgniter.</span></div><div style="font-family: Georgia,"Times New Roman",serif;"><span style="font-size: small;"><br />
</span></div><div style="font-family: Georgia,"Times New Roman",serif;"><span style="font-size: small;">To use the library you must first pass in some parameters. The apikey is the apikey provided to you once you register with youtube to use the API (I put mine in a config file). Next you want to include the oauth consumer key that you setup when you setup oauth with google. The secret is the consumer secret google provides you if you are using HMAC-SHA1 signing or the file path to your .pem file if you are using RSA-SHA1 signing (again I put these in a config file for easy access/changes). You must then specify the signing algorithm you use to make your oauth signatures. Finally you have to specify the access token and token secret if your user has already authorized your site to connect to youtube on their behalf.</span></div><div style="font-family: Georgia,"Times New Roman",serif;"><span style="font-size: small;"><br />
</span></div><div style="font-family: Georgia,"Times New Roman",serif;"><span style="font-size: small;">If any of this seems over your head please consult the oauth docs on youtube for further clarification. You can find those <a href="http://code.google.com/apis/youtube/2.0/developers_guide_protocol_oauth.html">here</a>. It should also be noted that this library only does OAuth authentication it does not support AuthSub feel free to add this if you would like though. </span></div><div style="font-family: Georgia,"Times New Roman",serif;"><span style="font-size: small;"><br />
</span></div><div style="font-family: Georgia,"Times New Roman",serif;"><span style="font-size: small;">This library does require the oauth_helper I wrote for CodeIgniter I will link to the file at the bottom of the page but if you wish to further understand what it does visit the CodeIgniter Wiki <a href="http://codeigniter.com/wiki/OAuth_Helper/">here</a>. Also I wrote a library to handle all of the OAuth interactions that is also available on the Wiki <a href="http://codeigniter.com/wiki/OAuth_for_Google/">here</a>. (I will provide a link to this at the bottom of this post too.)</span></div><br />
<pre class="brush: php">$params['apikey'] = $this->config->item('youtube_api_key');
$params['oauth']['key'] = $this->config->item('google_consumer_key');
$params['oauth']['secret'] = $this->config->item('google_consumer_secret');
$params['oauth']['algorithm'] = 'RSA-SHA1';
$params['oauth']['access_token'] = array('oauth_token'=>urlencode($token));
$this->load->library('youtube', $params);
</pre><br />
That's it you now have a youtube API instance and can make calls. The following methods are available please consult the documentation for usage etc.<br />
<br />
Here is a list of methods that are available right out of the box, no authentication needed.<br />
<br />
<pre class="brush: php">$this->youtube->getVideoEntry($videoId);
$this->youtube->getRelatedVideoFeed($videoId, $params = array());
$this->youtube->getVideoResponseFeed($videoId, $params = array());
$this->youtube->getKeywordVideoFeed(array $keywords, $params = array());
$this->youtube->getVideoCommentFeed($videoId, $params = array());
$this->youtube->getTopRatedVideoFeed($params = array());
$this->youtube->getMostViewedVideoFeed($params = array());
$this->youtube->getRecentlyFeaturedVideoFeed($params = array());
$this->youtube->getWatchOnMobileVideoFeed($params = array());
</pre><br />
The list of methods below requires an authenticated user before they can be used.<br />
<br />
<pre class="brush: php">$this->youtube->getUserPlaylistFeed($user = 'default', $params = array());
$this->youtube->getPlaylistFeed($playlistid, $params = array());
$this->youtube->getSubscriptionFeed($user = 'default', $params = array());
$this->youtube->getContactFeed($user = 'default', $params = array());
$this->youtube->getUserUploads($user = 'default', $params = array());
$this->youtube->getUserFavorites($user = 'default', $params = array());
$this->youtube->getUserProfile($user = 'default');
$this->youtube->getUserActivity($user = 'default');
$this->youtube->getInboxFeedForCurrentUser();
</pre><br />
Finally these methods all require some type of data to be specified whether that be XML meta data, a comment or a boolean value.<br />
<br />
<pre class="brush: php">$this->youtube->directUpload($path, $contenttype, $metadata, $user = 'default');
$this->youtube->getFormUploadToken($metadata);
$this->youtube->addComment($videoId, $comment, $commentId = false);
$this->youtube->addVideoResponse($videoId, $responseId);
$this->youtube->addNumericRating($videoId, $rating);
$this->youtube->addLikeDislike($videoId, $like);
</pre><br />
<div style="color: black; font-family: Georgia,"Times New Roman",serif;"><span style="font-size: x-small;"><span style="font-size: small;"><span style="font-size: x-small;"><span style="font-size: small;">All methods where the user is defined as 'default', or are getting data from the current user, and the form upload token method, all require oauth authentication or they wont work. The methods that let you define the user may work without authentication but will only show data that the specified user has made public. The form upload token method requires xml meta data to be passed in as well. You can see what this should look like <a href="http://code.google.com/apis/youtube/2.0/developers_guide_protocol.html#Sending_a_Browser_Upload_API_Request">here</a>. All API request return XML and it is your job to parse it and get what you want from it. </span></span></span></span></div><div style="color: black; font-family: Georgia,"Times New Roman",serif;"><br />
</div><div style="color: black; font-family: Georgia,"Times New Roman",serif;"><span style="font-size: x-small;"><span style="font-size: small;"><span style="font-size: x-small;"><span style="font-size: small;">I should note that I haven't tested all of the methods defined in this library so I cannot say with 100% certainty that they all work, but from the ones I have tested I can make a pretty good assumption that they do. Also I used RSA-SHA1 signing for my OAuth requests I just couldn't get HMAC to work properly I found an issue with my signing method for HMAC and fixed it but I cannot guarantee that it works properly either. If you have an issue post it in the comments and give me your HTTP header information for both your request and the response. There is a DEBUG constant flag you can set that will output this information to your error logs. I am also going to post a more technical brief of this on the CodeIgniter wiki which I will link to <a href="http://codeigniter.com/wiki/YouTube_API_for_CodeIgniter/">here</a>.</span></span></span></span></div><br />
<div style="font-family: Georgia,"Times New Roman",serif;"><span style="font-size: x-small;"><span style="font-size: small;"><span style="font-size: x-small;"><span style="font-size: small;">[EDIT] There seems to be some confusion about how all this stuff fits together so let me clarify the steps. Please Please Please read all the documentation before leaving a comment.</span></span></span></span><br />
<ol><li><span style="font-size: x-small;"><span style="font-size: small;"><span style="font-size: x-small;"><span style="font-size: small;">Download the linked files and put them in the correct CI directories. You need all 3 of them. Two go in the application/libraries folder and one goes in the application/helpers folder.</span></span></span></span></li>
<li><span style="font-size: x-small;"><span style="font-size: small;"><span style="font-size: x-small;"><span style="font-size: small;">Read the documentation on OAuth. Having a basic understanding of how it works is key. Make sure you read the oauth_helper and google_oauth wiki pages. Both contain vital information about generating the necessary keys and how to use those files. Read the oauth_helper wiki first. It has links on generating some keys and how to use them. Don't worry too much about understanding how oauth_helper works it is more for internal purposes but you do need to checkout the links in its wiki. Read the google_oauth wiki next as it provides more working examples of what you need to do to get oauth up and running and get the necessary access token.</span></span></span></span></li>
<li><span style="font-size: x-small;"><span style="font-size: small;"><span style="font-size: x-small;"><span style="font-size: small;">Make your controller to get a request and access token. Samples are provided on the google_oauth wiki page. If you have read the documentation up to this point then it shouldn't be too difficult to figure out what to do. Just use the google_oauth wiki controller examples for reference.</span></span></span></span></li>
<li><span style="font-size: x-small;"><span style="font-size: small;"><span style="font-size: x-small;"><span style="font-size: small;">Test your controller methods out and make sure you are getting an access token and there are no hiccups in the 3 step process. You can get an access token as many times as you need so don't worry if you messed something up and need to get a new one.</span></span></span></span></li>
<li><span style="font-size: x-small;"><span style="font-size: small;"><span style="font-size: x-small;"><span style="font-size: small;">Read the youtube api wiki page and check out the official youtube api documentation which can be found <a href="http://code.google.com/apis/youtube/2.0/developers_guide_protocol_audience.html">here</a></span></span></span></span></li>
<li><span style="font-size: x-small;"><span style="font-size: small;"><span style="font-size: x-small;"><span style="font-size: small;">Make your controller to access the youtube api. You will pass in the access token you got from the previous steps as well as an API key you get from google. Make sure you read up on all of the methods the api provides. It is by no means a complete API library there are a number of missing features which may get added in the future but my hope is that you can figure out how to add the things you need by reading the official youtube api documentation and looking at how I implemented things in the api library. Really what it boils down to is HTTP header manipulation. </span></span></span></span></li>
<li><span style="font-size: x-small;"><span style="font-size: small;"><span style="font-size: x-small;"><span style="font-size: small;">Finally put everything together. The process should be pretty seamless with the user only having to leave your site for a split second to approve the request token. Also note that you can do this via a local server so even if you setup everything to your sites domain if you are running a dev instance locally everything should still work. </span></span></span></span></li>
</ol></div><div style="font-family: Georgia,"Times New Roman",serif;"><span style="font-size: x-small;"><span style="font-size: small;"><span style="font-size: x-small;"><span style="font-size: small;">If you have read everything on this blog post and all the subsequent pages it links to and you still have questions please let me know. Judging from some of the questions I have had all of the info is in the blog post and the linked pages I think the problem is: there isn't a clear order to it all. For that I apologize. Follow the steps outlined and it should make things a bit easier.</span></span> </span></span></div>JimDoesCodehttp://www.blogger.com/profile/12997299334521011106noreply@blogger.com194tag:blogger.com,1999:blog-191563564512051166.post-82894753975744447482010-10-11T15:33:00.000-04:002010-10-11T15:33:13.278-04:00Komodo Edit 6 is out?It has just come to my attention that Komodo Edit 6 is out. I am kind of surprised as I attempted to update from 5 yesterday and no updates were found according to the built in update method.<br />
<br />
I think I will hold off for the time being though. I have a number of toolboxes defined and am right in the middle of a project so I would rather not risk it. Soon though, I need to finish reading the change list. I hope things are a bit more stable on Mac as it seems that Komodo Edit doesn't like being open for long stretches (3-4 days) and then have a number of tabs closed. It would pretty consistently crash when those stars aligned.JimDoesCodehttp://www.blogger.com/profile/12997299334521011106noreply@blogger.com0tag:blogger.com,1999:blog-191563564512051166.post-27868757476279643042010-10-11T11:52:00.000-04:002011-05-29T03:50:23.771-04:00SVN Support in Komodo EditOne of the features that makes a great IDE is version control support. Some really nice features like the ability to see what lines have changed in a file and revert a single line are built in to many IDEs such as NetBeans. However due to the issues I outlined in an earlier post NetBeans just won't work for me on the Mac. So I reverted to the tried and true Komodo Edit IDE.<br />
<br />
Subversion support does not exist out of the box in Komodo Edit, and once you get it working it is much more basic than the grandiose features of other IDEs but it works and it is certainly better than nothing. You can follow the instructions found <a href="http://moisadoru.wordpress.com/2009/02/12/home-baked-svn-support-for-komodo-edit/">here</a> or you can just download the KPZ file there. One thing I discovered was missing from this toolbox though is the ability to delete from subversion. I added another tool that gives this ability, it relies on you just deleting the added file then clicking the subversion delete button. Sorry about the ordering it appears that Komodo Edit only lets you set toolbox items alphabetically.<br />
<br />
Your order of operations prior to check in now becomes (Note 1 and 2 are interchangeable) :<br />
1) Click the Subversion add button. This will pickup any new files in your project.<br />
2) Click the Subversion delete button. This will remove any files deleted from your project.<br />
3) Click the Subversion check in button. To finally commit your project.<br />
<br />
You can read the blog I linked to for info on how to checkout a project and how to update.<br />
<br />
These files are now hosted in GitHub along with a similar tool set for Git Version Control.<br />
Here is the link to the <a href="https://github.com/jimdoescode/Komodo-Edit-Source-Control-Tools">GitHub Repository</a><br />
<br />
If you want to read more about the Git tool set check out my blog post about them.JimDoesCodehttp://www.blogger.com/profile/12997299334521011106noreply@blogger.com0