Jason Leveille's Blog
Web Development Intoxication
Home
Tue, 22 Apr 2008 19:41:37 +0000 2 Comments
I have had a bit of a hair pulling experience over the last few hours, until finally I got some sense and looked at the Definition and Usage of parseInt. Here’s the example:
<script type="text/javascript">
var data = new Array('007', '008', '009', '010');
for(var x in data)
{
console.log(data[x] + ' -> ' + parseInt(data[x]));
}
</script>
And the result:
007 -> 7 008 -> 0 009 -> 0 010 -> 8
What I wanted was the result 7, 8, 9, and 10. The result seen above comes from the fact that, because I have a leading 0 in my strings, parseInt is reverting to a base 8 (octal) radix. The solution of course is to specify a base 10 (decimal) radix.
<script type="text/javascript">
var data = new Array('007', '008', '009', '010');
for(var x in data)
{
console.log(data[x] + ' -> ' + parseInt(data[x], 10));
}
</script>
And the result:
007 -> 7 008 -> 8 009 -> 9 010 -> 10
Mon, 21 Apr 2008 08:14:15 +0000 No Comments
Last week Dave and I were trying to figure out the best way to synchronize member data from an asp application with a WordPress installation. I don’t remember how it came up in conversation, but in a flurry of chatter we decided that we should build a RESTful API to allow the applications in question to communicate. In the interest of re-usability we also decided that we should build a generic toolkit. One that could easily be used to expose an API for any supported database, through PHP. So, using this toolkit you should quite easily get your Lasso application talking with your PunBB software, if that’s what you need.
So was born rest-toolkit. We have released an alpha version of the project, so download it and give it a try. I hope you don’t mind a lack of formal documentation. Depending on how things go documentation will follow.
Fri, 18 Apr 2008 08:40:57 +0000 2 Comments
Recently I worked on a project where all member data was being managed through a third party member management service, provided by a company named Avectra. The product does more than manage member data from the looks of things, but all I cared about was interaction with the member management API.
I had to authenticate against an external data source, as well as query the data source for member information when needed. Avectra does have a web service API which it has named xWeb. Here is a quote from their Wiki:
xWeb is netFORUM’s XML web services application. netFORUM is an enterprise level Association Management System (AMS) developed by Avectra that allows associations to manage their customers and related activities. netFORUM is used by association staff, members, and the public at large.
After a successful authentication with Avectra, the authenticated user is presented with a token that they pass along with API requests. Pretty standard stuff. The Wiki does an ok job of explaining authentication and login (two different things), therefore I’ll jump right to the good stuff. If you’re stuck on authentication/weblogin please let me know.
For interacting with the API I created a class file to abstract, at least to a small degree, some of the details of consuming the service. Here it is:
<?php
/*
* @author: Jason Leveille
* Provides access to avectra web services
*/
class Avectra
{
//Avectra organization api username and password (not member username/password) to access web services
private $user = 'user';
private $pass = 'password';
//Avectra paths to xweb and eweb. This is handy so that you can easily switch back and fourth between dev and production
private $xweb = 'www.mencnet.org/xweb/';
private $eweb = 'https://www.mencnet.org/netforummenctest/eweb/';
/**
* Grabs data associated with a member based on customer key / token
* @param $cst_key Customer Key to search on
*/
public function getMemberDataByKey($cst_key) {
if(empty($cst_key))
{
return false;
}
$memberData = sprintf('https://%s:%s@%snetFORUMXML.asmx/GetIndividualInformation?IndividualKey=%s', $this->user, $this->pass, $this->xweb, $cst_key);
//The simplest solution is to call simplexml_load_file directly, however this was causing issues on Solaris 10, php 5.2. Didn't have time to investigate, so I went with load_string
//return simplexml_load_file($memberData);
$data = simplexml_load_string(file_get_contents($memberData));
//make sure that the returned xml file actually contains data
if(empty($data->IndividualObject[0]->eml_address))
{
return false;
}
return $data;
}
/**
* Grabs data associated with a member based on member email
* @param $email Member email to search on
*/
public function getMemberDataByEmail($email) {
if(empty($email))
{
return false;
}
$memberData = sprintf('https://%s:%s@%snetFORUMXML.asmx/GetQuery?szObjectName=%s&szColumnList=%s&szWhereClause=%s&szOrderBy=%s',
$this->user,
$this->pass,
$this->xweb,
'Individual',
'ind_first_name, ind_last_name, cst_org_name_dn, adr_city, adr_state, eml_address',
sprintf("eml_address = '%s'", $email),
"ind_last_name"
);
return simplexml_load_file($memberData);
}
/**
* Grabs the url of the avectra eweb application
*/
public function getEwebUrl() {
return $this->eweb;
}
}
?>
So, for example, to retrieve data about a specific member, and to store that data in session variables for later use, your code might look similar to the following:
function login_success($cst_key = null) {
if(!$cst_key)
{
//set error message and redirect
}
//ensure clean referer data
$original_referer = $this->clean->stripScripts($this->params['url']['ref']);
//Avectra object
//include avectra class file, for example, in CakePHP
App::import('Vendor', 'Avectra');
$avectra = new Avectra();
//ensure a clean customer key
$cst_key = $this->clean->stripScripts($cst_key);
//if we successfully load the associated user data
if($data = $avectra->getMemberDataByKey($cst_key))
{
$data = $data->IndividualObject[0];
$this->Session->write("Member.memberId", $this->clean->stripScripts($data->eml_address));
$this->Session->write("Member.firstName", $this->clean->stripScripts($data->ind_first_name));
$this->Session->write("Member.lastName", $this->clean->stripScripts($data->ind_last_name));
$this->Session->write("Member.email", $this->clean->stripScripts($data->eml_address));
$this->Session->write("Member.location", $this->clean->stripScripts($data->adr_city . ', ' . $data->adr_state));
$this->Session->write("Member.loggedIn", 1);
$this->Session->write("Member.customerKey", $cst_key);
//indicate successful login and redirect to original referrer
}
else
{
//set error message and redirect
}
}
The Avectra Wiki examples are slanted heavily in the direction of SOAP, however in this instance I just thought it was overkill. I figured the response was going to come back in XML, so I would just use simplexml_load_file and pass in the URI. The application lives with Solaris 10 and PHP 5.2. For some reason simplexml_load_file was failing under certain boundary cases that I couldn’t quite pin down. This was an easy fix as I just used simplexml_load_string and file_get_contents to retrieve the xml response. An extra step, but it seemed to solve whatever the issue was that I was having. So, all I needed to do was make sure that I had the properly constructed URI, and that I could authenticate. Authentication is simply handled by sending in the username:password combination as part of the request.
Tue, 15 Apr 2008 13:44:36 +0000 1 Comment
It seems that more and more people are moving away from the inclusion of www in their url. SitePoint recently wrote about the subject, and this past February Roger Johansson also wrote an article on the topic. Roger’s article was really more about making sure your site works with our without www (I couldn’t agree more). You wouldn’t get any more from me than you could get from taking a look at the articles I’ve referenced, therefore I’ll just skip to the good stuff. In general I feel that the inclusion of www is just a waste of address bar space. For this blog I have decided to throw it to the dogs. If I remember correctly, “Removing the Ws from URLs“, an article from 2002, was a big help for me on my path to www enlightenment.
<VirtualHost ipaddress> ServerAdmin root@localhost ServerAdmin webmaster@blueatlas.com DocumentRoot /path/to/public_html/ ServerName jasonleveille.com ErrorLog /path/to/logs/jasonleveille.com/error_log TransferLog /path/to/logs/jasonleveille.com/access_log </VirtualHost> <VirtualHost ipaddress> ServerName jasonleveille.com ServerAlias www.jasonleveille.com ServerAlias ww.jasonleveille.com Redirect permanent / http://jasonleveille.com/ </VirtualHost>
Perhaps you don’t have access to your VirtualHost block. Not a problem if your host/server/whatever allows you to override directives via .htaccess. This article on using .htaccess from Daring Fireball is a good reference regarding this topic.
RewriteEngine on
RewriteBase /
RewriteCond %{HTTP_HOST} ^www\.yourdomain\.com$
RewriteRule (.*) http://yourdomain.com/$1 [R=Permanent]
Mon, 14 Apr 2008 15:47:40 +0000 No Comments
I recently had the need to set up some permanent redirects for an application built on CakePHP. My first thought was to use a simple .htaccess Redirect at the top of my www .htaccess file, like such:
Redirect 301 /foo /bar
However, the result of the redirect was actually the following url:
http://foobar.com/bar?url=foo
This has to do with the QSA flag in the last RewriteRule of the root htaccess file. The QSA flag indicates that a query string should be appended to the url. In our case, foo is recognized as the query string and it ultimately is appended at the end of the bar redirect. Not what I wanted, as the appending of foo to bar results in a 404 error.
My next thought was to set up a RewriteRule for foo, so that it would be redirected to bar. Here is what I came up with, with its exact placement in the default CakePHP webroot htaccess file. The really important thing here has to do with the placement of the rule:
RewriteEngine On
#rule to redirect foo to bar
RewriteRule ^foo$ /bar [R=301,L]
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule ^(.*)$ index.php?url=$1 [QSA,L]
As you can see here, I am using the R and L flags at the end of the RewriteRule. These flags serve the following purpose:
R: Forces a redirect to the new url, and loads the new page
L: Ensures that this is the last rule that is processed by the server in this file. This is important here, as without the L flag the server would move on to the last rewrite rule, essentially ignoring the R flag for our redirect rule, and it would end up generating a 404 error.
Here’s a great set of cheatsheets if you’re interested in reading more.
Of course there are other options for redirects, including meta refresh or PHP header, however I didn’t want to clutter up the directory with pages whose only purpose was that of setting up a redirect.
Sun, 13 Apr 2008 13:23:02 +0000 No Comments
The death of an open source project starts when the lead developers stop actually using the project. If it is only being maintained out of a feeling of obligation for those who have downloaded and installed the code, than it’s bound to have a short shelf life. In July of 2006 Stephen Eskin (a former student of mine) and I launched the first version of Project Alumni. We had implemented an alumni application for our High School and we figured we might as well make it available to the world. In nearly two years the project has been downloaded approximately 3400 times. I’m pretty happy with those numbers. Just query google for “Powered by Project-Alumni” and you can get a good idea of the number of sites using the project.
On a personal level I’ve always been happy with the responses we’ve gotten from the people using the project. For what it’s worth, I’m proud of the fact that this was the first real application I ever took part in developing. I’ve always been really impressed by what Eskin was able to accomplish with almost no PHP experience, and very little development experience. The project really has it’s origins in the need for a teacher to find something for a very bright student to do. We launched the first Project Alumni 1 month after conceiving the project in October of 2005, and most of that credit goes to Eskin.
On a professional level I’ve never felt quite right about the codebase. Considering the inexperience of Eskin and I when the project was first open sourced, and considering how much I didn’t know about basic security best practices, I think it’s ok. Ok won’t cut it though when new security vulnerabilities are discovered and I’m not around to patch them. Even though the data we’re housing might not be that sensitive (others might argue otherwise), a member might be using the same username/password that they use for their banking account. If that data isnt’ safe we have a problem. At least we are using mysql_real_escape_string and hashing the password. Actually, the more I dig into the code (again, which I have been disconnected from for a while now) the more I see things that I like. For instance, checking for ‘magic_quotes_gpc‘ and stripping slashes before running mysql_real_escape_string. Good one whoever implemented that way back in 2006. Someone was paying attention to the PHP manual. Probably Eskin.
I basically stopped supporting the project 4 months ago. The only reason I made a commit was because someone started asking me about security vulnerability reports that had started showing up. So, I pushed out a patch and moved on. I used to maintain a website and a help forum, but I decided one day that I didn’t want that burden anymore, especially with a codebase that I wasn’t really invested in. Don’t get me wrong. I used to be invested in the project. I spent 8 hours on my day off once getting the application to install properly and behave on a Windows server running IIS, just because the guy who needed help was a nice guy.
So, how do you kill an open source project? I have stopped releases. I have stopped supporting the project. I have stopped submitting patches. I took down the website and forums. Still, this thing is getting downloaded 100 - 200 times a month. I feel like I can’t just pull the plug. I think the real way you kill an open source project is by not actually using it. I think the best projects are the ones where the lead developers are heavily invested in the security/structure/scalabilty/maintainability of their own code. It was easy to use this project when I was teaching and I was responsible for the websites at Quince Orchard. A security fix was good because it directly impacted a site that I was responsible for. That’s obviously changed now. An up-and-coming open-source software project of mine on the other hand will see a lot of use in the future. A small percentage of our client base at BlueAtlas is a perfect fit for what SimpleMC has to offer. Another percentage of our client base is a good fit after some client specific customization of the application. Some of which makes it back into the project, and some of which does not.
So, to kill or not to kill, that of course is the question. I’m definitely leaning towards no now that I have written this post. I was way in the direction of yes 30 seconds before I started writing. I would be interested to hear what others think.
Thu, 10 Apr 2008 12:22:35 +0000 8 Comments
I’ve been working on a project for a while now at work which we have dubbed SimpleMC (Simple Managed Content). I spoke with Dave this morning, and he gave me the go ahead to start the process of open sourcing the project … which I’m very excited about. I haven’t officially even released an alpha version yet, however you can get a sneak peak:
I apologize in advance if someone gets in there and changes the admin password or completely destroys the demo. It is a demo and thus I haven’t spent a lot of time (5 minutes) putting it in true demo mode. I’d also like to mention that you won’t find any documentation about getting SimpleMC to work for you. You can take a look at /bai_cms/demo/ in the source to see how it is integrated into a page. Any issues, just contact me or post a comment here.
Thu, 10 Apr 2008 10:36:08 +0000 No Comments
I recently implemented DFS and Iterative Deepening algorithms to search for a target node in a tree. Initially I thought I would write my program in C++, however after some thought I decided to go the route of JavaScript. I believe the source code is commented sufficiently to give you a glimpse into some of the decisions I made, therefore I won’t be providing any real detail in this post.
DFS and Iterative Deepening Project
I have to give much thanks to Kirupa, as his ActionScript implementation of DFS and BFS gave me the inspiration to go the route of JavaScript. Not only that, but I was able to use much of his work as a model for the direction I took. I hope you find that I did provide sufficient credit in my comments. Enjoy.
NOTE: I stayed up until 1am, two nights in a row to finish this. I don’t work well late at night and that is likely reflected in some of the algorithmic decisions I made. If you have any questions please don’t hesitate to ask. Also, you might be asking, WTH did he use extjs here? Honestly, I don’t know. I originally had grand visions for my node tree, etc, however those didn’t pan out. In it’s current state there is no advantage to using that framework.