May 18, 2006

PHP CSV to Array functions

You will find other articles relevant to this document in these sections:
Cameron Manderson @ 10:58 am

Documented on PHP.net is the function fgetcsv. I have found that often it won’t do exactly what you want it to do. Thankfully there is many snippets that make it easy for us to turn a CSV file into a 2D array (array[row][column]).

On the PHP.net comments section for fgetcsv, Cristian Zuddas posts a windows based (\r\n line ending) delimeter (semi-colon or comma etc) CSV to Array function that has sparked off many variations.

/**
* Function CSV2Array
* Convert CSV-text to 2d-array
* (delimeter = ';', line ending = 'rn' - only for windows platform)
*
* Reference File: http://php.mirrors.ilisys.com.au/manual/en/function.fgetcsv.php
* @author Cristian Zuddas
* @return array
*/
function CSV2Array($content, $delim = ';', $encl = '"', $optional = 1) {
   if ($content[strlen($content)-1]!="r" && $content[strlen($content)-1]!="n")
       $content .= "rn";

   $reg = '/(('.$encl.')'.($optional?'?(?(2)':'(').
           '[^'.$encl.']*'.$encl.'|[^'.$delim.'rn]*))('.$delim.
           '|rn)/smi';

   preg_match_all($reg, $content, $treffer);
   $linecount = 0;

   for ($i = 0; $i<=count($treffer[3]);$i++) {
       $liste[$linecount][] = $treffer[1][$i];
       if ($treffer[3][$i] != $delim)
           $linecount++;
   }
   unset($linecount);
   unset($i);
   unset($reg);
   unset($content);
   unset($delim);
   unset($encl);
   unset($optional);
   unset($treffer);

   return $liste;
}

Note: I have found it is easy to place these utility functions in a Utility static class such as CSVTools. You can therefore invoke using CSVTools::CSV2Array();
You may find this working out of the box, simply read the complete contents of your file into a variable, using file_get_contents and then invoke the function above with the variable contents. It will return an array and you are on your way.

$dataRows = CSV2Array($fileContents, ',');

You can now loop through the contents using a simple foreach loop as below:

foreach($dataRows as $rowNum => $rowData) { ... }

Remember, you may have problems with this if the line endings are not Windows or MS-DOS based. Typically on a PC you have no worries when you export from Excel, but on Mac you will have the options to choose the line endings. It would be very easy to edit this to your needs, but is a good starting point.

May 16, 2006

ZLib output compression in PHP

You will find other articles relevant to this document in these sections:
Cameron Manderson @ 5:46 pm

We can make use of ZLib output compression in PHP to compress the HTML output for transport across HTTP (if the browser supports it). This requires a little more server processing time, but can lead to significant speed increase in the transportation of your HTML.
In PHP we need to collect our output in a buffer, then compress it, then send the relevant HTTP headers. PHP can manage most of this for us with an inbuilt gzhandler which determines support for GZIP transmission.
At the top of our script (Or in MVC this could be included in our ActionDispatcher) where we start to produce output we set ZLib event handling on:

// Set the ZLib for compression
ini_set('zlib.output_compression_level', 4);  // 1-9 4=Not too CPU intensive

We then start our output buffer which calls back the function “ob_gzhandler” when we flush it.

ob_start("ob_gzhandler");

At the end of our script once we have generated all our output, we need to flush/clean out our buffer, with the call:

ob_end_flush();

You can use FireFoxes Live HTTP Headers plugin which allows you to see that your PHP page is correctly generating your compressed output. You should see a request by your browser, such as:

GET /index.php?do=task HTTP/1.1
Host: localhost
User-Agent: Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.8.0.3) Gecko/20060426 Firefox/1.5.0.3
Accept: text/xml,application/xml,application/xhtml+xml,text/html;q=0.9,text/plain;q=0.8,image/png,*/*;q=0.5
Accept-Language: en-us,en;q=0.5
Accept-Encoding: gzip,deflate
Accept-Charset: ISO-8859-1,utf-8;q=0.7,*;q=0.7
Keep-Alive: 300
Connection: keep-alive
Cookie: PHPSESSID=ABC123ABC123ABC123ABC123ABC123ABC123
Cache-Control: max-age=0

Followed by a response such as below:

HTTP/1.x 200 OK
Date: Tue, 16 May 2006 06:38:28 GMT
Server: Apache/2.2.0 (Win32) DAV/2 mod_ssl/2.2.0 OpenSSL/0.9.8a mod_autoindex_color PHP/4.4.1-pl1
X-Powered-By: PHP/4.4.1-pl1
Expires: Thu, 19 Nov 1981 08:52:00 GMT
Cache-Control: no-store, no-cache, must-revalidate, post-check=0, pre-check=0
Pragma: no-cache
Content-Encoding: gzip
Vary: Accept-Encoding
Content-Length: 2074
Keep-Alive: timeout=5, max=95
Connection: Keep-Alive
Content-Type: text/html

If you are trying to make large blocks of HTML transmit faster, at the very very very slight performance degredation server side generating the file this may be an appropriate way of speeding up your clients requests. You could even incorporate this into your caching algorithm, and extend the callback function to cache the compressed content.

PHP Listing files in a directory

You will find other articles relevant to this document in these sections:
Cameron Manderson @ 5:23 pm

There are numerous variations to loop through a list of files in a directory in PHP. Here are a couple of simple ways:

Variation 1:

$folder = dir("/path/to/folder");
while($folderEntry = $folder->read()) {
    // $folderEntry is the resource. You can now check against it.
}

Variation 2:

if ($handle = opendir("/path/to/folder")) {
    while (false !== ($file = readdir($handle))) {
        // $file is the resource
    }
}

Both use assignment in a while loop to not only get the resource but terminate looping through your results. Variation 2 includes a condition to see if there were issues while openning the directory. You should consider how you will deal with these in your code.

XML Flash Actionscript Tools

You will find other articles relevant to this document in these sections:
Cameron Manderson @ 11:15 am

A while ago helped out a designer (Sacha Jerrems) with some ActionScript XML functions that helped him retrieve nodes and node values instead of using firstChild etc.

Instead of using for loops to locate child nodes, and then go into them, we can make simple function calls to do the work for us.

Example Use

Say we have a valid XHTML document, with a node named ‘title’. To get its value we could simple call:

trace(getValue(getNode('title', xhtmlDoc)));

This method allows us to pipe the results without needing to assign them to variables etc. It can typically compress your code from 10s of lines down to a single assignment.

The Actionscript

/**
 * Searches through an XMLNode's children to locate a particular child node
 * 
 * @param String nodeName The nodeName to locate
 * @param XMLNode parent The parent to search through
 * @returns Found node or null if it could unable to locate a match
 * @author Cameron Manderson <cameronmanderson@gmail.com>
 */
function getChild(nodeName, parent) {
  return getNode(nodeName, parent, false);
}
 
/**
 * Searches Recursively through an XMLNode to locate a particular 
 * child node
 *
 * @param String nodeName The nodeName to locate
 * @param XMLNode parent The parent to search through
 * @param boolean recursive Whether to search recrusively
 * @returns Found node or null if it could unable to locate a match
 * @author Cameron Manderson <cameronmanderson@gmail.com>
 */
function getNode(nodeName, parent, recursive) {
  // Check that we are not looking through or for undefined variables
  if(nodeName == undefined || parent == undefined) {
    return null;
  }
  if(recursive == undefined) recursive = false;
  var i = 0; var locatedNode = null;
  // Check parent for match
  if(parent.nodeName == nodeName) { 
    return parent;
  }
  // Check through the child nodes until the particular child node is located
  for(var i = 0; parent.childNodes && i < parent.childNodes.length; i++) {
    // look to see if the child is what we want
    if(parent.childNodes[i].nodeName == nodeName) {
      return parent.childNodes[i]; 
    }
    // if we are recursing, recurse into child
    if(recursive) {
      locatedNode = getChild(nodeName, parent.childNodes[i], recursive);
    }
    if(locatedNode !== null) {
      return locatedNode;
    }
  }
  return null;
}

You could also then use a simple getValue() function such as below to help you retrieve a node value.

function getValue(node) {
  if (node && node.firstChild) {
    return node.firstChild.nodeValue;
  }
  return "";
}

Hopefully this helps you quickly find the power of XML with Flash

P.S. I request that you leave my name in the functions if you use them. Code is released under our standard LGPL. Which means it is free for you to use, but you must leave the code intact. If you make changes to the code, you should email them back to me. I wrote this a while back and it is probably time for me to make it AS2, but atleast it is more backward compatible.

Extensis Portfolio Help

You will find other articles relevant to this document in these sections:
Cameron Manderson @ 10:53 am

For those of you who are looking for help familiarising/extending the functionality of Extensis Portfolio software, a great site that I recommend (very complete) is http://www.portfoliofaq.com/

Portfolio allows you to manage an image catalog, which can power a SQL database which you could then use their NetPublish software, or write your own frontend interface, to allow people to browse/shop through the photos.

I have to checkout the software to get up a quote for development by tomorrow. So far the contact I was put in contact with Stephen from PICA was very helpful.

May 12, 2006

CSS - IE Hacks Recommendations

You will find other articles relevant to this document in these sections:
Cameron Manderson @ 5:01 pm

I have been doing some compliance based development at the moment, and I found the easiest way of handling your CSS is as follows (my current recommendation):

Create a directory for each major media, e.g. “css/screen” and “css/print”. I tend to prefer seperating my CSS into two sheets. Layout CSS (layout.css) purely defines any required layout of divs, and mainly governs the CSS properties; float, margin, padding, position, top, left, overflow etc. All those relating to laying out our design. The site CSS (site.css) defines our other global colours, backgrounds, fonts, borders and the like.

Usually this break down allows us to work in a series of steps.

  • Our first it to write pure (validating) HTML, writing it looking like a beautiful word document, without any formatting, but concentrating on clean clean code, valid code and follow all recommendations programmatically required by W3C accessibility guidelines.
  • The second step is to step into the Layout mode, where you position our elements into our layout.
  • Our third is to make the site rich with colour and match our PSD/Design.

I have found this approach usually allows a few different developers to work concurrently, as one can work on layout, while another is extracting graphics and worrying about colours etc.

I start with the “screen” media and then once done I work on the “print” media. Most of the time all we have to do is hide out components, such as verbose navigations etc, using the simple CSS properties, such as

div.nav {
display: none;
visibility: hidden;
}

We could go further and colour up the print out, but generally we like it clean and easy to read, most of the time Serif fonts will print and read easier.
Next when I go to include the CSS in the header I specify the media with the media attribute;

<link rel="schema.dc" href="http://purl.org/metadata/dublin_core_elements" />
<link href="css/screen/layout.css" rel="stylesheet" type="text/css" media="screen, tv, projection" />
<link href="css/screen/site.css" rel="stylesheet" type="text/css" media="screen, tv, projection" />
<link href="css/print/layout.css" rel="stylesheet" type="text/css" media="print" />
<link href="css/print/site.css" rel="stylesheet" type="text/css" media="print" />

Now that I have organised my folders correctly, and I have specified the media it is easy to analyse where to make various changes to my CSS code.
Most importantly, to work across different browsers such as Internet Explorer (IE6 PC or IE5.1 Mac) It is important to include some conditional inclusion of CSS that will overwrite previously declared CSS rules for a specific browser. These are often called Box Hacks. There are many box hacks out there, often they are about stopping the processing of a CSS rule by a browser’s CSS “parser” at a certain point; usually some browsers will continue reading when others decide not to.

Often this means that you end up with a CSS document full of various hacks and definitions of widths and heights, paddings and margins, side by side, without really allowing us to deal with them seperately. Often this ends up like a soup of code not making much sense, with various asterisks, and useless definitions you are unsure if they are being picked up or not.

I prefer to define all standards compliant CSS from the start, without worrying about IE compliance. As IE requires changes to CSS rules to match the normal, we add extra style sheets after we have included all our standards complaint CSS rules and then set them to overwrite the rules previously defined for individual non-complying sheets. Doing this means that I like to start with a standards compliant browser such as Mozilla Firefox for development. Get it looking right here, validating both your XHTML/CSS and Accessibility.

Now to worry about those browsers that don’t comply to the standard “box model” or handle rules the same as the standard.

The other you include your CSS documents in your HTML is very important. If you have defined rules in one sheet you include, if the next file you include defines the same property it will overwrite the previous rules. We take advantage of this by creating 2 seperate CSS documents that will contain our CSS hacks, cleanly presented in their own document. I recommend naming them “css/screen/IE6.css” or “css/screen/IE51.css” depending on which rules you are overwriting.

You can then include the extra lines in your header of your HTML after your standards compliant SCREEN/PRINT media CSS docs. e.g.

PC IE 6 Box Hack

Seperate style sheet (seperate CSS document) overwriting specific rules without cluttering your standards compliant CSS docs. This also is forward compatible with IE7 as it is only included on upto and including version IE6, and is recommended by Microsoft:

<!--[if lte IE 6]>
<style type="text/css" media="screen, tv, projection">
@import "css/screen/ie6.css";
</style>
< ![endif]-->

MAC IE 5.1 Box Hack

By seperate style sheet. This exploits the fact that IE Mac 5.1 would read in this style sheet where others will not:

<!-- MAC IE start -->
<style media="screen" type="text/css">
@import("css/screen/ie51.css");
</style>
<!-- MAC IE end -->

Overall stucturing your CSS this way allows us to centrally write standards compliant CSS and creates a nice workflow for handling our CSS. You can start with firefox, then load into IE and place in some specific rules that will make your CSS work as predicted in IE.

Making good use of the media attribute is important also.

Google gets Trendy!

You will find other articles relevant to this document in these sections:
Richard Lee @ 12:14 pm

A new Google thing, “Google Trends” works similar to the regular Google but instead of producing a list of web pages it provides various statistics on how the rest of the world is searching your topic. Enter up to five topics and see how often they’ve been searched for on Google over time. Google Trends also displays how frequently your topics have appeared in Google News stories, and which geographic regions have searched for them most often. For more info http://www.google.com/trends/about.html

Other interesting Google flavours I recommend:

XBox Live Upgrades

You will find other articles relevant to this document in these sections:
Richard Lee @ 10:27 am

This week at Electronic Entertainment Expo in Los Angeles, Microsoft announced upgrades to its Xbox Live online game service, which includes a feature that will allow players on its Xbox 360 console to share games and messages between PCs and mobile phones.

More on XBox Live…

The online service launched in 2002 allows video game players to compete against one another, exchange text and voice messages and download new game levels and simple arcade titles. Xbox Live quickly became the signature of the Xbox console, and is one of the key strengths of the Xbox 360.

May 9, 2006

Anti-Spam ACTIVATED

You will find other articles relevant to this document in these sections:
Richard Lee @ 5:56 pm

Spammers, time to stick your head between your legs and kiss your collective asses goodbye.

Due to the recent onslaught of comment spam we at Melbourne Chapter have been collecting IP addresses and reporting offenders on a daily basis. Today we went one step further and installed the Akismet anti-spam software, and I’m happy to say since the installation moderating comments has never been easier! - All spam is filtered and automatically deleted.

Thanks Auttomatic for this kickass plugin!!!

For more information on Akismet and how to support the Akismet project please read here.

May 8, 2006

Bugs: Shipping Tax not passed onto final payment

You will find other articles relevant to this document in these sections:
Richard Lee @ 11:54 pm

March this year I reported a case where OSCommerce was not successfully passing shipping tax onto the final payment amount. I found that although the order total was indicated on the confirmation page, the amount processed by the Payment Module was always less the shipping tax amount! A quick diagnosis of the problem indicated that OSCommerce’s developers had intended to calculate once for output on the confirmation page, and then a second time for Payment processing. However, due to the incorrect inclusion order of source files the latter calculation would not complete before the transaction of the Payment Module began.

Resolving this bug is relatively straight forward (as always please backup, and use at own risk):


 
/*
$Id: checkout_process.php,v 1.128 2003/05/28 18:00:29 hpdl Exp $
 
osCommerce, Open Source E-Commerce Solutions
http://www.oscommerce.com
 
Copyright (c) 2003 osCommerce
 
Released under the GNU General Public Licensend
 
amended by Richard Lee
*/
 

CHANGE


$payment_modules->before_process();
 
require(DIR_WS_CLASSES . 'order_total.php');
$order_total_modules = new order_total;

TO


// make sure we run total's calculations first
$order_totals = $order_total_modules->process();
 
$payment_modules->before_process();

« Previous PageNext Page »