Hi

Welcome to my website: part portfolio, part blog, part place where I can try out new code. Enjoy.



jQuery: Getting an elements position/offset relative to a parent element

Posted 12 Years Ago



Various projects I've worked on in the past have required me to get an element's position or offset that's neither relative to the document's body, nor relative to it's immediate 'position:relative' element.  Up until now I've used very project specific solutions.  Today, I decided to solve the problem once and for all and write my own jQuery plugin to accomplish this.

I've named the plugin offsetRelative (though I included an alias of positionRelative if you prefer that naming scheme).  To call the plugin is pretty simple.  You simply call the offsetRelative() function on the child element you want to get the position of and pass the 'parent' element you want the position to be relative to as the 1st parameter of the function. 

$(child-selector).offsetRelative(parent-selector);



Example

So, if we had a child element with an id of "child-element" and we wanted to get it's left/top position relative to a parent element, say a div that had a class of "item-parent", we'd use this code.

$("#child-element").offsetRelative("div.item-parent");

This would then return the top and left position of the "#child-element" relative to the "div.item-parent" which we could then use as thus:

var position = $("#child-element").offsetRelative("div.item-parent");
alert('left: '+position.left+', top: '+position:top);



Plugin

Finally, for the actual plugin (with a few notes expalaining what's going on):

// offsetRelative (or, if you prefer, positionRelative)
(function($){
    $.fn.offsetRelative = function(top){
        var $this = $(this);
        var $parent = $this.offsetParent();
        var offset = $this.position();
        if(!top) return offset; // Didn't pass a 'top' element
        else if($parent.get(0).tagName == "BODY") return offset; // Reached top of document
        else if($(top,$parent).length) return offset; // Parent element contains the 'top' element we want the offset to be relative to
        else if($parent[0] == $(top)[0]) return offset; // Reached the 'top' element we want the offset to be relative to
        else { // Get parent's relative offset
            var parent_offset = $parent.offsetRelative(top);
            offset.top += parent_offset.top;
            offset.left += parent_offset.left;
            return offset;
        }
    };
    $.fn.positionRelative = function(top){
        return $(this).offsetRelative(top);
    };
}(jQuery));

 
 

Functionality

Just a few notes on how the plugin will function in certain situations. 

If you don't pass a 'top' element in the first parameter of the function we'll simply return jQuery's .position() function's offset (which is relative to the element's nearest reatively positioned parent element).

If the 'top' element you pass isn't a 'reatively positioned' element, meaning that element doesn't effect the viewport at which the element will be positioned, the plugin will return the offset at the element, which is to say the offset in relation to the next 'reatively positioned' element above the 'top' element we passed.

Finally, if we don't find that the 'top' element you passed exists as a parent to the child, we'll simply return the offset in relation to the document's body (the same as would happen with jQuery's .offset() function).


Let me know if you find any bugs or have any suggestions.







HTML tag wishlist: Event, Time, Phone, Audio, Video

Posted 14 Years Ago



So I couldn't sleep again and my ever working brain was thinking of things it shouldn't be thinking of at 7 AM.  For some context, I got an iPhone about a month ago and am very impressed with how easy and simple it is to use.  I'm not a big Apple guy (I find some Apple people a little dickish about their love of everything Apple), but with the iPhone I really see how the Apple brands simplicty and intuitivness can be used to great effect.  Everything just seems to work together.  See a phone number on a website, click it and you can call it. See an address, click on it to open it in the Maps app. (Note: I've never used either feature and I don't know of either of these actually exist, but it just seems like they should.)

Now, there could be improvements to this interconnectivity which is what got me thinking this morning in the first place and, as I'm a web guy, I started applying those thoughts more to websites.  What I came up with is a modest list of HTML tags which seem rather obvious to me, but which don't exist.  First, however, let's look at one tag which does exist:

 

address

The address tag is a tag I never use, but see the value of.  It lets you specifically define a block of text as an address.  Technically, this is supposed to be the address of the document author/owner (or the aritlce author/owner in HTML 5), but I think of it more as a general way to define addresses. 

I suspect many web developers like me don't use this tag because...well, it doesn't really do much for us or our clients except give us a way to easily style an address via CSS.  Sure, search engines and other fancy things we don't know about probably use this, but we don't see the benefit (or realize it).  The possible value of it, though, seems to me very great indeed now that I think about it.  It seems to me that whenever you click on an address within an address tag (or right click or hover maybe) you should be able to do some basic things like map it, save it to you address book, etc. whether your on an iPhone or browsing via Firefox or Internet Explorer (20 years after everone else has already implemented it).

event

The first new HTML tag I prupose is the 'event' tag.  This would probably have to have sub tags such as date, time, location, etc. (or probably eventdate, eventtime, eventlocation).  Again, if you clicked on, right clicked, hovered over or did whatever UI people decided was best, you would be able to save this event to your calendar, whether it was your iPhone Calendar App or your default calendar program on you computer much the way opening a mailto: link opens in your default e-mail client.

Now the event tag name may not be the best as it could cause confustion when talking about even handlers such as onchange, onkeyup, etc. so it may be better to use something like calendar or date, but to me event just makes the most sense.

Examples:
<event>
    <eventlocation>Some Cool Place</eventlocation>
    <eventaddress>123 SW 5th Street</eventaddress>
    <eventdate>November 13, 2008 at <time timezone="PST" meridiem="PM">4:00 PM</time></event>
</event>

time

Wikipedia tells me there are 33 standard timezones, which isn't even counting all those wierd timezones (certain counties in certain states don't observe day light savings, etc.).  Not to mention there is both military time and the 12 hour time formats.  In an increasingly global world it can be confusing to know exactly what timezone we're talking about when we list a time value on a website. 

A time tag (which I already used in the previous example) would allow you as the programmer to specifically define both the time and the timezone (using a standardized list of timezone codes of course).  It may alse be required to enter a meridiem value for AM or PM. When a user hovered over the time tag, then, they would see this translated into their own time format (as defined on their computer or smart phone) in a small dialog or tooltip box just above the original time (and would be smart enough to use only the numbers and colon (or even period) to determine the time).

Examples:
<time timezone="PST" meridiem="AM">7:46</time>
<time timezone="GMT" meridiem="PM">20:12</time>
<time timezone="EDT" meridiem="PM">3:24:13 PM</time>
<time timezone="EST" meridiem="AM">5.21</time>

phone

The iPhone is pretty good at picking out phone numbers on websites which you can simply click on which opens a dialog box asking if you'd like to call that number or not.  That being said it would be even easier for them (and the rest of the computer world) if there was a phone tag in HTML. 

Like time, there are too many phone number formats to count (555 -555-5555, 123.456.7891 ext 24, 08700 100 555, etc.)  Now, apart from saving a phone number into a users contact/address book I can't readily think of a use for this on a computer, but you can't say it wouldn't be useful to implement it now so it could be utitlized later as phones and computers become ever more interconnected.

The name phone probably isn't the best as this isn't a phone, it's a phone number, but that's longer and people might use a space, etc. so I stuck with phone for my example.

Example:
<phone>555.555.5555</phone>
<phone>01246 565300</phone>
<phone>(123) 456-7891</phone>

 


audio/video

Yes, I know, I know, both audio and video are being implemented in HTML 5 which is exciting in a very nerdy way.  I just wanted to make a note that they could be very easily integrated into a smart phone or computers media player.  Right click an audio or video tag and you could download to your library, play it in your default media player for that file type, maybe even convert it, etc.

This, I know, will never be because of copyright, too many file formats, etc. but I just thought I'd dream.  

~

Anyway, it's those basic (and simple) things which make the users experience better.  When something is easy to do and is useful, it quickly becomes part of there normal behaivor.

Plus, it's just fun for us programmers to have new stuff to play with.

So, have any ideas for new HTML tags?  Think I'm stupid and want to say so in the most vulgar language you can think of?   Or have you seen examples of websites/software/operating systems which use similar, simple methods of sharing data?  Well, post a comment then and share you knowledge with us all.







PHP Shipping Calculator Class...my first class as it were

Posted 15 Years Ago



So I decided it was time I dive into that mysterious world of Objected Oriented Programming.  Of course, I've worked with classes and PHP 5 and all that good stuff before.  I've used many-a-class for things like Authorize.net payment processing, Facebook applications, YouTube integration, and OpenInviter.

I had not, however, written my own class from scratch... that is until this evening.

Why a Shipping Calculator?

I must admit that I have been (and still am, come to that) a little hesitant to embrace classes.  I have not been offered a good reason for their use as opposed to well written functions.  It seems to me that you're just doing more work to create and execute more restricted functions.

However, looking through my standard website framework I decided that the three seperate shipping calculator functions (UPS, USPS, and FedEx) would probably qualify as a good candidate for one unified class so I whipped up this little class in about an hour and a half (yes, I am bragging).

Here is the result..

Features

  • Calculates shipping rates for UPS, USPS, and FedEx
  • Allows you to set package size in either inches, centimeters, or feet
  • Allows you to set package weight in either pounds, ounces, grams, or kilograms
  • Automatically converts weight and sizes
  • Handles Batch or Single Rate Calculation
  • Two ways to pass configuration
  • Built in debugging
  • Small (309 lines)

You'll find the source code at the end of this article.  Before we get to that though, let's see an example or two of what this class does:

Examples


Imlementation

To see how we got these let's first take a look at an array ($services) of the various Shipping Companies and Methods which we'll use in calculating shipping rates:

Services Array

// UPS
$services['ups']['14'] = 'Next Day Air Early AM';
$services['ups']['01'] = 'Next Day Air';
$services['ups']['65'] = 'Saver';
$services['ups']['59'] = '2nd Day Air Early AM';
$services['ups']['02'] = '2nd Day Air';
$services['ups']['12'] = '3 Day Select';
$services['ups']['03'] = 'Ground';
$services['ups']['11'] = 'Standard';
$services['ups']['07'] = 'Worldwide Express';
$services['ups']['54'] = 'Worldwide Express Plus';
$services['ups']['08'] = 'Worldwide Expedited';
// USPS
$services['usps']['EXPRESS'] = 'Express';
$services['usps']['PRIORITY'] = 'Priority';
$services['usps']['PARCEL'] = 'Parcel';
$services['usps']['FIRST CLASS'] = 'First Class';
$services['usps']['EXPRESS SH'] = 'Express SH';
$services['usps']['BPM'] = 'BPM';
$services['usps']['MEDIA '] = 'Media';
$services['usps']['LIBRARY'] = 'Library';
// FedEx
$services['fedex']['PRIORITYOVERNIGHT'] = 'Priority Overnight';
$services['fedex']['STANDARDOVERNIGHT'] = 'Standard Overnight';
$services['fedex']['FIRSTOVERNIGHT'] = 'First Overnight';
$services['fedex']['FEDEX2DAY'] = '2 Day';
$services['fedex']['FEDEXEXPRESSSAVER'] = 'Express Saver';
$services['fedex']['FEDEXGROUND'] = 'Ground';
$services['fedex']['FEDEX1DAYFREIGHT'] = 'Overnight Day Freight';
$services['fedex']['FEDEX2DAYFREIGHT'] = '2 Day Freight';
$services['fedex']['FEDEX3DAYFREIGHT'] = '3 Day Freight';
$services['fedex']['GROUNDHOMEDELIVERY'] = 'Home Delivery';
$services['fedex']['INTERNATIONALECONOMY'] = 'International Economy';
$services['fedex']['INTERNATIONALFIRST'] = 'International First';
$services['fedex']['INTERNATIONALPRIORITY'] = 'International Priority';


Here's we have the basic configuration we'll send to the class.  You'll notice we use the $services array we just created to define the shipping methods we want to find the rates for:

Configuration

// Config
$config = array(
    // Services
    'services' => $services,
    // Weight
    'weight' => 2, // Default = 1
    'weight_units' => 'lb', // lb (default), oz, gram, kg
    // Size
    'size_length' => 5, // Default = 8
    'size_width' => 6, // Default = 4
    'size_height' => 3, // Default = 2
    'size_units' => 'in', // in (default), feet, cm
    // From
    'from_zip' => 97210,
    'from_state' => "OR", // Only Required for FedEx
    'from_country' => "US",
    // To
    'to_zip' => 55455,
    'to_state' => "MN", // Only Required for FedEx
    'to_country' => "US",
   
    // Service Logins
    'ups_access' => '', // UPS Access License Key
    'ups_user' => '', // UPS Username 
    'ups_pass' => '', // UPS Password 
    'ups_account' => '', // UPS Account Number
    'usps_user' => '', // USPS User Name
    'fedex_account' => '', // FedEX Account Number
    'fedex_meter' => '' // FedEx Meter Number
);

// Create Class (with config array)
$ship = new ShippingCalculator ($config);
// Get Rates
$rates = $ship->calculate();

Note: You'll have to get the various usernames, passwords, and accounts from UPS, USPS, and FedEx to run this class.  I've added several links and the exact things you need at the very end of this article.

Finally, here's how we call the class and get our rates:


Implemetation

// Create Class (with config array)
$ship = new ShippingCalculator ($config);
// Get Rates
$rates = $ship->calculate();


Results

This class spits out information via the calculate(); method.  In our example above $rates is an array of the rates we calculated.  I ran a quick example using a few shipping methods from each company (not all of them); here's what the results look like:

Rates Array

Array (
    [ups] => Array (
        [12] => 15.07
        [03] => 8.35
        [11] =>
    )
    [usps] => Array (
        [PRIORITY] => 8.10
        [PARCEL] => 7.62
        [FIRST CLASS] =>
    )
    [fedex] => Array (
        [FEDEX2DAY] => 18.55
        [FEDEXEXPRESSSAVER] => 13.53
        [FEDEXGROUND] => 6.34
    )
)

You'll notice some are empty. This means that, for one reason or another, the shipping company doesn't ship your query via that method.  Perhaps it was a worldwide shipping method and your shippment is local, etc.

One more note before I leave you.  If you wanted to match these rates with their more user friendly names (as seen in the original $services array) and wanted to simultaneously print some radio buttons where a user could select their shipping method you could do something simple like this:

Printing Radio Buttons

foreach($rates as $company => $codes) {
    foreach($codes as $code => $rate) print "
<input type='checkbox' name='shipping' value='".$rate."' /> ".$services[$company][$code]."<br />";
}

And of course, here's the source code:


Enjoy! and let me know if you have any input, find any bugs, etc.

Update: 03-20-2010


  • Fixed the link to the source code.
  • Fixed incorrect name of constructor function
  • Added 'batch' rate lookup for USPS (the only company that lets you get rates for more than one method at a time).

And, as promised, here is some info about obtaining all the proper access keys, etc. from the different shipping companies (all are free):

UPS Online Tools Account

Link: https://www.ups.com/upsdeveloperkit?loc=en_US
What You Need:
  • Username
  • Password
  • Access License Key
  • Account Number

USPS Webtools Account
Link: https://secure.shippingapis.com/registration/
What You Need:
  • Username

FedEX Developer Account
Link: http://www.fedex.com/us/developer/
What You Need (test account versions are fine):
  • Account Number
  • Meter Number








Anchored based URL Navigation

Posted 15 Years Ago



I've been noticing a trend with AJAX based websites lately.  Of course, AJAX isn't new, but the method these websites used for navigation was new.  Instead of simply calling javascript on a click, then displaying the information inside the desired element these websites we're utilizing the built in functionality of HTML anchor tags to amend the URL which appears in a user's brower address bar.  The result is something like this:

http://hypem.com/#/artist/florence+and+the+machine

At first I thought it was a little curious, but I've since come to think it's rather ingenious.

Credit to the Originals

I first noticed this new technique on Hype Machine.  If you've never heard of it, it's a website which aggregates MP3's from hundreds of music blogs.  It's pretty nifty and recently they launched their entirely AJAX site.  The main advantage of this is that they can keep music playing while allowing you to navigate throughout the rest of the site.

Of course, they probably didn't invent this technique, but that's where I first noticed it and ever since I've stumbled across it on a handful of other sites including a little site called Facebook.

Before I move on I must also say I just searched for information on this new technique and found two excellent blog posts about it from Rebecca Murphy and YenDesign.
 

Alright, it's neat...so what?

Well, if you've worked extenstively with AJAX (or Flash for that matter) before you'll have noticed that one major drawback is that a user is always on the same URL.  That may not seem like a big deal, but say a user clicks three levels deep into your site, finds something cool, copies the URL and sends it to their friend.  Well, the friend now has to find that information all over again. 

This violoates what's called Progressive Enhancement strategy (Don't worry, I'd never heard of it before either).  Here's what Wikipedia has to say on the matter:

Progressive enhancement is a strategy for web design that emphasizes accessibility, semantic markup, and external stylesheet and scripting technologies. Progressive enhancement uses web technologies in a layered fashion that allows everyone to access the basic content and functionality of a web page, using any browser or Internet connection, while also providing those with better bandwidth or more advanced browser software an enhanced version of the page.

Anyway, the solution the world of web developers has come up with is rather ingenious.  The anchor tag is the only (to my knowledge) standard HTML thing which allows you to change a page's URL without reloading the page.  It stands to reason then this functionality can be used to maintain 'Progressive Enhancement' while still being able to utilize AJAX.
 

Well...it's kind of interesting...so how do I do it?

Well, I don't know . . . give me a minute...

Let's say we want to load photos.html, but with AJAX.  First, the link:

Anchor Nav Link
<a href="#photos.html" class="anchor">Photos</a>

Pretty basic.  Now, the second step is to be able to know when a user actually clicks this link.  I've seen two methods for this.  YenDesign stores the current URL then checks ever 300 milliseconds to see if that URL changes. I'm not so much a fan of that idea.  I prefer Rebecca Murphy's method of attatching an onclick event to anchor links.  I'm going to amend it a little though and add a class to each link I want to use this functionality.  We'll call this class 'anchor' (as you can see in my example above).

Now I'm going to use jQuery because . . . well, that's just the javascript library I use, but I'm sure you Scriptaculous and MooTools die hards can use your own methods

...actually, I'm going to jump ahead a few steps because I'm too lazy to write this all out.

Anchor Nav Javascript
<script type='text/javascript'>
$(document).ready(function() {
    anchors();
});
function anchors() {
    $("a.anchor").each(function() {
        $(this).click(function() {
            var a = $(this).attr('href').split('#')[1];
            if(a) loadAnchor(a);
        }).removeAttr('anchor');
    });
}
function loadAnchor(a) {
    alert(a);
}
</script>

Alright, so here's what the javascript is doing.
  • When the page loads it searches for all links with class="anchor"
  • It finds the anchor link within that link
  • If it found an anchor link it attatches an 'onclick' function to the link which executes the loadAnchor function
  • When a user clicks on a link, we alert the anchor link (just for showing we got this far).

Now it's just a matter of adding the AJAX call to our loadAnchor function.

Anchor Nav AJAX
function loadAnchor(a) {
    $.get(a,null, function(html){
        $("#content").html(html); 
    });
}

This loads the photos.html file into a div with id='results'.  Of course, this would also handle .php pages, even ones with query strings (I think, too lazy to test it right now).  You'd probably want to call the anchors function again to see if there are any new anchor links (which conflicts with the next step I'm about to describe, but I'll figure something out and let you know).

Now, there's only one more main function we need.  The real value of this technique is that users can return to the same page using the new URL.  So let's work that into the javascript:

Reload Anchor URL
function anchors() {
    $("a.anchor").each(function() {
        $(this).click(function() {
            var a = $(this).attr('href').split('#')[1];
            if(a) loadAnchor(a);
        }).removeAttr('anchor');
    });
   
    var url = document.location.toString();
    var a = url.split('#')[1];
    if(a) loadAnchor(a);
}

I worked the code into the 'anchors' function so it too gets called when the page loads.  Of course, the problem with javascript is you have to wait for the page to load for this to happen which is a bit annoying, but what can you do.

Anyway, this is a pretty basic example.  Her'es a demo of what I just did:

Demo


And here's the imortant source code:

Source Code
$(document).ready(function() {
    anchors();
});
function anchors() {
    $("a.anchor").each(function() {
        $(this).click(function() {
            var a = $(this).attr('href').split('#')[1];
            if(a) loadAnchor(a);
        }).removeAttr('anchor');
    });
   
    var url = document.location.toString();
    var a = url.split('#')[1];
    if(a) loadAnchor(a);
}
function loadAnchor(a) {
    $.get(a,null, function(html){
        $("#results").html(html); 
    });
}
</script>

<h1>Anchor Based URL Navigation</h1><br />
<a href='#photos.html' class='anchor'>Photos</a>

<div id="results"></div>

I'll try and work this into a jplugin-in the next few days.  Let me know if you have any suggestions.







jQuery WYSIWYG Editors - jwysiwyg is my pony

Posted 15 Years Ago



FCKEditor, You're so Big

For the last year or two I've been using FCKEditor for my custom content management systems.  It does what it needs to do and does it better than any other WYSIWYG editor I've seen.  For newbies out there, a WYSIWYG Editor is a 'What You See Is What You Get' editor.  It allows users to create HTML content without having to know any HTML.  In fact, this blog post right now is being written with the use of the FCKEditor WYSIWYG.

Anyway, there are a few things I don't like about FCKEditor.

  • Speed - It takes a rather long time to load on the page.
  • Installation - It's really easy to install it after you've done it once or twice, but uploading the thousands of files you need is a bit cumbersome.
  • Plugins - To be fair I havne't tried very hard to create a plugin for it, but it seems like there's a bit of a learning curve for writing the plugins.
  • Touchy - The Unorder List I'm typing here is giving me all sorts of trouble.  I can deal with it, most clients get driven crazy by it.

Typing this article on (a slimmed down) FCKEDitor


The jQuery Alternatives

So, the other day I looked around for something better, specifically a jQuery WYSIWYG because that's my soup d'jour.  I discovered there are basically two editors out there:

1. WYMeditor - Doesn't advertise itself as jQuery, but I'm pretty sure it is.  However, it confuses me.  I don't get why it shows me 'p' tags, etc.

2. jWSIWYG Editor - Apparently based off the WYMEditor, but much better in my opinion.  Super small size, efficient, pretty, does basic things very well.  However, it's not very robust and the documentation is non-existant.

...oh, wait, just found a third:

3. HTMLBox- Only just found this.  Looks like it's more robust than the others, but kind of ugly.  I'll have to play around with it more.

jWYSIWYG Is My Pony

So far I'm putting my money on jWYSIWYG. It's already a staple of my code base and I'm very happy with it.  It's perfect for basic editing (forum posts, comments, about me, etc.) and at only 4KB it's the smallest WYSIWYG editor I've ever seen.  Plus, it seems to do things so much better.  It responds quickly to your actions and does what you want it to do. 

Of course, the reason it's does things so nicely right now is because it doesn't do much.  Here's a full list of features:

  • Bold
  • Italic
  • Strike Through
  • Underline
  • Jstify Left
  • Justify Center
  • Justify Right
  • Justify Full
  • Indent
  • Outdent
  • Subscript
  • Superscript
  • Undo
  • Redo
  • Insert Ordered List
  • Insert Unordered List
  • Insert Horizontal Rule
  • H1
  • H2
  • H3
  • H4
  • H5
  • H6
  • Cut
  • Copy
  • Paste
  • Increase Font Size
  • Decrease Font Size
  • Create Link -

    Dialog box pops up with field for the link URL

  • Insert Image -

    Dialog box pops up with a field for the Image URL

  • Html -

    A view of the HTML Source code for the WYSIWYG Editor

  • Remove Format


Looking at it now, it's a pretty good list and--as I said--it works perfectly well for most small text formatting.  Indeed, as developers we often want to restrict what users have the ability to do.  But, there are some key things missing; some things which are required if it's ever going to be capable of being integrated into a Content Management System

  • Image Uploading
  • Tables
  • Flash 
  • Text Color
  • Font Family
  • CSS Styles

Alright, well that's all I can think of at the moment, but I'm sure there's more things it needs.  Anyway, the point is I'm going to be playing around with it in the next few weeks, starting with the 'Image Uploading' capability.  I'll let you know what I come up with.







MySQL Bits - Large MySQL Database Backup

Posted 15 Years Ago



The Problem

One of the sites I own (http://www.writerscafe.org/) has managed to attrace a good number of users and user created content.  This, of course, is a grand old thing and what we all strive for.  But when you're site starts getting large new and more complex problems arise which don't have such easy solutions. 

One such problem I faced was backing up a large database (almost 9GB).  I tried the basic methods first (MySQL Dump, GUI MySQL Backup Programs, MySQL Hot Backup, etc.), but none of them did exactly what I wanted.  What's more, all of them inevitably locked up important MySQL tables for an unacceptable period of time.  For example, the table which stored all the private messages has almost 4 million rows and weighs in at a good 5.8 GB. 

The Solution

The solution I came up with was to write a script which loops through the database, backing up rows in chunks, then saving them to a file, and looping through again.  This meant that instead SELECTing all 4 million rows at once, I was only grabbing 10,000, which is a much shorter query to run. 

It may also breaks the backup into several files.  After playing around with the script a little, I discovered that you could not create a backup file that's over 2GB.  The reason is that PHP's fopen function can't handle more than 2GB (unless you do some server stuff which isn't worth the trouble).  So the script will also (in theory) break up the backup into files of 2GB (or whatever size you set) if the database exceeds that size.

Then, when it's done creating the backup up, it creates nice little .gz files so it's easier to download.

I've named this little script MySQL Bits because it backs up the database in bits (I was going to go with 'Chunks' but the name didn't sound quite so appealing).  Below is a link to the backup.php file which handles the backup:

MySQL Bits - Large MySQL Database Backup

Example of Script Output


Basic Configuration

The script should be all ready to go.  The only thing you HAVE to edit is the MySQL database connection and the folder you'd like to save the backup(s) to.  Here's what that code looks like:

// MySQL Variables
define('MY_S','localhost'); // Server (usually 'localhost')
define('MY_D','charles_website'); // Database Name
define('MY_U','database_username'); // Username
define('MY_P','database_password'); // Password

// Relative Folder to Save To
$path = "backups/";

Should be simple enough (I 'defined' my MySQL variables because it makes them easier to use in functions).  The $path variale is a relative path to the backup script.  In the example script I simply created a backups/ folder and saved the backups there.  Note: you must change the permissons on this folder to 0777.

Advanced Configuration

Of course, I know we all like to have control over our scripts so there are a few other options you can play around with:

$pp

Rows Per Loop
This is the number of rows each loop with select from the database before updating the .sql file.  If a table has less than the $pp value it will continue onto the next table until is reaches $pp.  If a table has more than the $pp value, it will select that many rows, add it to the .sql file, then continue on where it left off.

Default = 10000
 $max_file_size Max File Size (in bytes)
As I mentioned, PHP's fopen function can't handle more than 2GB so I've set the default (2000000000 bytes) to slightly below 2GB (2147483647 bytes).  You can change this if you want to be able to download smaller backup files.

Default = 2000000000
 $name File Name
The fomat of the Backup's filename.  I recommend using some sort of date format.  You should NOT include .sql in the file name.
Note: the filename is appended with _x.sql to accomodate backups which are split into multiple files.

Default = MM-DD-YYYY_Timestamp
 $life Backup Life (in days)
This is the number of days you want to keep this backup on your server.  The backup will be deleted after this many days.  The default is 30 so, if you we're running a weekly backup you'd have approximately 4 backups on your server at all times.

Default = 30
 
max_execution_time / mysql.connect_timeout / set_time_limit PHP Timeout (in seconds)
We don't want our script running out before it's completed (my backups can take a couple of hours) so we up the server's timeout settings.  Note: these may not work on all servers because of your permissions.

Default = 7200 (2 days)


The Limitations

There are a few problems I've encountered with the script.  I'm going to keep working on it, and feel free to offer advice.

2GB Limit
The multi-file part of the script works, I've tested it with a max_file_size of 50000000 (about 47 MB) and it works fine.  However, whenever it's backed up about 2GB worth of data (into one or many files) it craps out.  This is because the fopen() function can't handle more than 2 GB. 

I've worked around it by setting up a cron to run daily.  On Sunday it starts to backup (storing the progress in the db) and each day after that it picks up where it crapped out the day before. 

SELECTing End of Large Tables
When selecting the ends of a large table (SELECT * FROM .... ORDER BY LIMIT 10000000,10000) it runs rather slowly.  The script uses the Primary Key to SELECT rows where it can, but that's also slow (SELECT * FROM .... WHERE primary_key > 10000000 AND primary_key <= 10010000 ORDER BY primary_key ASC).

I think this is more of a MySQL / Server bottleneck issue and I haven't found anyone who has a possible solution except tweaking the server's my.cnf file.

Conclusion

Well, that's about it.  I'm sure there's some bugs so you'll have to let me know if you find any.  Also, let me know if you have any suggestions.






jParallax Photo Collage

Posted 15 Years Ago



When I first stubmled across the jParallax jQuery plugin I got really excited.  It was the epitomy of jquery 'nifitiness'.  It looks like it should be flash, but it's pure javascript and proves that you can do some really cool things without having to resort to flash.

Of course, so far no one has really been able to find a proper function for the plugin, so I've set to work trying to find some way it can actually improve user experience (not just make them go "ohh, well, that's neat").

The first attempt is a jParallax Photo Collage.

jParallax Photo Collage Demo



Example of jParallax Photo Collage

Basically, you click on a link in the list and it get's focused in the jParallax box, grows in size, and becomes clickable (the example just links to a bigger version of the image using the jQuery thickbox plugin).

The problem, of course, is that--as a user--you want to hover over the images and be able to click on them.  Reasonable enough, but with all the large div's layered on top of each other which the jParallax plugin creates, only the top image is clickable.  The example deals with this by moving an image to the top of the z-index list once you click on the name in the list.

Anyway, it's a start and was fun to play around with.  Let me know if you have any suggestions for improving upon it (it's rather worthless at the moment) or if you have any ideas for other 'functional' uses for the jParallax plugin.








Welcome to the New CharlesKonsor.com

Posted 15 Years Ago



Welcome to the new CharlesKonsor.com

Gone is the flash site.  It's been replaced by a much simpler, more functional website. 

The site is now almost exclusively devoted to the web development aspect of my life (with the exception of the 'Photos' section).  It is now a place where I can show off cool bits of code which I find as I travel around the internet.  It will also be a place where I can share some of my own code which I think might help other developers out.

Of course, if you want to employ me you can check out the Portfolio and Resume sections of the site. 

So, that's about it for now.

Welcome,
-Charlie