Share/Save/Bookmark Subscribe

Friday, December 31, 2010

Fun with initialization order

Here's something I meant to post ages ago, when I was doing J2ME to Flash conversions, and got caught out by assumptions about the evaluation order of values passed to a method or to initialize an array. It's one of those really subtle issues that had me scratching my head to figure out what had gone wrong in a piece of code.

Consider the following (pseudo)code:
1 2 3 4 5 6 7 8 9 
function evalTest(val1, val2, val3)
{
     print("val1: "+val1+", val2: "+val2+", val3: "+val3);
}

int val = 0;
int arr = { ++val, ++val, ++val };
print("arr: ["+arr[0]+", "+arr[1]+", "+arr[2]+"]");

Now what would you expect the output to be? I had unwittingly assumed the result would consistently be:
arr: [1, 2, 3]
val1: 1, val2: 2, val3: 3

As it turns out, the answer varies from language to language (which is why I got snagged by code working 'correctly' in one language but 'breaking' in another):

Java:
1 2 3 4 5 6 7 8 9 10 11 
int val = 0;
int[] arr = {++val, ++val, ++val};
System.out.println("arr: ["+arr[0]+", "+arr[1]+", "+arr[2]+"]");

val = 0;
evaluationTest(++val, ++val, ++val);

void evaluationTest(int val1, int val2, int val3) {
  System.out.println("val1: "+val1+", val2: "+val2+", val3: "+val3);
}

Result:
arr: [1, 2, 3]
val1: 1, val2: 2, val3: 3
 
Actionscript:
1 2 3 4 5 6 7 8 9 10 
function evaluationTest(val1:Number, val2:Number, val3:Number) {
        trace("val1: "+val1+", val2: "+val2+", val3: "+val3);
}
var val:Number = 0;
var arr:Array = [++val, ++val, ++val];
trace("arr: ["+arr[0]+", "+arr[1]+", "+arr[2]+"]");
 
val = 0;
evaluationTest(++val, ++val, ++val);

Result:
arr: [3, 2, 1]
val1: 3, val2: 2, val3: 1
 
Some others:
C++ undefined:
C# guaranteed to be right to left:

Posted via email from Matt's thoughts

Saturday, December 18, 2010

DSTV Mobile on Nokia N96

With all the marketing Multichoice is doing around DSTV Mobile, I thought I'd brush off the N96 and put it's DVB-H receiver to the test again (previous attempts proved fuitless). This time around it all worked pretty smoothly on the first attempt-if a bit confusingly. Nokia's "Live TV" allowed me to purchase a DSTV Mobile subscription (currently free). I did find though that on restarting the phone after removing and reinserting the SIM, the app had lost my subscription data-no big deal for free promos, but I can see some really irritated users when their paid subscription goes missing. Note that while the app doesn't use 3G to receive the actual TV signal, it does need a cellular data connection to validate licensing (which means no using the service out in the bundus to catch the cricket or rugby).
The app itself is actually pretty well put together, with different program guide views in portrait and landscape, the ability to set program alarms and auto-tuning events, and both fullscreen and windowed (with programming info) views. Parental controls are enabled by default, and set to an age limit of 15, so it's possible first time viewers will have to hunt around for the default unlock code (12345 in case anyone gets here searching for it). Another interesting quirk is that the app locks the video down against both screenshots of content (note the attached shaky cam files taken from my iPhone) and TV out. I suppose I'm not entirely surprised, but this level of lockdown seems seriously ridiculous considering you'll ultimately need a full DSTV subscription anyway when the service goes paid in a couple of months.
The content available in the DSTV mobile package is fairly limited, with the focus heavily on sports, but what's there comes through clearly. I have to say I was pleasantly surprised at both the video and audio quality and the glitch-free nature of the experience, this is no frustrating streamed video. Not being much of a TV watcher, and given the content, I can't say I could see myself paying for the service but I can definitely see the value to avid sports fans and even the 'distract the kids' value of Cartoon Network.

Download now or watch on posterous
ChannelO.mov (1054 KB)

Posted via email from Matt's thoughts

Saturday, October 23, 2010

Testing out the new posterous app

Posterous has for some time had an app on the iPhone called "PicPosterous", focused on posting multiple images from the device direct to a posterous album (and of course optionally adding a blog post). Checking on the app store today, I saw the sneaky buggers had at some point released a new app called (imaginatively enough) "Posterous".
This is my first post from that app, so let's see how it goes. I'm most interested in seeing if autoposting of multiple images works (in the past, in Facebook for example, a new album would be created by PicPosterous with just the first image, the rest would all make it to posterous but not facebook). To test this I've added two hopefully prescient screenshots from the incredibly awesome and devilishly addictive iPhone game, "game Dev Story". If you haven't checked it out yet, do so now (but first warn your loved ones they may not see you for a couple of days. Or weeks)!
From an editing point of view, the new posterous app uses the standard iPhone editor (so no text styling), and allows enabling or disabling geotagging, autoposting and private settings for the post. Tags can be added (with a nifty chooser that shows past tags), and of course media can be attached. At this stage only photos and videos can be attached (new or from the library) but no audio recordings. There's also unfortunately no multiple-select for images and videos, so each has to be added individually.
In addition to posting to any of your posterous blogs, the app also allows you to view past posts. I've yet to check if they can be edited, and since there's no way to save a draft, I'll try it after posting this.
Like posterous itself, the app is dead simple and intuitive, just what you need (well, most of it) and no more.

Posted via email from Matt's thoughts

Saturday, September 25, 2010

Molting rain spider

We lucked out catching this rain spider while it was molting at a
friend's house. The wives wanted to kill it :P

Posted via email from Matt's thoughts

Saturday, August 28, 2010

Reefsteamers train to magaliesburg

Today we took the Reefsteamers steam train from Maraisburg station to Magaliesburg. The train departs a little after 9am, winding out of Joburg at a nice lazy pace. We had initially tried to book a 3 seater coupe, but they were sold out for this trip so we settled for regular single seats. This turned out not to be a great idea, the regular seating area is way too noisy for those of us without kids and the screaming tolerance they build ;) We were lucky enough to find a coupe who's occupants hadn't pitched and 'upgraded'. I'd definitely suggest anyone planning on taking the trip to hold out for one of these compartments, they make for a great experience. Make no mistake, these are vintage commuter trains in their original state, no Rovos level niceties, but they are a nice way to relive those old trips to holiday spots by rail.

After about two and a half hours of relaxed travel through the countryside (including some shunting stops on the single gauge track), the train dropped those travelers who had booked for lunch at the Magaliesburg Country Hotel, and then carried on to drop the rest off at the self catering picnic grounds. Sadly the lunch at the hotel wasn't much to write home about, but the dessert at Wimpy around the corner was great. Whether going with kids or without, I'd suggest skipping on the hotel dinner and rather going for a Wimpy burger or the picnic option.

The trip back was somewhat shorter at about ninety minutes, due to fewer shunting stops, but was no less relaxing-especially with bellies full of food.

Overall, this was a fun experience at a reasonable price. It would also definitely be a great way to entertain kids and introduce them to an older, slower paced way of doing things.

Posted via email from Matt's thoughts

Thursday, August 26, 2010

The Harvest

The Harvest is a Luma Arcade developed and Microsoft Game Studios published title under development for the upcoming Windows Phone 7 platform. The game is developed in C# using Microsoft's XNA set of API's on top of the .Net Compact Framework. The high production quality bar for a game on a (not yet final) mobile platform meant serious work on squeezing every ounce of performance out of the engine. In addition to the usual engineering challenges of developing a truly AAA 3D title, and working closely with the MGS publishing team in a senior role, this project gave me the incredible opportunity to visit Microsoft in Seattle to work with them directly on performance challenges, gameplay and usability fine tuning, audio balancing and more. 

From Xbox.com:
On a future Earth, the invading alien Harvesters use humans and animals to create cyborgs: crude amalgamations of flesh and machinery. Mankind, in the form of the Global Defence Force, now fights a war against The Harvesters using human controlled mechanized infantry units. As a member of the GDF army, you have been sent to investigate reported Harvester activity in the ruins of an ancient city once used as a military base. As you explore, fight off wave after wave of The Harvester horde, find hidden upgrades, and defeat imposing enemy boss units in order to return Earth to its rightful inhabitants.
Designed from the ground up to be the best looking 3-D mobile phone game to date, The Harvest™ features innovative touch screen gameplay, along with visceral combat, and opportunities for exploration, character customization, and more. This action RPG experience is an Xbox LIVE-enabled game for Windows Phone 7, and will immerse you into a deep and intriguing story where it is vital that the GDF is victorious.

For videos of The Harvest in action, see the recently posted playthroughs on GameTrailers.com.

Posted via email from Matt's thoughts

Tuesday, August 24, 2010

Champ Chase

Champ Chase was a project by I-Imagine for the Nelson Mandela Children's Fund's "Champion for Children" campaign. Released as an online flash title as well as a J2ME mobile game, the challenges here were to quickly build a Flash equivalent to I-Imagine's flexible J2ME engine, as well as expand on the company's in-house high score system and communicate with it from flash.

The game is a 2D platformer aimed at educating young players about various dangers they may encounter such as criminals, drug abuse and online predation. This was achieved through a combination of stylized characters associating each concept with a familiar object or animal with typically negative connotations, as well as more direct information provided at key points. The game is simple and fun, placing the player in the role of a protector saving children from these dangers.

Posted via email from Matt's thoughts

Sunday, August 22, 2010

Death of optimism

I have always been supportive of South Africa and positive about it's people and future, the guy who would argue down naysayers at work, at the dinnertable, wherever negative sentiments might arise. For every pessimistic complaint about our politicians, our crime levels and our problems I would provide a counterpoint.

My family has been on the victim's end of it's fair share of property and contact crime. We've been tied up, stabbed and held at gunpoint in armed robberies. We've had cars and small items and even the entire stock of our shop stolen. Most families in this country have had similar experiences, regardless of race or background. Despite this I have always sung South Africa's praises to all who would listen, firmly believing these problems would be solved.

For every corrupt politician shamelessly leeching funds needed by the poor and downtrodden to fund an opulent lifestyle, I have firmly believed there is another dedicated, hardworking individual with a love for their homeland  and the fire of justice in their belly. For every potholed road I've been able to point to a glowing new advancement in public transport. For every dirty downtown street I've been able to counter with encouraging stats about waste management and recycling. Dropping educational standards? Growth in industry and sheer number of people getting an education will sort that out in the long term.

But none of that matters anymore. As of this Thursday past my optimism is gone, taken by the thugs with knopkierries beating on a door, the other side of which had been barricaded by my wife and one of her patients to keep these monsters out. Who were these vicious villains? Were they drugged up kids on a narcotic warpath? Career criminals looking for their belongings? Perhaps escapees from the mental ward come to exact their revenge on the institution? No, they were my wife's highly trained and respected colleagues in medical work. Nurses and other staff that work in the public hospitals. Professionals entrusted with the care of our sick and downtrodden, wanting to drag co-workers out of the hospital and physically assault them for not partaking in their illegal strike. Health care workers forgoing their oath of service to haul non-striking theater staff out of active operating theaters, regardless of the already anesthetized patients who's lives lay in the balance.

At the same time schoolbusses were announcing they would discontinue their services during the strike action for fear of being targeted. By schoolteachers. Let me spell that out: school buses full of children the potential target of violence by school teachers. I  am completely in favor of industrial action, of underpaid and undervalued workers having the right to express their unhappiness and disillusion, especially when these are the workers carrying out two of the most important jobs imaginable: caring for our sick and teaching our young. However strike violence is not a valid part of this action, and nothing on earth justifies these same caregivers turning on each other and on their charges, nothing.

Because of the hair-trigger nature of racial debate in our country I have to emphasize that this is not about race. There were members of various races on both sides of that door. This is simply about the people of our country failing at a basic human level-to have empathy for our sick and young. Even in times of war, hospitals and schools are considered places of safety and refuge. Violating them in any way whatsoever is looked on with great scorn and leads to trials in The Hague. Yet here are our own medical staff and teachers violating that universal principle-for a pay rise. What kind of a people must we be, when those in our community we are expected to trust more than any other must be feared like common thugs? How can we be expected to carry on "Leading SA" and hoping for a bright future for our beautiful rainbow nation? Well I for one can't. My hope and faith and optimism -fundamental parts of my being- have been wrenched from me by the dogs that threatened the life of my wife while she was in the act of helping someone.

Cry the Beloved Country. Indeed.

Posted via email from Matt's thoughts

Sunday, June 27, 2010

Great Netbook case on the cheap

Nat and I were in a PNA for something, and spotted their leather Bible
cases-which happen to be just the right size for a netbook and are
under 200 bucks!
This is a simple one, there were full combos with a separate
compartment for a (paper) notebook, pen loops, etc in the same price
range. Compare that to 300+ for a neoprene sleeve, and you have a
damned good deal.

Posted via email from Matt's thoughts

Saturday, June 12, 2010

Some great productivity keyboard shortcuts in Windows 7

Windows 7 may basically be Vista with a fresh coat of paint and with a bit a of steroid injection, but it also comes with some great productivity enhancements to the UI, like Aero Snap (pulling a window to the top or sides of the screen snaps it to fullscreen or half screen, respectively). What's even better for keyboard-centric users like myself are the keyboard shortcuts around those features:
  • Windows Key + Left/Right: Resizes the current window to half the size of the screen it's currently on, and snaps it to the left or right edge of the screen, respectively. Pressing one of these repeatedly will cycle the window through original size and snapped half size across different screens. These are fantastic for comparing documents side-by-side.
  • Windows Key + Up: Maximizes the current window.
  • Windows Key + Down: Restores the current window to it's previous size if maximized, otherwise minimizes it.
  • Windows Key + Shift + Left/Right: Switch the current window between screens. Really useful when you usually have your notebook dual screened with an extra monitor, and windows start on the wrong screen (ie hidden) when that extra monitor's not available :)
For mobile warriors, these two are great:
  • Windows Key + X: Opens the Mobility Center, a really useful control panel that allows you to quickly change audio, power, wifi, display, sync and presentation settings.
  • Windows Key " P: Opens a panel that lets you quickly cycle between multiscreen/projector layouts.
All the Windows 7 shortcuts are available on Microsoft's site, all the usual suspects are there, as well as some new ones not mentioned here.

Posted via email from Matt's thoughts

Monday, May 24, 2010

Flash development workflow for traditional dev teams, Part 2

Part 1 of this walkthrough ended off with a flash animation linked up to a main application class that would allow regular updates of that application. This time around we'll see how to access objects in your application added in Flash from the library. Once these are in place, your artists can go nuts customizing them, as long as the basic setup stays the same.

The Menu and Button classes
Let's set up a simple menu class that will allow us to continue to gameplay, or quit the animation. In Flashdevelop, create a new class in your package (right-click the package, Add->New Class) called Menu, specifying MovieClip as it's base class. Add two MovieClip members to it for the buttons, called playBtn and quitBtn:
1 2 3 4 5 6 7 8 9 10 
/**
* Play button.
*/
var playBtn:MovieClip;

/**
* Quit button.
*/
var quitBtn:MovieClip;

As with the App class, add basic singleton functionality, but this time initialize the singleton in the menu constructor:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 
/**
* The Menu instance.
*/
private static var instance:Menu;

/**
* Singleton accessor.
*/
public static function getInstance():Menu
{
return instance;
}

 /**
* Creates a new Menu and sets the singleton pointer.
*/
public function Menu()
{
instance = this;
}

Note I'm not clearing the singleton pointer at any stage, but it will be replaced the next time an instance is created, releasing the reference to the last object and allowing it to be garbage collected. This isn't a singleton in the purest sense, but it does allow us global access to the most current instance. Actionscript doesn't have destructors and I'm yet to find a replacement that I'm 100% happy with.

Finally, add a function onButtonReleaseHandler to handle button presses, and implement the (extremely simple) menu logic:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 
/**
 * Handles an onRelease event.
 * @param source The MovieClip that triggered the onRelease event.
 */
public function onButtonReleaseHandler(source:MovieClip):Void
{
switch(source) {
case playBtn:
App.getInstance().playGame();
break;
case quitBtn:
fscommand ("quit");
break;
}
}

You'll also need to import the App class at the top of the file, using it's fully qualified name:
1 
import us.benic.matt.App;

Note: I've switched on the actual source object here. Actionscript's switch statement is extremely flexible, unlike that in C++ and Java, any object can be used as a case, including strings.

Here is the completed Menu class:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 
import us.benic.matt.App;

/**
* Menu for the Flash Workflow demonstration.
* @author Matt Benic
*/
class us.benic.matt.Menu extends MovieClip
{
/**
* Play button.
*/
var playBtn:MovieClip;

/**
* Quit button.
*/
var quitBtn:MovieClip;

/**
* The Menu instance.
*/
private static var instance:Menu;

/**
* Singleton accessor.
*/
public static function getInstance():Menu
{
return instance;
}

/**
* Creates a new Menu and sets the singleton pointer.
*/
public function Menu()
{
instance = this;
}

/**
* Handles an onRelease event.
* @param source The MovieClip that triggered the onRelease event.
*/
public function onButtonReleaseHandler(source:MovieClip):Void
{
switch(source) {
case playBtn:
App.getInstance().playGame();
break;
case quitBtn:
fscommand ("quit");
break;
}
}
}

Now we need a simpleMovieClip subclass called Button that will notify the menu when it is pressed. Flash does have it's own Button class, but it's really inflexible in that Button components can't use a custom Button subclass. The norm seems to be to just use a custom MovieClip subclass, and the functionality in the Flash Button class can easily be implemented anyway. For our purposes, a simple class that calls the Menu singleton's onButtonReleaseHandler when it is released will suffice:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 
import us.benic.matt.Menu;

/**
* Button for the Flash Workflow demonstration.
* @author Matt Benic
*/
class us.benic.matt.Button extends MovieClip
{
/**
* Creates a new button and sets it's onRelease to notify the Menu instance.
*/
public function Button()
{
// Notify menu instance when released
onRelease = function ():Void {
Menu.getInstance().onButtonReleaseHandler(this);
}
}

}

Changes to the App class
At this point very little needs to be added to the App class, it just needs the function the Menu class called, playGame. This will move the main clip to the Level frame:
1 2 3 4 5 6 7 8 
/**
* Play the game.
*/
public function playGame():Void
{
gotoAndStop("Level");
}

You may also want to remove the trace call in onEnterFrameHandler. It's demonstrative purpose has been served, and outputting text on every frame will just slow down the animation.

The Menu and Button MovieClips
Now we need the actual visual elements used for the menu. First create a new MovieClip in the library (Ctrl+L or Windows-Library to open the library, right click in the library->New Symbol...) called PlayButton. Set it's Type to MovieClip, check the Export for ActionScript checkbox, and specify it's Class as your fully qualified Button class's name (ie including the package):

 

Clicking Ok to dismiss the Create New Symbol dialog causes Flash to open that symbol for editing. Use the flash tools to create a simple button. Eg add a Rectangle for a background, and a TextElement for the text to end up with something similar to this:
 
Copy that symbol as a starting point for the Quit button, right click the symbol in the Library and select Duplicate. In the Duplicate Symbol dialog name the symbol QuitButton and as before enable Export for ActionScript and set it's class to your Button class:


Again, dismissing the dialog with Ok opens the component on the stage. Edit it to say Quit instead of Play.

Now create another new Symbol, this time calling it Menu and setting it's class to your Menu class:


Drag the PlayButton symbol from the Library to the stage, and then do the same with the QuitButton. The result should look something like:

The buttons now need to be named to match the members added to the Menu class earlier. To do this, click on a button on the stage to select it (not it's template control in the library), open the Properties window with Ctrl+F3 or Windows->Properties and replace the <instance name> text in the topmost textbox with the appropriate name. Your Play button should be called playBtn and your Quit button quitBtn:


Putting it all together
The last thing to do is add your newly created menu to the appropriate frame at the top level of the timeline. Return to the top level by clicking on Scene 1 above the stage. In the timeline, on the Objects layer, add new keyframes (right click->Insert Keyframe) below the Menu and Level labels (should be frames 10 and 20 respectively). Now with the new keyframe under Menu selected, drag the Menu symbol from the library onto the stage. Frames 10 to 20 on the Objects layer should now be grayed out to indicate content exists on those frames.

 

If you now run the animation with Ctrl+Enter, the menu will be displayed, and clicking Play will take you to the Play frame (which is currently empty). The Quit button may appear to do nothing, but that is just because fscommand ("quit") has no effect when run from the Flash environment. When the generated .swf file is run by double clicking it in an explorer window, the effect is as expected.

The full project so far is attached to the post. That's it for part 2, the next post will go into adding and manipulating objects programmatically.

A note on variables linked to stage objects
In this example, I used variables within a class who's only link to visual objects is their name. That's scary. Actionscript won't tell you if one of these objects is missing, it will just carry on as if nothing is wrong. You can't even expect an error or exception when you call a method on one of these nonexistent member objects. That's terrifying. Now you may be tempted to insist on creating all objects yourself, programmatically, but that's once again taking a certain amount of creative control (placement) away from the artists, which is kind of the whole point of Flash. The only way to be 100% sure objects you expect to be there are actually there is to check them against null and handle the missing case by throwing an exception/error or making the mistake known some other way.
Related to this is the interesting little issue that numeric values in flash are represented by the Number class, as opposed to some kind of integral type, and must be properly initialized like any other object or will be null. This can catch you by surprise with some really wierd behavior, so if you start seeing NaN's in output, there's an uninitialized Number somewhere.

Click here to download:
WorkFlowProject.zip (10 KB)

Posted via email from Matt's thoughts

Displaying UTF8 from MySQL with PHP

I had some issues displaying localized text in a PHP based internal tool recently, it turns out the solution was really simple-the MySql connection just needs to know that the connection must be UTF8. Probably no-brainer stuff for all you PHP-Ninjas.. news to me :)

To do this with a PDO connection, just add an init command when you create the PDO command:

1 2 3 
$this->pdo = new PDO("mysql:host=".$this->host."; dbname=".$this->databaseName,
$this->user, $this->password,
array(PDO::MYSQL_ATTR_INIT_COMMAND => "SET NAMES utf8"));

Thanks to Rob Allen for the tip, variation for other connection methods can be found on his blog.

Posted via email from Matt's thoughts

Friday, May 21, 2010

Some useful regular expression patterns when porting code between languages

I'm currently moving a lot of code from Java to Actionscript, and regex has been a lifesaver. Here are some of the patterns that proved invaluable, and that would work on most c-style languages. The Actionscript replacements are obviously specific to that language, but changing them for a different output language really would be trivial:

Find non-parameter variable declarations and assignments
Note: this will find returns as well, see the next pattern
(\w+)(\s)(\w+)(;|\s=)

Flash replacement:
var$2$3:$1$4

Will replace:
    int myInt;
    boolean myBool = true;
With:
    var myInt:int;
    var myBool:boolean = true;   

Find resulting returns in Flash
This will match all the wonky return statements resulting from the previous replacement.
var(\s)(\w+):return;

Flash replacement:
return$1$2;

Will replace:
    var true:return;
With:
    return true;

Find parameter variable declarations
(\w+)(\s)(\w+)(,|\))

Flash replacement:
$3:$1$4

Will replace:
    public int foo(int intParam, boolean boolParam) {
With:
    public int foo(intParam:int, boolParam:boolean) {

Find function signatures with parameters in c/java format
(\w+)(\s)(\w+\([\s?\w\s\w+,?]*\))(\s?\{)

Flash replacement:
function$2$3:$1$4

Will replace:
    public int foo(int intParam, boolean boolParam) {
With:
    public function foo(int intParam, boolean boolParam):int {


Find function signatures with parameters in Actionscript format
(\w+)(\s)(\w+\([\s?\w+:\w+,?]*\))(\s?\{)

Flash replacement:
function$2$3:$1$4

Will replace:
    public int foo(intParam:int, boolParam:int) {
With:
    public function foo(intParam:int, boolParam:int):int {

Find numeric types
(,|;|\(|\)|=|\s)(int|long|short|float|double|byte)(,|;|\(|\)|=|\s)

Flash replacement:
Number

Will replace:
    var myInt:int;
    long myLong;
    float foo(byte bar) {
With:
    var myInt:Number;
    Number myLong;
    Number foo(Number bar) {

Posted via email from Matt's thoughts

Sunday, May 16, 2010

Untitled

Untitled

Untitled

Untitled

Untitled

Populating and serving a temporary SQLite database file and serving.

Recently I had the requirement in PHP to populate a SQLite file with data from a MySQL database and make it available for download. I was using PDO objects for MySQL, and found I could do the same for SQLite, so the simple answer became to create a temporary SQLite file with PDO, populate it from the existing MySQL PDO object (by querying the required data and inserting it into the SQLite file-no shortcut there unfortunately) allow the user to download it and then delete it. The sample code below excludes the selection from the existing database (which is comparitively trivial) but includes the rest.
One major thing worth noting (and not illustrated here) is that if you're going to be inserting more than a few dozen records, it's worth wrapping everything in a transaction. This may seem overkill for a temporary file that will fail anyway and hit the try-catch if there's a probelm, but it results in massive performance improvements due to PHP doing all the SQL work in memory and writing the transaction to file in one operation. Just don't go doing it with hundreds of megabytes of data ;)


<?php function
outputDownloadHeaders
($path, $filename, $binary = false) { header("Pragma: public"); header("Expires: 0"); header('Cache-Control: no-store, no-cache, must-revalidate'); header('Cache-Control: pre-check=0, post-check=0, max-age=0', false); header('Last-Modified: '.gmdate('D, d M Y H:i:s') . ' GMT'); // Browser specific headers $browser = $_SERVER['HTTP_USER_AGENT']; if(preg_match('/MSIE 5.5/', $browser) || preg_match('/MSIE 6.0/', $browser)) { header('Pragma: private'); // C in control must be lowercase header('Cache-control: private, must-revalidate'); // Must be a number for IE header("Content-Length: ".filesize($path)); } else { header("Content-Length: ".(string)(filesize($path))); } header('Content-Type: application/x-download'); header('Content-Disposition: attachment; filename="'.$filename.'"'); // Tell the client file is binary if ($binary) { header('Content-Transfer-Encoding: binary'); } } function populateSqlite($sqlitefilepath) { // Open the file-creates new file if necessary $pdo = new PDO("sqlite:".$sqlitefilepath); // Create table in the db if needed $pdo->query("CREATE TABLE IF NOT EXISTS test_table ". "(id INT NOT NULL, text VARCHAR(100) NOT NULL, PRIMARY KEY (id));"); // Populate with some data $pdo->query("INSERT INTO test_table (id, text) values (0, 'Hello');"); $pdo->query("INSERT INTO test_table (id, text) values (1, 'World');"); $pdo->query("INSERT INTO test_table (id, text) values (2, 'from');"); $pdo->query("INSERT INTO test_table (id, text) values (3, 'PHP');"); $pdo->query("INSERT INTO test_table (id, text) values (4, 'and');"); $pdo->query("INSERT INTO test_table (id, text) values (5, 'SQLite'); "); // Connection closed by scope return true; } // The filename to present to the client $dbfilename = 'sqlite.sq'; // Temporary file to hold the sqlite db on the host $dbfilepath = sys_get_temp_dir() . uniqid('sqlite') . '.sq'; try { // Populate new file with some data if (populateSqlite($dbfilepath)) { // Prompt the user to save the file locally outputDownloadHeaders($dbfilepath, $dbfilename, true); // Stream the file to the client $file = fopen($dbfilepath, 'rb'); if ($file) { while(!feof($file) and (connection_status()==0)) { print(fread($file, filesize($dbfilepath))); flush(); } fclose($file); } } } catch (Exception $ex) { echo "Oops, something went wrong: $ex->getMessage()"; } // Clean up the file unlink($dbfilepath); ?>

Posted via email from Matt's thoughts

 

Copyright 2007 All Right Reserved. shine-on design by Nurudin Jauhari. and Published on Free Templates

Afrigator