php without php—automattic

62
PHP without PHP A Philosophy for Good Architecture terry chay 2010-09-12T18:00-0500 WordCamp Meetup Seaside, Florida

Upload: terry-chay

Post on 14-Dec-2014

4.889 views

Category:

Technology


5 download

DESCRIPTION

Take a simple PHP trick and follow it on a huge tangent to the philosophy of good web architecture. Presentation given as Flash Talk at Automattic Meetup in Seaside on September 2010 Presentation originally a long form, but in the spirit of things, I have cut it down. Automattic is the company I work for. The company is distributed worldwide and once a year we gather at a remote location and meet face-to-face. This year, all the employees are taking a little time during the meetup to compose and give at least one presentation for each other, talking about any subject we are passionate about. This is based on a PHP Advent article I wrote almost two years ago and formed a low key presentation. I thought it’d be nice to give a more “traditional” PHP talk at the meetup—but one which I felt the audience at large could relate to. I hope you enjoy it.

TRANSCRIPT

Page 1: PHP Without PHP—Automattic

PHP without PHPA Philosophy for Good

Architecture

terry chay2010-09-12T18:00-0500

WordCamp MeetupSeaside, Florida

Page 2: PHP Without PHP—Automattic

Funky CachingPrologue #1

Page 3: PHP Without PHP—Automattic

aka

ErrorDocument trick

Smarter Caching

… Rasmus’s Trick (Stig’s trick)

Go into apache.conf (or .htaccess) and

ErrorDocument 404 /error.php

Page 4: PHP Without PHP—Automattic

$filepath = parse_url($_SERVER['REQUEST_URI'], PHP_URL_PATH); //or $_SERVER['REDIRECT_URL']$basepath = dirname(__FILE__).DIR_SEP; // Test to see if you can work with itif (false) { //…EDIT…    //output a 404 page    include('404.html'); // see http://www.alistapart.com/articles/perfect404/ for tips    return;} // Generate the file// …EDIT…$data = 'something'; // Don't send 404 back, send 200 OK because this is a pretty smart 404// not a clueless one! http://www.urbandictionary.com/define.php?term=404header(sprintf('%s 200', $_SERVER['SERVER_PROTOCOL']));//Show the fileecho $data; //Store the page to bypass PHP on the next request. Use a temp file with a// link trick in order to avoid race conditions between concurrent PHP// processes.$tmpfile = tempnam($basepath.'tmp','fc');$fp = fopen($tmpfile,'w'); //remove the "_" this is crashing my blog syntax hilighterfputs($fp, $data);fclose($fp);@link($basepath.$filepath, $tmpfile); //suppress errors due to losing raceunlink($tmpfile);

Error.PHP

Page 5: PHP Without PHP—Automattic

$filepath = parse_url($_SERVER['REQUEST_URI'], PHP_URL_PATH); //or $_SERVER['REDIRECT_URL']$basepath = dirname(__FILE__).DIR_SEP; // Test to see if you can work with itif (false) { //…EDIT…    //output a 404 page    include('404.html'); // see http://www.alistapart.com/articles/perfect404/ for tips    return;} // Generate the file// …EDIT…$data = 'something'; // Don't send 404 back, send 200 OK because this is a pretty smart 404// not a clueless one! http://www.urbandictionary.com/define.php?term=404header(sprintf('%s 200', $_SERVER['SERVER_PROTOCOL']));//Show the fileecho $data; //Store the page to bypass PHP on the next request. Use a temp file with a// link trick in order to avoid race conditions between concurrent PHP// processes.$tmpfile = tempnam($basepath.'tmp','fc');$fp = fopen($tmpfile,'w'); //remove the "_" this is crashing my blog syntax hilighterfputs($fp, $data);fclose($fp);@link($basepath.$filepath, $tmpfile); //suppress errors due to losing raceunlink($tmpfile);

Error.PHP

Page 6: PHP Without PHP—Automattic

$filepath = parse_url($_SERVER['REQUEST_URI'], PHP_URL_PATH); //or $_SERVER['REDIRECT_URL']$basepath = dirname(__FILE__).DIR_SEP; // Test to see if you can work with itif (false) { //…EDIT…    //output a 404 page    include('404.html'); // see http://www.alistapart.com/articles/perfect404/ for tips    return;} // Generate the file// …EDIT…$data = 'something'; // Don't send 404 back, send 200 OK because this is a pretty smart 404// not a clueless one! http://www.urbandictionary.com/define.php?term=404header(sprintf('%s 200', $_SERVER['SERVER_PROTOCOL']));//Show the fileecho $data; //Store the page to bypass PHP on the next request. Use a temp file with a// link trick in order to avoid race conditions between concurrent PHP// processes.$tmpfile = tempnam($basepath.'tmp','fc');$fp = fopen($tmpfile,'w'); //remove the "_" this is crashing my blog syntax hilighterfputs($fp, $data);fclose($fp);@link($basepath.$filepath, $tmpfile); //suppress errors due to losing raceunlink($tmpfile);

Error.PHP

Page 7: PHP Without PHP—Automattic

PHP without PHP

Page 8: PHP Without PHP—Automattic

Engineer and Architect

Page 9: PHP Without PHP—Automattic

1 Fallingwaterorganic, democratic, plasticity, continuity

Page 10: PHP Without PHP—Automattic
Page 11: PHP Without PHP—Automattic

…including me

Page 12: PHP Without PHP—Automattic

Hatchway Staircase View at the main (living room) level, from the bridge (from east)

Page 13: PHP Without PHP—Automattic

Beyond the glass Fallingwater: Living room terraces and glass walls (from east).

Page 14: PHP Without PHP—Automattic

Fall Foliage View from lookout, downstream.

Page 15: PHP Without PHP—Automattic

Fall Foliage View from lookout, downstream.

Page 16: PHP Without PHP—Automattic

No barriers Detail: corner window at the guest house, from southeast.

Page 17: PHP Without PHP—Automattic

Existing tree The trellis over the driveway is built to accommodate a tree.

Page 18: PHP Without PHP—Automattic

Local quarry Living room, west (downstream) side, from southeast

Page 19: PHP Without PHP—Automattic

Existing boulder Living room fireplace and hearth, looking from kitchen door to south windows

Page 20: PHP Without PHP—Automattic
Page 21: PHP Without PHP—Automattic

Philosophyorganic,

democratic,

plasticity,

continuity.

Page 22: PHP Without PHP—Automattic

Why on PHP?

Page 23: PHP Without PHP—Automattic

Harmony with Environment

Apache web server: ErrorDocument

Customer-centric: Performance paramount

Relational Database: Slow persistence

Harmony with PHP itself…

Page 24: PHP Without PHP—Automattic

Architecture of PHP Modern web architecture

Page 25: PHP Without PHP—Automattic

Architecture of PHP Modern web architecture

Page 26: PHP Without PHP—Automattic

2 Bellefield TowersDesign Hubris

Page 27: PHP Without PHP—Automattic
Page 28: PHP Without PHP—Automattic

Gothic Romanesque architecture The current Bellefield Church (two blocks away)

Page 29: PHP Without PHP—Automattic

Other city towers Allegheny Courthouse Main Tower & Four Tower Types at Jail (and other towers)

Page 30: PHP Without PHP—Automattic

Tower of Learning

Within spitting distance of Bellefield Towers

Page 31: PHP Without PHP—Automattic

Carnegie Library Most iconic moment in baseball history

Page 32: PHP Without PHP—Automattic

Why is Bellefield Towers so Ugly?

Page 33: PHP Without PHP—Automattic

Design Hubris?Develop in the PHP community?

Take over an existing project?

Limitations of Site Operations? Hosting? or Virtual hosting?

Business needs trump programmer desire?

Dealt with a user request?

Choosing Frameworks over Applications (Like WordPress)?

Page 34: PHP Without PHP—Automattic

Solutions Consider Environment

Page 35: PHP Without PHP—Automattic

3 Golden Gate BridgeThe Design Pattern

Page 36: PHP Without PHP—Automattic
Page 37: PHP Without PHP—Automattic

the other bridge

Page 38: PHP Without PHP—Automattic
Page 39: PHP Without PHP—Automattic
Page 40: PHP Without PHP—Automattic

Same problem, different pattern

Original design was hybrid cantilever-suspension.

Replaced by purse suspension

Page 41: PHP Without PHP—Automattic

Art DecoBridge Tower, Lighting,

pedestrial walkway

Page 42: PHP Without PHP—Automattic

International Orange

Rust colored like the environment it lives in … and

safe.

Page 43: PHP Without PHP—Automattic

Part of the whole

Page 44: PHP Without PHP—Automattic

Design Patterns Defined

“Each pattern describes a

problem which occurs over

a n d o v e r a g a i n i n o u r

e n v i r o n m e n t , a n d t h e n

describes the core of the

solution to that problem, in

such a way that you can use

this solution a million times

over, without ever doing it

the same way twice.”

Page 45: PHP Without PHP—Automattic

Certainly iconic Me in front of both icons

Page 46: PHP Without PHP—Automattic

Never the same way twice How do you know which one?

How do you know which way?

Page 47: PHP Without PHP—Automattic

Funky Caching again

“search for the closest matching valid URL and redirect, and use attempted url text as a DB keyword lookup”

—Rasmus Lerdorf

Page 48: PHP Without PHP—Automattic
Page 49: PHP Without PHP—Automattic
Page 50: PHP Without PHP—Automattic

Javascript and CSS compiling & caching

Page 51: PHP Without PHP—Automattic
Page 52: PHP Without PHP—Automattic
Page 53: PHP Without PHP—Automattic

<?php

$watermark = '3129080702_c4e76f71d7_o.png';$dead_url = 'http://example.com/dead_image.png'; // {{{ start_image($filename, &$data)/*** Creates a gd handle for a valid file* @param $filename string the file to get* @param $data array the imagesize* @return resource GD handle*/function start_image($filename, &$data) {    $data = @getimagesize($filename);    if (empty($data)) { return null; }    $data['ratio'] = $data[0]/$data[1];    switch($data[2]) {        case IMG_GIF: return imagecreatefromgif($filename);        case 3: //problem where IMG_PNG is not bound correctly for my install        case IMG_PNG: return imagecreatefrompng($filename);        case IMG_JPG: return imagecreatefromjpeg($filename);        case IMG_WBMP: return imagecreatefromwbmp($filename);        case IMG_XPM: return imagecreatefromxbm($filename);    }    return null;}   // }}}$requestimg = $_SERVER['REDIRECT_URL'];if (!$_SERVER['QUERY_STRING']) {    // redirect user to invalid image    tag_http::redirect($dead_url);    return '';}// grab image to temp {{{$ch = curl_init($_SERVER['QUERY_STRING']);$tempfile = tempnam('/tmp', 'prod_remote_');$fp = f_open($tempfile, 'w'); //again delete the "_"curl_setopt($ch, CURLOPT_FILE, $fp);curl_setopt($ch, CURLOPT_HEADER, 0);curl_exec_($ch); //delete the final "_"curl_close($ch);fclose($fp);// }}}

Page 54: PHP Without PHP—Automattic

<?php

$watermark = '3129080702_c4e76f71d7_o.png';$dead_url = 'http://example.com/dead_image.png'; // {{{ start_image($filename, &$data)/*** Creates a gd handle for a valid file* @param $filename string the file to get* @param $data array the imagesize* @return resource GD handle*/function start_image($filename, &$data) {    $data = @getimagesize($filename);    if (empty($data)) { return null; }    $data['ratio'] = $data[0]/$data[1];    switch($data[2]) {        case IMG_GIF: return imagecreatefromgif($filename);        case 3: //problem where IMG_PNG is not bound correctly for my install        case IMG_PNG: return imagecreatefrompng($filename);        case IMG_JPG: return imagecreatefromjpeg($filename);        case IMG_WBMP: return imagecreatefromwbmp($filename);        case IMG_XPM: return imagecreatefromxbm($filename);    }    return null;}   // }}}$requestimg = $_SERVER['REDIRECT_URL'];if (!$_SERVER['QUERY_STRING']) {    // redirect user to invalid image    tag_http::redirect($dead_url);    return '';}// grab image to temp {{{$ch = curl_init($_SERVER['QUERY_STRING']);$tempfile = tempnam('/tmp', 'prod_remote_');$fp = f_open($tempfile, 'w'); //again delete the "_"curl_setopt($ch, CURLOPT_FILE, $fp);curl_setopt($ch, CURLOPT_HEADER, 0);curl_exec_($ch); //delete the final "_"curl_close($ch);fclose($fp);// }}}

Page 55: PHP Without PHP—Automattic

<?php

$watermark = '3129080702_c4e76f71d7_o.png';$dead_url = 'http://example.com/dead_image.png'; // {{{ start_image($filename, &$data)/*** Creates a gd handle for a valid file* @param $filename string the file to get* @param $data array the imagesize* @return resource GD handle*/function start_image($filename, &$data) {    $data = @getimagesize($filename);    if (empty($data)) { return null; }    $data['ratio'] = $data[0]/$data[1];    switch($data[2]) {        case IMG_GIF: return imagecreatefromgif($filename);        case 3: //problem where IMG_PNG is not bound correctly for my install        case IMG_PNG: return imagecreatefrompng($filename);        case IMG_JPG: return imagecreatefromjpeg($filename);        case IMG_WBMP: return imagecreatefromwbmp($filename);        case IMG_XPM: return imagecreatefromxbm($filename);    }    return null;}   // }}}$requestimg = $_SERVER['REDIRECT_URL'];if (!$_SERVER['QUERY_STRING']) {    // redirect user to invalid image    tag_http::redirect($dead_url);    return '';}// grab image to temp {{{$ch = curl_init($_SERVER['QUERY_STRING']);$tempfile = tempnam('/tmp', 'prod_remote_');$fp = f_open($tempfile, 'w'); //again delete the "_"curl_setopt($ch, CURLOPT_FILE, $fp);curl_setopt($ch, CURLOPT_HEADER, 0);curl_exec_($ch); //delete the final "_"curl_close($ch);fclose($fp);// }}}

Page 56: PHP Without PHP—Automattic

<?php

$watermark = '3129080702_c4e76f71d7_o.png';$dead_url = 'http://example.com/dead_image.png'; // {{{ start_image($filename, &$data)/*** Creates a gd handle for a valid file* @param $filename string the file to get* @param $data array the imagesize* @return resource GD handle*/function start_image($filename, &$data) {    $data = @getimagesize($filename);    if (empty($data)) { return null; }    $data['ratio'] = $data[0]/$data[1];    switch($data[2]) {        case IMG_GIF: return imagecreatefromgif($filename);        case 3: //problem where IMG_PNG is not bound correctly for my install        case IMG_PNG: return imagecreatefrompng($filename);        case IMG_JPG: return imagecreatefromjpeg($filename);        case IMG_WBMP: return imagecreatefromwbmp($filename);        case IMG_XPM: return imagecreatefromxbm($filename);    }    return null;}   // }}}$requestimg = $_SERVER['REDIRECT_URL'];if (!$_SERVER['QUERY_STRING']) {    // redirect user to invalid image    tag_http::redirect($dead_url);    return '';}// grab image to temp {{{$ch = curl_init($_SERVER['QUERY_STRING']);$tempfile = tempnam('/tmp', 'prod_remote_');$fp = f_open($tempfile, 'w'); //again delete the "_"curl_setopt($ch, CURLOPT_FILE, $fp);curl_setopt($ch, CURLOPT_HEADER, 0);curl_exec_($ch); //delete the final "_"curl_close($ch);fclose($fp);// }}}

Page 57: PHP Without PHP—Automattic

<?php

$watermark = '3129080702_c4e76f71d7_o.png';$dead_url = 'http://example.com/dead_image.png'; // {{{ start_image($filename, &$data)/*** Creates a gd handle for a valid file* @param $filename string the file to get* @param $data array the imagesize* @return resource GD handle*/function start_image($filename, &$data) {    $data = @getimagesize($filename);    if (empty($data)) { return null; }    $data['ratio'] = $data[0]/$data[1];    switch($data[2]) {        case IMG_GIF: return imagecreatefromgif($filename);        case 3: //problem where IMG_PNG is not bound correctly for my install        case IMG_PNG: return imagecreatefrompng($filename);        case IMG_JPG: return imagecreatefromjpeg($filename);        case IMG_WBMP: return imagecreatefromwbmp($filename);        case IMG_XPM: return imagecreatefromxbm($filename);    }    return null;}   // }}}$requestimg = $_SERVER['REDIRECT_URL'];if (!$_SERVER['QUERY_STRING']) {    // redirect user to invalid image    tag_http::redirect($dead_url);    return '';}// grab image to temp {{{$ch = curl_init($_SERVER['QUERY_STRING']);$tempfile = tempnam('/tmp', 'prod_remote_');$fp = f_open($tempfile, 'w'); //again delete the "_"curl_setopt($ch, CURLOPT_FILE, $fp);curl_setopt($ch, CURLOPT_HEADER, 0);curl_exec_($ch); //delete the final "_"curl_close($ch);fclose($fp);// }}}// configure image and dimensions {{{$size_data = array();$im = start_image($tempfile, $size_data);if (!$im) {    unlink($tempfile);    tag_http::redirect($dead_url);    return;}// }}}// get watermark information {{{$wm_data = array();$wm = start_image($watermark, $wm_data);if (!$wm) {    unlink ($tempfile);    tag_http::redirect($dead_url);    return;}// }}}// add watermark {{{if ($size_data['ratio']> $wm_data['ratio']) {    // image is wider format than the watermark    $new_smaller_dim = $wm_data[0] * ($size_data[1]/$wm_data[1]);    $dst_x = ($size_data[0] - $new_smaller_dim)/2;    $dst_y = 0;    $dst_w = $new_smaller_dim;    $dst_h = $size_data[1];} else {    // image is taller format than the watermark    $new_smaller_dim = $wm_data[1] * ($size_data[0]/$wm_data[0]);    $dst_x = 0;    $dst_y = ($size_data[1] - $new_smaller_dim)/2;    $dst_w = $size_data[0];    $dst_h = $new_smaller_dim;;}imagecopyresized($im, $wm, $dst_x, $dst_y, 0, 0, $dst_w, $dst_h, $wm_data[0], $wm_data[1]);header(sprintf('%s 200', $_SERVER['SERVER_PROTOCOL']));header(sprintf('Content-type: %s',$size_data['mime']));// }}}switch ($size_data[2]) {    case IMG_GIF: imagegif($im); break;    case 3: case IMG_PNG: imagepng($im); break;    case IMG_JPG: imagejpeg($im); break;    case IMG_WBMP: imagewbmp($im); break;    case IMG_XPM: imagexbm($im); break;}imagedestroy($wm);imagedestroy($im);unlink($tempfile);

Page 58: PHP Without PHP—Automattic

<?php

$watermark = '3129080702_c4e76f71d7_o.png';$dead_url = 'http://example.com/dead_image.png'; // {{{ start_image($filename, &$data)/*** Creates a gd handle for a valid file* @param $filename string the file to get* @param $data array the imagesize* @return resource GD handle*/function start_image($filename, &$data) {    $data = @getimagesize($filename);    if (empty($data)) { return null; }    $data['ratio'] = $data[0]/$data[1];    switch($data[2]) {        case IMG_GIF: return imagecreatefromgif($filename);        case 3: //problem where IMG_PNG is not bound correctly for my install        case IMG_PNG: return imagecreatefrompng($filename);        case IMG_JPG: return imagecreatefromjpeg($filename);        case IMG_WBMP: return imagecreatefromwbmp($filename);        case IMG_XPM: return imagecreatefromxbm($filename);    }    return null;}   // }}}$requestimg = $_SERVER['REDIRECT_URL'];if (!$_SERVER['QUERY_STRING']) {    // redirect user to invalid image    tag_http::redirect($dead_url);    return '';}// grab image to temp {{{$ch = curl_init($_SERVER['QUERY_STRING']);$tempfile = tempnam('/tmp', 'prod_remote_');$fp = f_open($tempfile, 'w'); //again delete the "_"curl_setopt($ch, CURLOPT_FILE, $fp);curl_setopt($ch, CURLOPT_HEADER, 0);curl_exec_($ch); //delete the final "_"curl_close($ch);fclose($fp);// }}}// configure image and dimensions {{{$size_data = array();$im = start_image($tempfile, $size_data);if (!$im) {    unlink($tempfile);    tag_http::redirect($dead_url);    return;}// }}}// get watermark information {{{$wm_data = array();$wm = start_image($watermark, $wm_data);if (!$wm) {    unlink ($tempfile);    tag_http::redirect($dead_url);    return;}// }}}// add watermark {{{if ($size_data['ratio']> $wm_data['ratio']) {    // image is wider format than the watermark    $new_smaller_dim = $wm_data[0] * ($size_data[1]/$wm_data[1]);    $dst_x = ($size_data[0] - $new_smaller_dim)/2;    $dst_y = 0;    $dst_w = $new_smaller_dim;    $dst_h = $size_data[1];} else {    // image is taller format than the watermark    $new_smaller_dim = $wm_data[1] * ($size_data[0]/$wm_data[0]);    $dst_x = 0;    $dst_y = ($size_data[1] - $new_smaller_dim)/2;    $dst_w = $size_data[0];    $dst_h = $new_smaller_dim;;}imagecopyresized($im, $wm, $dst_x, $dst_y, 0, 0, $dst_w, $dst_h, $wm_data[0], $wm_data[1]);header(sprintf('%s 200', $_SERVER['SERVER_PROTOCOL']));header(sprintf('Content-type: %s',$size_data['mime']));// }}}switch ($size_data[2]) {    case IMG_GIF: imagegif($im); break;    case 3: case IMG_PNG: imagepng($im); break;    case IMG_JPG: imagejpeg($im); break;    case IMG_WBMP: imagewbmp($im); break;    case IMG_XPM: imagexbm($im); break;}imagedestroy($wm);imagedestroy($im);unlink($tempfile);

Page 59: PHP Without PHP—Automattic

<?php

$watermark = '3129080702_c4e76f71d7_o.png';$dead_url = 'http://example.com/dead_image.png'; // {{{ start_image($filename, &$data)/*** Creates a gd handle for a valid file* @param $filename string the file to get* @param $data array the imagesize* @return resource GD handle*/function start_image($filename, &$data) {    $data = @getimagesize($filename);    if (empty($data)) { return null; }    $data['ratio'] = $data[0]/$data[1];    switch($data[2]) {        case IMG_GIF: return imagecreatefromgif($filename);        case 3: //problem where IMG_PNG is not bound correctly for my install        case IMG_PNG: return imagecreatefrompng($filename);        case IMG_JPG: return imagecreatefromjpeg($filename);        case IMG_WBMP: return imagecreatefromwbmp($filename);        case IMG_XPM: return imagecreatefromxbm($filename);    }    return null;}   // }}}$requestimg = $_SERVER['REDIRECT_URL'];if (!$_SERVER['QUERY_STRING']) {    // redirect user to invalid image    tag_http::redirect($dead_url);    return '';}// grab image to temp {{{$ch = curl_init($_SERVER['QUERY_STRING']);$tempfile = tempnam('/tmp', 'prod_remote_');$fp = f_open($tempfile, 'w'); //again delete the "_"curl_setopt($ch, CURLOPT_FILE, $fp);curl_setopt($ch, CURLOPT_HEADER, 0);curl_exec_($ch); //delete the final "_"curl_close($ch);fclose($fp);// }}}// configure image and dimensions {{{$size_data = array();$im = start_image($tempfile, $size_data);if (!$im) {    unlink($tempfile);    tag_http::redirect($dead_url);    return;}// }}}// get watermark information {{{$wm_data = array();$wm = start_image($watermark, $wm_data);if (!$wm) {    unlink ($tempfile);    tag_http::redirect($dead_url);    return;}// }}}// add watermark {{{if ($size_data['ratio']> $wm_data['ratio']) {    // image is wider format than the watermark    $new_smaller_dim = $wm_data[0] * ($size_data[1]/$wm_data[1]);    $dst_x = ($size_data[0] - $new_smaller_dim)/2;    $dst_y = 0;    $dst_w = $new_smaller_dim;    $dst_h = $size_data[1];} else {    // image is taller format than the watermark    $new_smaller_dim = $wm_data[1] * ($size_data[0]/$wm_data[0]);    $dst_x = 0;    $dst_y = ($size_data[1] - $new_smaller_dim)/2;    $dst_w = $size_data[0];    $dst_h = $new_smaller_dim;;}imagecopyresized($im, $wm, $dst_x, $dst_y, 0, 0, $dst_w, $dst_h, $wm_data[0], $wm_data[1]);header(sprintf('%s 200', $_SERVER['SERVER_PROTOCOL']));header(sprintf('Content-type: %s',$size_data['mime']));// }}}switch ($size_data[2]) {    case IMG_GIF: imagegif($im); break;    case 3: case IMG_PNG: imagepng($im); break;    case IMG_JPG: imagejpeg($im); break;    case IMG_WBMP: imagewbmp($im); break;    case IMG_XPM: imagexbm($im); break;}imagedestroy($wm);imagedestroy($im);unlink($tempfile);

Page 60: PHP Without PHP—Automattic

Beyond Funky Caching

Page 61: PHP Without PHP—Automattic

San FranciscoLooking around you for

inspiration

Page 62: PHP Without PHP—Automattic

Thanks!