Jasper: Just a store platform experience, reworked

Jasper LogoFor the past 3 years, I’ve been working on a store that uses the Yahoo! Store platform. At first, the user interface for the web page design and page object models was easy to grasp (both the prefab versions and the custom ones I had access to), but going through the entire rewrite process was a pain – the biggest of which was the requirement of perfection. If a mistake was made in any field names or data-types it held, the whole object model had to be scrapped and started over. They’ve made minor improvements over the past 3 years to their Merchant Solutions side of things, but they have been extremely minor. One thing that hasn’t changed is the interface to edit pages.

There are two methods of doing the editing, depending on the Yahoo! Store platform that you have. If you’re on the Legacy version, you must go to the page itself, and click edit. This provides you with a series of fields and input boxes for each type of field. No intelligence in the design of what those fields are for or differentiation in how they interact.

If you’re on the Merchant Solutions platform, then you have the option of going directly to the page still, or you can do it in a flat-file pseudo database-like UI which is nothing more than a search-by-field interface, which presents you with a different-looking (but still the same) interface for editing the page.

Over the next few months, I’m going to embark on a web-based interface for importing the legacy store feed (objinfo.xml, which can’t be customized) and see what can be done with the data as far as modifying it, preparing it, cleaning it, and exporting it back to the store. I’m also going to attempt to code it entirely using Kodingen.com. I’ve done a highly customized version of this concept for the company I currently work for (at the time of this post), but none of the code will be reused from that project, and this project will have different, and limited features (in some areas, and expanded in other areas), but for a different data model. In some areas, this application will be more limited (since it’s working with a standardized data format, rather than a customized “catalog.xml” feed from Merchant Solutions. Once this basic version is solid, I may start working on a customized version, or even offering a customizing service to handle the catalog.xml file.

Some things I’d like to do differently with this basic version is:

  • create an install process (a la phpBB)
  • extensive automation, and possibly some AI concepts
  • learn more about object-oriented design and how it can be extended conceptually
  • experiment with some various php and javascript frameworks

There are plenty of other feature sets that I’ve learned and developed in addition to these in the past and plan to use as well. So we’ll see how this goes, and I’ll post some updates here. Depending on what I plan to do with it, I may or may not open-source it. If I do, I’ll host it on Google Code.

Technorati Tags: , , , , , , , , , , ,

How to Connect to SQL through Windows Authenticated ODBC in PHP

For about the last year, I’ve been creating a CMS (content management system), for the automatic management and maintenance of my company’s eCommerce site, on the Yahoo! Store platform. The software imports the entire store automatically, runs a series of cleanup processes with about a dozen different criteria, saves the changes it has made, exports the modified pages, and makes them available to download from Jada’s interface. This automation cuts the need for about 3-4 people doing a weeks’ worth of work, and does it all automatically in 10-30 minutes. The one thing it doesn’t do, is the one cleanup process that takes the longest, and requires the most human thought: comparing every product’s available options on the site, and checking them against actual inventory in the order management software.

Until now.

Our current order management software runs as a MS Access front-end to a MSSQL 2005 server backend through and ODBC DSN connection. This connection has been limited to MS Access and MS Excel application/queries, and thus, was the limiting factor to writing this most-complex cleanup process into Jada. The most difficult part in my development was finding an understandable article describing how to make an ODBC call, and then actually get the data back, in the same simple manner that one makes a MySQL query. The real issue has been once the connection is closed, the result cannot be accessed. I had to find that out the hardway, via Microsoft’s convoluted documentation on using ODBC.

Here’s the code I’ve used to make the ODBC connection in PHP (unfortunately my blog’s template can’t handle actual code right now):

Code Breakdown

We’ll start creating a function that makes an ODBC connection, passes it an SQL query, then parses the data into a table/array and return the array.

Function call

function odbcQuery($sql, $attempt="") {

When we call the function, we’ll provide the SQL Query we want executed, and an optional description of what we’re trying to do with the query. In this way, if it errors, an semantic error will be displayed along with the technical one to help locate the code easily.

Database Connection

// Establish an odbc connection with the database
$link = odbc_connect("My_DSN_Name", "", "");

When running odbc_connect() it takes 3 parameters:

  • the DSN; Server,Port; or Server/SQLInstance
  • username
  • password

When connecting using Windows Authentication & a DSN (as this example is about), there are some caveats and things to remember:

  1. On the web server, the User running the Web Service process needs to be a User with permission to access the SQL Server.
    1. In my case, the user running the web server is SYSTEM, and so the user trying to access the SQL server is “DOMAIN\COMPUTERNAME$“.
    2. There is no password for a SYSTEM account, and so on the SQL Server needs to have a user created named “DOMAIN\COMPUTERNAME$“.
    3. Due to some security concerns, I’ve decided to give the account read-only access to the database I want to access. You’ll need to consult your own IT Administrator or security advisor for your security concerns.
  2. In the odbc_connect() statement, you then only need the name of the DSN (which I assume has already been configured on the Web Server you’re using) , followed by two null-quotes: “”.

This creates an active link via ODBC to the SQL Server…supposedly

Database Connection Checking & Error Handling

if (!$link) {
	die('Could not connect: '.odbc_error().': '.odbc_errormsg());
} else {

Next, we check the link . If it just flat-out doesn’t exist, then we kill the program, throw an error message that will read: “Could not connect: <;insert odbc error code>;: <;insert odbc error text>;”. Otherwise, we move on…

Sending the SQL Query & Checking Response

$data = odbc_exec($link, $sql);
if($data === false) {
	echo "ODBC Query: ".$sql."

"; die("ODBC Query failed: ".$attempt."
Error: ".odbc_error()); } else {

Now that we have a valid link to the database, we’ll send a request for data using the odbc_exec() function. This function sends the connection resource ($link) and the SQL Query we want run ($sql). It will return a “ODBC result identifier” or false.

Since a result identifier could, I assume, be the number 0 (zero) I want to ensure that $data is actually false and not just zero. That’s where the triple === comes in. When doing conditional statements, using == will convert the data being compared into a true/false value, where zero or nothing = false and anything else = true. When you use === you test for an actual boolean value, meaning anything including zero = true and false = false.

If the query failed, and resulted in a false result, we’ll display an error message: “ODBC Query: <;insert actual SQL Query>; // ODBC Query failed: <;insert query description>; // Error: <;insert ODBC error code>;”. Otherwise, we’ll move on…

Parsing the Query Results – Column Headers

// Initialization
$row = $fields = $records = $result = array(); 	

// Get the result's column names
$count = odbc_num_fields($data);
for($x=1;$x<=$count;$x++) {
	$fields[] = odbc_field_name($data, $x);
}

We start off by initializing all the variables we're going to use in the next bit of code, to make sure they're empty.

Then we'll run odbc_num_fields() over the $data to get the number of columns we need to iterate through. For columns, the counting starts at 1, so the for-loop starts at 1.

Iterate through each column name and add it to an array, called $fields:

Array (
	[0] => field_name_1
	[1] => field_name_2
	[2] => field_name_3
)

Parsing the Query Results - Records

// Get the result's data: array[record#][column#] = value
$count = odbc_num_rows($data);
for($x=0;$x<$count;$x++) {
	odbc_fetch_into($data, $row, $x);
	array_push($records,$row);
}

Then we run odbc_num_rows() over the $data to get the number of rows we need to iterate through. For rows, the counting starts at 0, so the for-loop starts at 0.

Iterate through each record row and insert it to a temporary array $row using odbc_fetch_into(). Then take $row and put it into an array of records, $records giving you something like this:

Array (
	[0] =>; Array (
		[0] =>; record_1_column_1
		[1] =>; record_1_column_2
		[2] =>; record_1_column_3
	)
	[1] =>; Array (
		[0] =>; record_2_column_1
 		[1] =>; record_2_column_2
 		[2] =>; record_2_column_3
  	)
	[2] =>; Array (
 		[0] =>; record_3_column_1
 		[1] =>; record_3_column_2
 		[2] =>; record_3_column_3
  	)
 )

Making the data useable

Now that we've got two tables/arrays of data - the field/column names, and each record's array of data - it's time to make it usable in a format that we can consistently expect to be returned. There are two ways to do this. We can create an array listind every record as an array with column_name keys and values

// Return data in the format: array[record_id][column_name] = value
foreach($records as $rid =>; $record) {
	foreach($fields as $key =>; $name) {
		$result[$rid][$name] = $record[$key];
	}
}

or we can list every column as an array of record id's as keys and values.

// Return the data in the format: array[column_name][record_id] = value
foreach($fields as $key =>; $name) {
	foreach($records as $record) {
		$result[$name][] = $record[$key];
	}
}

Personally I find the first option to be more consistent with my results when calling a 2-dimensional result from MySQL queries, so it is the one I have gone with in my example at the start of the post, and in this description.

The foreach() statements describe a compilation of a $result array in this manner:

  1. For each item in the $records array, store the record_id as $rid, and the record array as $record.
  2. Then for each item in the $fields array, store its cardinality as $key and it's value/name as $name.
  3. Then compile an array, iterating through each of the fields, storing this $record's associated cardinality $key's value into the $result array's storage for this record's id ($rid) under the appropriate field name.

It's a lot easier to grasp than it sounds. Basically, take array from the Query Results - Records section, and replace the # with the column name in each: [#] =>; record_y_column_x, but store it as a different array, called $results. The resulting array would look something like this:

Array (
	[0] =>; Array (
		[column1] =>; record_1_column_1_data
		[column2] =>; record_1_column_2_data
		[column3] =>; record_1_column_3_data
	)
	[1] =>; Array (
		[column1] =>; record_2_column_1_data
 		[column2] =>; record_2_column_2_data
 		[column3] =>; record_2_column_3_data
  	)
	[2] =>; Array (
 		[column1] =>; record_3_column_1_data
 		[column2] =>; record_3_column_2_data
 		[column3] =>; record_3_column_3_data
  	)
 )

Close the connection, Return the result

		odbc_close($link);
		return $result;
	}
}

Now that we've stored the data we need from the volatile $data variable returned from the SQL Query into $result, we can close the connection to $link using odbc_close(), and then return $result for the program to do with it what it will.

Conclusion

This is just an example code that explains one way of many to extract a variable 1-2 dimension array of data from your SQL Query, using a Windows-Authenticated ODBC DSN connection. There are many other methods to do this, as well as security fixes, data scrubbing, and other modifications that one would probably want to do.

This is the first function I've written in any language to access an SQL Server via ODBC. This is also a function that has worked in tests, but that I have not yet put into production. I encourage you to take this bit of explanation and massage it into something that fits your needs in the code that you're writing, and don't rely on what I've got here as a written-in-stone example of good production-level code. This sample will change many times before I actually implement it.

Happy Hacking!

Technorati Tags: , , , , , , , , , , , ,

Living in the Cloud: Code Editing

As I mentioned in my previous post of the Living in the Cloud series, the majority of the stuff I do on the computer at work, and on the internet these days, involves creating/editing PHP codes or work and personal projects. Continuing the effort to turn the CR-48 into a useful and productive tool for people in my line of work, I have found a workable solution for those wishing to edit codes, and keep them sync’d onto their computers via DropBox.

Over the course of the last couple weeks with the Chrome OS netbook, my file synchronization setup has come to this:

  • Intranet web server runs Windows Live Mesh 2011 – syncs website files & database to Skydrive
  • Work PC runs Windows Live Mesh 2011 and pulls files from Skydrive. It saves them in a DropBox subfolder, and sends them up to the DropBox server.

A couple things about why my configuration is the way it is:

  • I use Windows Live Mesh 2011 for two reasons: the remote desktop feature and the fact that it doesn’t care where the folder you want to sync is, you can sync it right there.
  • I only recently started using DropBox for the potential of its API functionality. However, not many people are using the API, and it’s only available in certain programming languages.
  • I do use WAMP on my intranet server, so I am capable of moving the website’s files out of the www drive and into a DropBox subfolder and creating an alias in the Apache config for the new location. I haven’t done it yet, because I hadn’t found a web-based code editor that works with DropBox to provide a compelling reason to make that change – until now.

On to the good stuff.

For my web-based editing, I have decided to use a relatively new app from DropBox‘s own app site called: TextDrop. (Update, the app is no longer listed in the DropBox app site. The Link now goes directly to the app’s site.)

TextDrop - First Run

At first glance, this is a very basic text-editor. I do all my web coding in Notepad++, so using a notepad-type app is not an issue for me. If this is not the case for you, you may be better off using Kodingen.com or Bespin from Mozilla.

Also, right now, if you create a new page with the app, it is unable to save that back to DropBox. I don’t know what the status of this issue is, but at this time, it is only a minor annoyance as I’m not creating files usually, I’m editing existing ones.

TextDrop - Open files

The opening page has a Log In link, which gets you set up with DropBox to authenticate the app and give it permission to access/edit your files. Once you’ve granted TextDrop permission, you’re all set. Choose the Open button and you’ll be presented with the top-level directory of your DropBox cloud storage. Open up any text-based file, and you’ll be able to edit it right there, and save it back.

Since I only just found out about this app recently, I’m by no means an expert on it. However, Monday when I return to work, I will give all the pieces of my Living in the Cloud configuration a shot to see how productive I can be with only an internet browser.

Another web-based app that I’ll be keeping an eye on (which is being actively developed as of a couple days prior to this posting) is SourceKit. Right now it doesn’t get past the login screen – apparently the developer is working on getting it approved as a Production Application from the DropBox folks (API Key requirements, etc., if you’re familiar with how all that stuff works). It will have a tree-structure file list, and include the Bespin code editor along side it – essentially a light-weight Kodingen setup, using the DropBox storage instead of an FTP backend. The author has released some updates and looks like everything is ready to go. I’ll be working on a blog post after I’ve spent some time with it on my web development projects. It might even become my de facto code editor.

There will be more Living in the Cloud posts to come as well, with some Google Chrome OS features, functionality examples, and hardware demonstrations, some of which will also have videos. But for now, this is a promising step in the right direction to make this a viably productive utility.

Technorati Tags: , , , , , , , , , , , , , , , , , ,

Hamachi Web Status Images

Update…

Unfortunately, LogMeIn figured out they forgot about that page, I guess when people started reading this post and hitting it on their servers. They have removed the text status as well as all the others, and I can’t figure out why they would do such a thing.

I’m also not sure what they’re offering as an alternative either. So if you know, please leave a comment below. Thanks.

Depreciated Process…

A while back, I started a project called tsn.lcl or tsnlocal, but gave up on it when my electricity bill hit $400 in a month.

Today, I decided to fix up the domain name and get it back on the internet – at least to remove it from GoDaddy’s Parking Page – where they’re making money, not me, off of it.

When I got it published I noticed that none of the Hamachi Web Status images worked anymore, and that the link to such an image, redirected to their login page for your Hamachi Management Dashboard. However, upon further investigation, I found that there was not only an Image version of those status instances, but also a text version.

I really wanted to show the online status of all my machines again, so I wrote my own php script to parse that text data, and created some simple images to show on the website based on the returned status.

So here’s the code so you can do the same thing…

The PHP Function

{code type=php}<?php
function hamachiImg($ip) {
$url = “https://my.hamachi.cc/status/text.php?$ip”;
$status = file_get_contents($url);
$status = preg_replace(‘/\d*\.\d*\.\d*.\d* /’, ”, $status);
$image_url = “./images/$status.png”;
return $image_url;
}
?>{/code}
This code creates a $url variable with the address to the text status, based on the $ip that is passed to it. Then it requests the data, removes the ip address and the trailing space, leaving only the status text. On the server, I have a collection of images with the 4 different statuses as their file name, and with that an $image_url is created to be returned.

The 4 possible statuses are:

  • – online
  • – offline
  • – unknown
  • – error

The HTML Code and PHP Function Call

Once you have your php function in the page (I stuck mine before the first <html> tag), you can use the php function to insert the image url when you pass it an IP…
{code type=html}<table>
<tr>
<td style=”width: 100%”>[[Neo]]:</td>
<td style=”width: 100%”> <img src=”<?php echo hamachiImg(’5.37.117.104′); ?>”></td>
</tr>
</table>{/code}
hamachi-exampleOnce you’ve done that, assuming you have entered a valid hamachi IP address, the results should look something like the image at right.

Technorati Tags: , , , ,

Quakecon 2009 & Google Latitude

It’s that time again – time to pack up all your computer crap, go wait in line for 8 hours, just to put it down at a hotel and go home…then come back and stay up for 98 hours straight running on nothing but BAWLS and pure adrenaline.

That’s right – it’s time for Quakecon 2009.

I’ve added a  Google Latitude App to the right sidebar of my blog to show where I am in the whole ordeal – but don’t be fooled, I will have remote access to both locations, from both locations – so no funny business.

Granted this idea works better for people that have to make a longer trek than my 35 mile drive – but it’s still cool none the less.

To get your own badge check out the Google Latitude badge page.

Technorati Tags: , , , , ,