PHP without PHP
   The Philosophy of Good
        Architecture


         terry chay
   2009-05-27T14:15+0200
Internationa...
Funky Caching
   Prologue #1
aka
ErrorDocument trick

Smarter Caching

… Rasmus’s Trick (Stig’s trick)



Go into apache.conf (or .htaccess) and

    E...
Error.PHP
$filepath = parse_url($_SERVER['REQUEST_URI'], PHP_URL_PATH); //or $_SERVER['REDIRECT_URL']
$basepath = dirname(...
Error.PHP
$filepath = parse_url($_SERVER['REQUEST_URI'], PHP_URL_PATH); //or $_SERVER['REDIRECT_URL']
$basepath = dirname(...
Error.PHP
$filepath = parse_url($_SERVER['REQUEST_URI'], PHP_URL_PATH); //or $_SERVER['REDIRECT_URL']
$basepath = dirname(...
PHP without PHP
Paradigms
 Prologue #2
Code Complete
The metaphor of Code as
construction comes from this
book…


We   now   know    this   is
fundamentally wron...
Mythical Man Month
“man-month” is a term from
construction work


The premise is that man and
months are interchangeable.
...
paritionable
                                             with training
                                             trani...
Engineer and
 Architect
1 Fallingwater
organic, democratic, plasticity, continuity
…including me
Hatchway Staircase   View at the main (living room) level, from the
                                                 bridg...
Beyond the glass   Fallingwater: Living room terraces and glass
                                               walls (from...
Fall Foliage   View from lookout, downstream.
Fall Foliage   View from lookout, downstream.
No barriers   Detail: corner window at the guest house,
                                       from southeast.
Existing tree   The trellis over the driveway is built to
                                   accommodate a tree.
Local quarry   Living room, west (downstream) side, from
                                             southeast
Existing boulder   Living room fireplace and hearth, looking
                         from kitchen door to south windows
Philosophy
organic,


democratic,


plasticity,


continuity.
Why on PHP?
Harmony with Environment

 Apache web server: ErrorDocument

 Customer-centric: Performance
 paramount

 Relational Databa...
Architecture of PHP   Modern web architecture
PHP is “Cheap”

“A project done in Java will cost 5 times
as much, take twice as long, and be
harder to maintain than a pr...
PHP is “Scalable”
“That a Java servlet performs better
than a PHP script, under optimal
conditions [has] nothing to do wit...
PHP is “Pragmatic”
“PHP is not about purity in CS
principles or architecture; it is about
solving the ugly web problem wit...
2 Bellefield Towers
     Design Hubris
Gothic Romanesque architecture   The current Bellefield Church (two blocks
                                               ...
Other city towers   Allegheny Courthouse Main Tower & Four
                       Tower Types at Jail (and other towers)
Tower of
     Learning
Within spitting distance of
    Bellefield Towers
Carnegie Library   Most iconic moment in baseball history
Why is Bellefield
Towers so Ugly?
Design Hubris?
Frameworks (almost by definition)

Develop in the PHP community?

Take over an existing project?

Limitatio...
add slideshow




…at Tagged
…at Tagged
     Cubes
Waterfall process
   Oracle RAC
      Java
      PHP4
Zend Accelerator
Solutions Consider
   Environment
3 Golden Gate Bridge
     The Design Pattern
the other bridge
Same problem,
different pattern
Original design was hybrid
 cantilever-suspension.
    Replaced by purse
       suspension
Art Deco
Bridge Tower, Lighting,
 pedestrial walkway
International
     Orange
   Rust colored like the
environment it lives in … and
           safe.
Part of the
  whole
Design Patterns
      Defined
“Each pattern describes a
problem which occurs over
and   over   again     in   our
environm...
Certainly iconic   Me in front of both icons
Never the same way twice   How do you know which one?
                           How do you know which way?
Funky Caching again

“search for the closest matching valid
URL and redirect, and use attempted
url text as a DB keyword l...
Javascript and CSS
compiling & caching
<?php

$watermark = '3129080702_c4e76f71d7_o.png';
$dead_url = 'http://example.com/dead_image.png';
 
// {{{ start_image($...
<?php

$watermark = '3129080702_c4e76f71d7_o.png';
$dead_url = 'http://example.com/dead_image.png';
 
// {{{ start_image($...
<?php

$watermark = '3129080702_c4e76f71d7_o.png';
$dead_url = 'http://example.com/dead_image.png';
 
// {{{ start_image($...
<?php

$watermark = '3129080702_c4e76f71d7_o.png';
$dead_url = 'http://example.com/dead_image.png';
 
// {{{ start_image($...
// configure image and dimensions {{{
$size_data = array();
$im = start_image($tempfile, $size_data);
if (!$im) {
    unli...
// configure image and dimensions {{{
$size_data = array();
$im = start_image($tempfile, $size_data);
if (!$im) {
    unli...
// configure image and dimensions {{{
$size_data = array();
$im = start_image($tempfile, $size_data);
if (!$im) {
    unli...
Beyond Funky
  Caching
San Francisco
Looking around you for
      inspiration
Thanks!
  tychay@php.net
terrychay.com/blog
PHP Without PHP—IPC
PHP Without PHP—IPC
PHP Without PHP—IPC
PHP Without PHP—IPC
PHP Without PHP—IPC
PHP Without PHP—IPC
PHP Without PHP—IPC
PHP Without PHP—IPC
PHP Without PHP—IPC
PHP Without PHP—IPC
Upcoming SlideShare
Loading in …5
×

PHP Without PHP—IPC

3,094 views

Published on

PDF version of my slide deck for "PHP Without PHP" given at International PHP Conference in Berlin, Germany on May 2009

Abstract:
An obscure but ubiquitous design pattern in PHP development is known as Funky Caching. Using real architectural examples as a lens to look at this one simple PHP design pattern, we see how we can design web architectures that are "organic, democratic, and lasting."

Published in: Technology
2 Comments
2 Likes
Statistics
Notes
No Downloads
Views
Total views
3,094
On SlideShare
0
From Embeds
0
Number of Embeds
46
Actions
Shares
0
Downloads
55
Comments
2
Likes
2
Embeds 0
No embeds

No notes for slide

PHP Without PHP—IPC

  1. 1. PHP without PHP The Philosophy of Good Architecture terry chay 2009-05-27T14:15+0200 International PHP Conference Berlin, Germany
  2. 2. Funky Caching Prologue #1
  3. 3. aka ErrorDocument trick Smarter Caching … Rasmus’s Trick (Stig’s trick) Go into apache.conf (or .htaccess) and ErrorDocument 404 /error.php
  4. 4. Error.PHP $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 it if (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=404 header(sprintf('%s 200', $_SERVER['SERVER_PROTOCOL'])); //Show the file echo $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 quot;_quot; this is crashing my blog syntax hilighter fputs($fp, $data); fclose($fp); @link($basepath.$filepath, $tmpfile); //suppress errors due to losing race unlink($tmpfile);
  5. 5. Error.PHP $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 it if (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=404 header(sprintf('%s 200', $_SERVER['SERVER_PROTOCOL'])); //Show the file echo $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 quot;_quot; this is crashing my blog syntax hilighter fputs($fp, $data); fclose($fp); @link($basepath.$filepath, $tmpfile); //suppress errors due to losing race unlink($tmpfile);
  6. 6. Error.PHP $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 it if (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=404 header(sprintf('%s 200', $_SERVER['SERVER_PROTOCOL'])); //Show the file echo $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 quot;_quot; this is crashing my blog syntax hilighter fputs($fp, $data); fclose($fp); @link($basepath.$filepath, $tmpfile); //suppress errors due to losing race unlink($tmpfile);
  7. 7. PHP without PHP
  8. 8. Paradigms Prologue #2
  9. 9. Code Complete The metaphor of Code as construction comes from this book… We now know this is fundamentally wrong…
  10. 10. Mythical Man Month “man-month” is a term from construction work The premise is that man and months are interchangeable. This means that in order to reach a deadline I simply add more people to the project.
  11. 11. paritionable with training traning + communication unpartitionable 20 Time to COmplete Title First consider something like painting a fence: everything is 15 partionable (man-month). …add a constant time for training. 10 …add communication cost: n(n-1)/2. 5 Compare to the unpartitionable (single man) Adding people to a late project makes it later! Number of People
  12. 12. Engineer and Architect
  13. 13. 1 Fallingwater organic, democratic, plasticity, continuity
  14. 14. …including me
  15. 15. Hatchway Staircase View at the main (living room) level, from the bridge (from east)
  16. 16. Beyond the glass Fallingwater: Living room terraces and glass walls (from east).
  17. 17. Fall Foliage View from lookout, downstream.
  18. 18. Fall Foliage View from lookout, downstream.
  19. 19. No barriers Detail: corner window at the guest house, from southeast.
  20. 20. Existing tree The trellis over the driveway is built to accommodate a tree.
  21. 21. Local quarry Living room, west (downstream) side, from southeast
  22. 22. Existing boulder Living room fireplace and hearth, looking from kitchen door to south windows
  23. 23. Philosophy organic, democratic, plasticity, continuity.
  24. 24. Why on PHP?
  25. 25. Harmony with Environment Apache web server: ErrorDocument Customer-centric: Performance paramount Relational Database: Slow persistence Harmony with PHP itself…
  26. 26. Architecture of PHP Modern web architecture
  27. 27. PHP is “Cheap” “A project done in Java will cost 5 times as much, take twice as long, and be harder to maintain than a project done in a scripting language such as PHP or Perl.” —Phillip Greenspun
  28. 28. PHP is “Scalable” “That a Java servlet performs better than a PHP script, under optimal conditions [has] nothing to do with scalability. The point is can your application continue to deliver consistent performance as volume increases. PHP delegates all the ‘hard stuff’ to other systems.” —Harry Fuecks
  29. 29. PHP is “Pragmatic” “PHP is not about purity in CS principles or architecture; it is about solving the ugly web problem with an admittedly ugly, but extremely functional and convenient solution. If you are looking for purity, you are in the wrong boat. Get out now before you get hit by a wet cat!” —Rasmus Lerdorf
  30. 30. 2 Bellefield Towers Design Hubris
  31. 31. Gothic Romanesque architecture The current Bellefield Church (two blocks away)
  32. 32. Other city towers Allegheny Courthouse Main Tower & Four Tower Types at Jail (and other towers)
  33. 33. Tower of Learning Within spitting distance of Bellefield Towers
  34. 34. Carnegie Library Most iconic moment in baseball history
  35. 35. Why is Bellefield Towers so Ugly?
  36. 36. Design Hubris? Frameworks (almost by definition) 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?
  37. 37. add slideshow …at Tagged
  38. 38. …at Tagged Cubes Waterfall process Oracle RAC Java PHP4 Zend Accelerator
  39. 39. Solutions Consider Environment
  40. 40. 3 Golden Gate Bridge The Design Pattern
  41. 41. the other bridge
  42. 42. Same problem, different pattern Original design was hybrid cantilever-suspension. Replaced by purse suspension
  43. 43. Art Deco Bridge Tower, Lighting, pedestrial walkway
  44. 44. International Orange Rust colored like the environment it lives in … and safe.
  45. 45. Part of the whole
  46. 46. Design Patterns Defined “Each pattern describes a problem which occurs over and over again in our environment, and then 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.”
  47. 47. Certainly iconic Me in front of both icons
  48. 48. Never the same way twice How do you know which one? How do you know which way?
  49. 49. Funky Caching again “search for the closest matching valid URL and redirect, and use attempted url text as a DB keyword lookup” —Rasmus Lerdorf
  50. 50. Javascript and CSS compiling & caching
  51. 51. <?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 quot;_quot; curl_setopt($ch, CURLOPT_FILE, $fp); curl_setopt($ch, CURLOPT_HEADER, 0); curl_exec_($ch); //delete the final quot;_quot; curl_close($ch); fclose($fp); // }}}
  52. 52. <?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 quot;_quot; curl_setopt($ch, CURLOPT_FILE, $fp); curl_setopt($ch, CURLOPT_HEADER, 0); curl_exec_($ch); //delete the final quot;_quot; curl_close($ch); fclose($fp); // }}}
  53. 53. <?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 quot;_quot; curl_setopt($ch, CURLOPT_FILE, $fp); curl_setopt($ch, CURLOPT_HEADER, 0); curl_exec_($ch); //delete the final quot;_quot; curl_close($ch); fclose($fp); // }}}
  54. 54. <?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 quot;_quot; curl_setopt($ch, CURLOPT_FILE, $fp); curl_setopt($ch, CURLOPT_HEADER, 0); curl_exec_($ch); //delete the final quot;_quot; curl_close($ch); fclose($fp); // }}}
  55. 55. // 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);
  56. 56. // 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);
  57. 57. // 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);
  58. 58. Beyond Funky Caching
  59. 59. San Francisco Looking around you for inspiration
  60. 60. Thanks! tychay@php.net terrychay.com/blog

×