Closed Thread Icon

Preserved Topic: Output Buffering - more thna just a "cannot add header information" cure .. Pages that link to <a href="https://ozoneasylum.com/backlink?for=13091" title="Pages that link to Preserved Topic: Output Buffering - more thna just a &amp;quot;cannot add header information&amp;quot; cure .." rel="nofollow" >Preserved Topic: Output Buffering - more thna just a &quot;cannot add header information&quot; cure ..\

 
Author Thread
trib
Paranoid (IV) Inmate

From: Den Haag, Netherlands
Insane since: Sep 2002

posted posted 03-17-2004 18:40

I, like many others, have come across "cannot add header information" in PHP resulting from trying to add a header after page output has begun .. and like most, I have occasionally fixed it by wrapping the page in ob_start/ob_end_flush functions ...

but this week I found a much more fun use for the ob_ series of commands.

As many of you know, I'm building/converting a large, well-used site for the European Space Agencythis one. Early in the redesign, I decided to make it into a custom CRM system, and permit them to manage their own content, leaving me time to focus on the dynamic and coding aspects of the job (rather than the <yawn> janitorial aspects of page maintenance).

All went well until we started to run up against the end-stops with the number of simultaneous database accesses our tired hardware and sub-optimal software combination could handle.

You see, every page was built on-the-fly from data retrieved from a MySQL database. Graphics etc. are stored in the filesystem, but static HTML, menu items, page metadata, user data, department/project data, etc. are all stored in the database. so every page load/refresh was causing about 10 separate MySQL reads to be performed.

Our sys admins worked hard to improve the capacity f the system, and at the same time I started toying with a rudimentary form of page caching.

The output buffering functions looked like they could provide me with an in-built answer to the problem and after a few day's playing I can now say it works well. On the test server, under simulated load, we've seen accesses to the database reduce by a factor in the order of thousands. Given that, I thought y'all might be interested in playing with it too ...

On the other hand, it's so simple, that everyone probably already knows bout it ... and I'm just a prat who's trying to teach his granny to suck eggs (again) .. but here goes.

The basic commnds I used were a subset of the output bffer commands available - I use

ob_start - start output buffering - don't show anything until the buffer is flushed
ob_end_clear - stop buffering and drop the contents in the bitbucket
ob_get_contents - dontchaluvit!! - get the current contents of the output buffer into a variable!

(excuse the pseudocode but) With those three added to your regular constructor page you can do :-<BLOCKQUOTE><FONT face="Verdana, Arial">code:</font><HR><pre>make a name for $cachefile;
if (!file_exists($cachefile)

DmS
Paranoid (IV) Inmate

From: Sthlm, Sweden
Insane since: Oct 2000

posted posted 03-17-2004 19:57

Trib, this is frekkin' brilliant!
You bet I'm gonna play with this

When we built www.detfinns.nu which is totally dynamic for all text/data on the site we built a rudimentary session based cache where all things that wouldn't change during a visitors session was stored in different sessions. Then for each pageload we checked the right sessions, if the data (example all categories) was there we got it from the session instead of the db. If the data wasn't there we retrieved it from the db, loaded the session for the next pageload.

This however seems to be quite a lot more flexible, as I'm posting this I'm starting to wonder if I perhaps can construct dynamic custom made classes for a framework on the fly with only the methods needed from a library of methods. This to reduce the looooooooong pages of included code that a framework usually "provides"...
<fingers itching... must scratch itch...>

Superb tip!
Thanx and If I come up with something useful along these lines I'll post it right back
/Dan

{cell 260}
-{ a vibration is a movement that doesn't know which way to go }-

Tyberius Prime
Paranoid (IV) Mad Scientist with Finglongers

From: Germany
Insane since: Sep 2001

posted posted 03-18-2004 00:09

you know, the grail actually caches the 100 most used db objects as they come back from the database...
Which of course still leaves all the in php processing to be done, but I set it up this way because it's way less of an annoyance
while developing (and there were a lot of minor 'change the look of this' changes during the grail's development.). You don't have to delete the cache every time you change somthing, and it still makes things zippy. (Since it's more often than not the queries that slow down a web based system).

now, if the cache deletion would have actually been called, I wouldn't be sitting here with 2807 files, instead of 100. oops.

[This message has been edited by Tyberius Prime (edited 03-18-2004).]

trib
Paranoid (IV) Inmate

From: Den Haag, Netherlands
Insane since: Sep 2002

posted posted 03-18-2004 09:56

Thanks Dan .. have fun - BTW - for someone at your level - take a look at the optional argument to ob_start .. that's a real eyeopener ... it's basically the name of a function which will be performed on the entire output of the OB when Output Buffering finishes .... Neat for variable substitution if you don't want to go caching ... or heres a really nice one ...

Look at the ob_gzhandler function. It's especially designed as an ob post processor function, and acts like an intelligent version of gzencode(). Unlike gzencode() it also takes care of checking whether recipient browsers are capable of handling gzip encoded files, and only gzips the output if they can ... So .. if you re-buffer the output from the last line of the code above vis ...

code:
ob_start("ob_gzhandler");
include($cachefile);
ob_end_flush();

... You get automatic on-the-fly gzip compression but only for browser which are set up for it ... which could reduce your uplink bandwidth usage by quite a considerable amount.

=========================

Thanks Tiberius - I actually have the same problem. On top of which, a lot of my cached files contain more php which is executed during the final include, so qute often I may want to see the intermediate output others time not ... so I set a variable $WMS_debug wherever I'm coding ... then ...<BLOCKQUOTE><FONT face="Verdana, Arial">code:</font><HR><pre>make a name for $cachefile;
$cachedir="specialplace/CACHE/"; // the regular cache save location
$debugdir=""specialplace/DEBUG/"; // where to put the debug output

// now still test for the 'genuine' cache file - it shouldn't be there
if (!file_exists($cachedir.$cachefile)

« BackwardsOnwards »

Show Forum Drop Down Menu