Skip to content
Apr 25 11

Takeaways from PHPCon, day 2

by Jonathon

Get my day one takeaways here.

Day two at PHPCon in Nashville, TN was packed with lots of information that frankly, I’m still digesting. It was well worth the trip and ended much too quickly!

Download my notes (PDF)

Morning Keynote

In his “brain dump,” Rasmus Lerdorf shared a collection of unrelated but very useful tips and observations about PHP.

  • PHP is the bottleneck, there is no significant difference between nginx/lighthttpd/apache
  • Error handling is not optimized in PHP because it should be an infrequent event. Set error_reporting = -1
  • Insufficient realpath_cache_size in PHP 5.2 can cause excessive filesystem STATs
  • Use gearman for out-of-band processing. Threads aren’t needed in PHP.
  • Don’t overload apache (8 core CPU = 25-30 apache clients; never more than 50)
  • Deploy processes should be atomic and robust (can use Capistrano or Rasmus’ own weploy script)
  • Node.js-style event programming is fast and easy (see http://php.net/libevent)

Slides: http://talks.php.net/show/phpcon2011 (ya gotta love the homegrown web-based presentation system!)

The Original Hypertext Preprocessor

Drew McLellan‘s presentation was particularly relevant for me in my role as CTO at Company52, and I consider it one of the best presentations at PHPCon. Drew’s goal was not to market Perch (although he did an awesome job of it without even trying), but rather to share his philosophy of what really great client support is all about, and how it has impacted his work.

  • Throwing new features at a problem often doesn’t solve it. Functionality is not enough.
  • Find ways to reduce support requests.
  • Every support request should be unique (no FAQs).
  • Fix areas of confusion rapidly.
  • Support your own software – programmers should see issues firsthand.
  • It’s OK to be opinionated (“WYSIWYG is evil”), but don’t be dictatorial. It’s not our place to tell people how to work.
  • Help customers look good in front of their clients.
  • Accept when users are having problems.
  • Really great developers solve problems. Excuses simply are not helpful.

The WonderProxy story

Paul Reinheimer shared the story of how he built (and self-funded) WonderProxy, born out of a personal need to test applications that use IP-based geolocation.

  • Mistakes – “crouch and hope you don’t get hit”
    • No account de-activation
    • NIH – wrote paypal IPN code instead of re-using own code
    • Mixing Linux distros
    • Server account renewals
    • Afraid to look at profitability numbers
  • Old strategy: blog about problems we encounter – competitors find posts
  • New strategy: blog about problems customers have – bring customers instead of competitors

Is it Handmade Code If You Use Power Tools?

Laura Beth Denker of Etsy shared an overview of their continuous integration processes, and how it has greatly improved both confidence and deployment speed. True to Etsy style, Laura came dressed in a handmade outfit from a Nashville-based Etsy vendor, earning a “too much swag” tweet from one listener!

  • NEED CONFIDENCE in your code
  • Effective testing strategies include functional (human) testing, integration testing (database), and unit testing (foundation)
  • Don’t use random data in unit tests
  • Test each case in control structures
  • Use DBUnit for testing database interaction
  • Tests should run rapidly
  • Group unit tests and target test groups to run
    • caches
    • databases
    • network tests (third-party APIs)
    • sleep
    • time
    • smoke, curl, regex
    • flaky

What happened to Unicode in PHP

Andrei Zmievski’s talk was a frank de-briefing of the failed attempt to bring native Unicode support to PHP6. Although this story is a rather personal one for Andrei, he was honest and incorporated a few surprisingly hilarious bits of humor. The conclusion: native Unicode support will only come to PHP if and when the community wants it — and is willing to put noses to the grindstone. The task is simply too big for his elite band of 10 (including Rasmus himself). Most of the content was historical in nature, but there were a few nice tidbits of information.

  • Complete I18N is more than language stuff:
    • Character set
    • Date/time formats
    • Currency formats
    • Collation (sorting, contractions – thanks to Andrei for finally helping me to understand what a “collation” is)
  • pecl/intl has some useful classes left over from the PHP6 unicode project (Collator, NumberFormatter, MessageFormatter)

Closing Keynote

Terry Chay’s closing keynote wove a common thread through all of the presentations given at PHPCon, along with a heaping helping of humor (seedy at times). My favorite part were the Chayisms: http://phpdoc.info/chayism/

Apr 21 11

Takeaways from PHPCon, day 1

by Jonathon

I’m here at PHPCon, the first PHP community developer conference in Nashville, TN. The first day consisted of two rather lengthy workshops, both of which were very informative.

Download my notes (PDF)

Web Services

This talk was given by Lorna Jane Mitchell, whose totally awesome British accent I could listen to all day. I consider myself no novice on consuming web services, but being a relative newcomer to building web services, I got a real education on how to do it right.

Key takeaways:

  • Use curl, it eliminates points of failure for more accurate testing. Lorna rejects any bug ticket that does not come with a curl test case, which reduced support requests by 50%!
  • Every web service should have a heartbeat method that echos the variables you pass to it.
  • Every web service should have documentation, (real) examples, and a support mechanism. If you’re not going to do this, don’t bother building a web service, ’cause nobody’s gonna use it.
  • Utilize the HTTP protocol as fully as possible, including HTTP headers (Accept, Content-Type, User-Agent), verbs (GET [read], POST [create], PUT [update], DELETE [delete]), and status codes (HTTP 200, 201, 301, 302, 400, 401, 403, 404, and 500).
  • Give consumers a choice of formats. text/html is useful for debugging purposes.
  • Parse the Http-Accept header and deliver content in first format listed that you support.
  • Don’t confuse HTTP 401 with HTTP 403 (“I don’t know who you are, so I’m denying access” vs “I know who you are, and you don’t have permission”).
  • pecl_http is an easier way to access web services than curl.
  • Error handling defines API quality. Provide complete, useful, and consistent error messages in the expected response format.

Link bundle: http://bit.ly/bundles/lornajane/2

Frontend Caching

This talk was given by Helgi Þorbjörnsson (I will not even attempt his Icelandic surname). Helgi is a long-time PEAR contributor and experienced front-end developer. Key takeaways:

  • 80% of response time is spent downloading resources.
  • Don’t abuse cookies. Large cookies hurt performance because of slow upload speeds, and because they are sent with every request. When you use cookies, be sure to set an expiration date and limit them to only the domains they are needed on.
  • Browsers have per-domain concurrent download limits. You can spread static assets across 3-4 multiple subdomains as a workaround.
  • Combine files judiciously. Be aware of the trade-off between fewer server requests and larger file size.
  • Load above the fold first.
  • Minify Javascript and CSS, preferably at build time.
  • Use gzip compressiononly for text-based content.
  • Save HTTP 404 bandwidth by ensuring that you have a robots.txt file and a favicon.
  • Compress images more (Photoshop doesn’t cut it; better alternatives include pngcrush and jpegtran).
  • Test with slower connections (tread the user’s path).
Mar 4 11

Catching the Javascript beforeunload event, the cross-browser way

by Jonathon

Javascript’s window.onbeforeunload event is useful for catching users that try to browse away from your page without having completed a certain action. Modern web applications such as Gmail and WordPress have made good use of this event.

Being a non-standard event originally invented by Microsoft back in the IE4 days, window.onbeforeunload has some real quirks, although thankfully every major modern browser does support it.

jQuery Doesn’t Help

Prior to jQuery 4, you couldn’t even bind to $(window).bind('beforeunload') due to a bug that has been fixed.

However, this isn’t your average Javascript event. window.onbeforeunload pops up a native dialog box that provides very little opportunity for customization beyond the text that is displayed to the user. There is no known way to disable this native dialog box and prevent normal behavior.

Tapping into jQuery’s $(window).unload() event doesn’t allow you to prevent the page from being unloaded, and I couldn’t get $(window).bind('beforeunload') to work at all in Firefox 3.6.

The Right Way

The right way turned out to be quite easy using native Javascript code (thanks to the Mozilla Doc Center for the working solution).

For IE and FF < 4, set window.event.returnValue to the string you wish to display, and then return it for Safari (use null instead to allow normal behavior):

window.onbeforeunload = function (e) {
    var e = e || window.event;

    // For IE and Firefox prior to version 4
    if (e) {
        e.returnValue = 'Any string';
    }

    // For Safari
    return 'Any string';
};
Dec 1 10

Three ways to tell if your are running PHP 5.3

by Jonathon

A quick-n-dirty way

If all you want to do is see if you are running PHP 5.3+, then just check for the existence of the array_replace() function, which was added in PHP 5.3:

<?php
if(function_exists('array_replace')) {
    // running PHP 5.3+
} else {
    // running something prior to PHP 5.3
}
?>

The “right way”

The version_compare() method can be used in conjunction with the PHP_VERSION constant to compare standardized PHP version strings. It also makes for more readable code:

if(version_compare(PHP_VERSION, '5.3.0') >= 0) {
    echo 'I am at least PHP version 5.3.0, my version: ' . PHP_VERSION . "\n";
}

Version constants

If you need to get down to the nitty gritty specifics of the PHP version you are running, use the PHP_VERSION_ID, PHP_MAJOR_VERSION, PHP_MINOR_VERSION, and PHP_RELEASE_VERSION constants, which were added in PHP 5.2.7. To ensure backward compatibility, the following code snippet from php.net will define these constants if they are undefined in your PHP version:

<?php
// PHP_VERSION_ID is available as of PHP 5.2.7, if our
// version is lower than that, then emulate it
if (!defined('PHP_VERSION_ID')) {
    $version = explode('.', PHP_VERSION);
    define('PHP_VERSION_ID', ($version[0] * 10000 + $version[1] * 100 + $version[2]));
}

// PHP_VERSION_ID is defined as a number, where the higher the number
// is, the newer a PHP version is used. It's defined as used in the above
// expression:
//
// $version_id = $major_version * 10000 + $minor_version * 100 + $release_version;
//
// Now with PHP_VERSION_ID we can check for features this PHP version
// may have, this doesn't require to use version_compare() everytime
// you check if the current PHP version may not support a feature.
//
// For example, we may here define the PHP_VERSION_* constants thats
// not available in versions prior to 5.2.7

if (PHP_VERSION_ID < 50207) {
    define('PHP_MAJOR_VERSION',   $version[0]);
    define('PHP_MINOR_VERSION',   $version[1]);
    define('PHP_RELEASE_VERSION', $version[2]);
    // and so on, ...
}
?>
Jun 16 10

How to send e-mail…that gets delivered

by Jonathon

I just got a really good education on how to make sure your (legit) email will navigate common spam blockers and be delivered successfully, thanks to Jeff Atwood.

Summary

  1. Make sure the computer sending the email has a Reverse PTR record. Your ISP has to do it, not your DNS provider or web host.
  2. Sign your messages using DomainKeys Identified Mail. Requires DNS and code changes.
  3. Set up a SenderID DNS record. Far less critical than the first two, but still nice to have.

Did it work?

  1. Send a message to a GMail account–they provide excellent diagnostic headers. Look for Received-SPF and Authentication-Results.
  2. Use the Port25 diagnostic service (check-auth@verifier.port25.com). You can ignore a DomainKeys check fail if the DKIM check passes.
Apr 7 10

Avoid the void(0) in IE6

by Jonathon

I recently learned the hard way that <a href="javascript:void(0)"> doesn’t work as expected in IE6. The solution is to use the familiar # but make sure your onclick event returns false:

<a href="#" onclick="aFunction();return false;">Link</a>

d’bug has a great writeup on why this works and the other doesn’t.

Jan 27 10

Compiling subversion from source on Bluehost

by Jonathon

I recently had to install the subversion client in a shared hosting environment (specifically Bluehost, but these instructions probably work with other web hosts as well). It goes like this:

1) Add these lines into ~/.bash_profile

export PYTHONPATH="$HOME/lib/python2.3/site-packages"
export LD_LIBRARY_PATH="$HOME/lib"

2) Download the subversion source code

mkdir ~/src
cd ~/src
wget http://subversion.tigris.org/downloads/subversion-1.4.6.tar.gz
wget http://subversion.tigris.org/downloads/subversion-deps-1.4.6.tar.gz
tar -xzvf subversion-1.4.6.tar.gz
tar -xzvf subversion-deps-1.4.6.tar.gz
cd subversion-1.4.6

3) Compile dependencies

cd apr
./configure --enable-shared --prefix=$HOME
make && make install

cd ../apr-util
./configure --enable-shared --prefix=$HOME --with-expat=builtin --with-apr=$HOME --without-berlekey-db
make && make install

cd ../neon
EXTRA_CFLAGS="-L/usr/lib64 -fPIC"
CFLAGS="-L/usr/lib64 -fPIC"
./configure --prefix=/home/zzzzz/system --enable-shared --with-ssl
make && make install

Note: replace zzzzz with your user directory.

4) Compile subversion

cd ..
./configure --prefix=/home/zzzzz/system --with-expat=builtin --with-ssl --with-neon=/usr/lib64
make && make install

Note: replace zzzzz with your user directory.

5) Edit ~/.bash_profile to add ~/system/bin to your path

vim ~/.bash_profile

replace:

PATH=$PATH:$HOME/bin

with:

PATH=$PATH:$HOME/bin:$HOME/system/bin

6) Logout of your session and then log back in again. Subversion should now be working.

Jan 14 10

What to do when WordPress 2.8+ asks for connection info to upgrade a plugin

by Jonathon

I was getting this when trying to upgrade a plugin automatically within WordPress:

Normally this would be a filesystem permission error. You have to make sure the wp-content/plugins folder is owned by the user apache is running as. However, that didn’t change a thing.

Further googling revealed that I needed to add this constant in my wp-config.php file:

define('FS_METHOD', 'direct');
Jan 1 10

jQuery table fade doesn’t work in IE7

by Jonathon

While working on an up-and-coming web service, I found that apparently Internet Explorer does not cope well with fading <table> elements using jQuery. Here’s what I was doing:

tbl = $('#primaryColumn table');
loading = $('#primaryColumn .loading');

tbl.fadeTo(300, 0.0, function() {
    loading.show();
        tbl.load('/contacts/{pagination:page}/' + page_num + '?ajax&search={pagination:search}', function() {
        loading.hide();
        tbl.stop().fadeTo(300, 1.0, function() {
            tbl.css('opacity', 'auto');  // removing the CSS opacity rule restores the ClearType anti-aliasing in IE
        });
    });
});

For some reason, the fadeIn(), fadeOut(), and fadeTo() effects do not work on <table> elements in IE, although they work great in Firefox and Opera. This also applies when using animate() to alter the CSS opacity rule (yeah, I tried them all).

As usual, the solution proved to be very easy: don’t animate the <table>, rather, wrap the <table> in a <div> and animate that. The only change required is the first line:

tbl = $('#primaryColumn div#table_div');

Bingo! Another three-hour bug-swatting episode reinforcing my hatred for Microsoft browsers of all versions just concluded.

Nov 24 09

Javascript reserved words trigger “Expected Identifier” error on IE

by Jonathon

If you’re getting an unreasonable “Expected Identifier” Javascript error on IE6/7, check to see if you have any variable names which are reserved words.

This also goes for HTML form element names:

<form name="aform">
    <input type="text" name="name" />
</form>

Then accessing document.aform.name.value would throw an error since name is a reserved word.

Javascript Reserved Words

  • abstract
  • alert
  • Anchor
  • Area
  • arguments
  • Array
  • assign
  • blur
  • boolean or Boolean
  • break
  • Button
  • byte
  • callee
  • caller
  • captureEvents
  • case
  • catch
  • char
  • Checkbox
  • class
  • clearInterval
  • clearTimeout
  • close
  • closed
  • comment
  • confirm
  • const
  • constructor
  • continue
  • Date
  • debugger
  • default
  • defaultStatus
  • delete
  • do
  • document
  • Document
  • double
  • Element
  • else
  • enum
  • escape
  • eval
  • export
  • extends
  • false
  • FileUpload
  • final
  • finally
  • find
  • float
  • focus
  • for
  • Form
  • Frame
  • frames
  • function
  • Function
  • getClass
  • goto
  • Hidden
  • history or History
  • home
  • if
  • Image
  • implements
  • import
  • in
  • Infinity
  • innerHeight
  • innerWidth
  • instanceOf
  • int
  • interface
  • isFinite
  • isNan
  • java
  • JavaArray
  • JavaClass
  • JavaObject
  • JavaPackage
  • label
  • length
  • Link
  • location or Location
  • locationbar
  • long
  • Math
  • menubar
  • MimeType
  • moveBy
  • moveTo
  • name
  • NaN
  • native
  • navigate
  • navigator or Navigator
  • netscape
  • new
  • null
  • Number
  • Object
  • onBlur
  • onError
  • onFocus
  • onLoad
  • onUnload
  • open
  • opener
  • Option
  • outerHeight
  • outerWidth
  • package
  • Packages
  • pageXoffset
  • pageYoffset
  • parent
  • parseFloat
  • parseInt
  • Password
  • personalbar
  • Plugin
  • print
  • private
  • prompt
  • protected
  • prototype
  • public
  • Radio
  • ref
  • RegExp
  • releaseEvents
  • Reset
  • resizeBy
  • resizeTo
  • return
  • routeEvent
  • scroll
  • scrollbars
  • scrollBy
  • scrollTo
  • Select
  • self
  • setInterval
  • setTimeout
  • short
  • static
  • status
  • statusbar
  • stop
  • String
  • Submit
  • sun
  • super
  • switch
  • synchronized
  • taint
  • Text
  • Textarea
  • this
  • throw
  • throws
  • toolbar
  • top
  • toString
  • transient
  • true
  • try
  • typeof
  • unescape
  • untaint
  • unwatch
  • valueOf
  • var
  • void
  • watch
  • while
  • window
  • Window
  • with