Roland Robert's Home Page

Once upon a time I had a home page. Well, sort of. It was really just a collection of information mostly about some PHP programming tools I put together. At this point, my "home" page is simple a jumping off point for that information. If you came here due to an old link that was supposed to take you directly to class.rFastTemplate.php information, you're only one click away; follow the link below.

Once upon a time, I also had a page with a PHP photoalbum "kit" based on class.rFastTemplate. I've dumped that since it was (1) hopelessly out-of-date, and (2) didn't scale well for large numbers of photos and albums, and (3) aren't you already using Flikr? or Gallery2? I switched to using Gallery2 early in 2006 and I'm not looking back.

The examples are no longer here because they require knowledge about where some of the files live in the local filesystem, something not easily done with a content management system.  That's not a problem with rFastTemplate, only with the examples.  Once I have them moved to another location, I'll reestablish links to them.

Equipment

I'm trying to reconstruct my "old" page of equipment information and hopefully, I'll be able to add some links with pictures to what I currently have since this is ahem, a bit outdated.

Of course, I may be too lazy to ever get it systematically organized.

Sony DCR-TRV310

Sony DCR-TRV310 Digital Camcorder We originally purchased the Sony DCR-TRV310 for home video of family events. On a lark, I decided to point it into the eyepiece on night and was pleasantly surprised that I got reasonable images. It just so happened that I picked the moon as a target and it was only slight after the new moon. This was fortunate in that the entrance pupil of the camera is not well matched to the exit pupil of the 25 mm Plossl eyepiece I was using (25 mm with an f/6 scope gives an exit pupil of 4.2 mm, rather large for the video camera).

When the full image cannot enter the camera, you end up with a shadow from the secondary in your images. But, because I was imaging a very thin crescent moon, the shadow from the secondary fell in the dark part of the moon so I couldn't tell. And, because I couldn't tell, I went on to try imaging Jupiter and Saturn.

Sorry, I don't have any technical details on the Sony DCR-TRV310, but once I do, I'll try to post them here.

Using the DCR-TRV310

For the planets, the DCR-TRV310 can be used in the normal 29.97 frames-per-second mode. For deep-sky objects the camera's "candle-light" mode is preferable. In this mode, the camera increases the exposure time by approximately a factor of 8 to produce 1/4-second exposures. Output continues at the 29.97 fps rate, but each set of 8 frames is identical.

The DCR-TRV310 has three output methods, composite video, S-Video, and FireWire. The latter is preferred as it is completely digital and what was used. Capturing over the digital FireWire connection makes it easy to get rid of duplicate frames when using the candle-light camera setting; each set of 8 frames is completely identical and any tool which will allow you to compare files will tell you which ones are unique.

Because the DCR-TRV310 is a standalone camera, you don't need any computer at the site to do your video capture; just a supply of digital 8-mm tapes and your telescope.

QuickCam VC

I purchased a QuickCam VC from Computer Geeks when they had a batch on sale for about USD $15. I keep going back hoping to find another batch, but so far no luck. Up until this, I had been using a Sony DCR-TRV310, a digital videocamera.

The QuickCam VC is similar to the other QuickCams and some detail information on modifying the camer for astronomical imaging can be found at the AstroCam web site. There is one thing you should be aware of if you are going to follow the instructions there for disassembling the camera. The instructions clearly point out that there is a small hole covered by a sticker on ]the camera. In the case of my QuickCam VC, there was no sticker, so finding the hole was easy. What I didn't fully realize is that the clip you release by poking in the hole is only one of three holes. In fact, you can see this in the photograph the AstroCam site provides of the QuickCam after it has been opened.

Alas, I was too rough or careless when opening my QuickCam VC. After pulling the lens and IR filter off then remounting it, it would not work. I rather more carefully opened it the second time and found what appeared to be a small surface mount resister array that was barely hanging on the PC board. I packed up the whole thing and shipped it as a gift to Bob May (a member of QCUAIG) who has equipment to repair it; he identified it as a tiny op-amp (so much for my electronics knowledge).

Philips ToUCam

Philips ToUCam Although I wasn't able to find this at the sort of discount I received on the QuickCam VC, this camera is still worth the money. All comments by users on the QCUAIG mailing list indicate this is a great webcam for astronomical use. I purchased the camera in early April, and have only tried to use it once conneted to a small, 133 MHz Cyrix MediaGX computer running Windows 98. I have Vega, a program written by Colin Bownes, to capture images. Vega is oriented more toward some of the operations you want to do in amateur astronomy rather than general webcam stuff. However, I'm having some problems with MediaGX machine that make me think it and Windows don't really get along all that well (I mean, even worse than Windows normally is).

Since I originally purchased the camera, there have been a number of exciting developments with the Philips webcams. Steve Chambers has put together a number of hardware modifications (see here for the ToUCam Pro) to enable true long exposure photography. I have not made this modification (yet), but the results look very promising.

ToUCam Mogg AdapterToUCam with Mogg Adapter InstalledI obtained an adapter from Stephen Mogg which is a nicely machined piece of black plastic which prevents me from having to open up the camera and break something, as I did with my QuickCam VC.

The ToUCam Pro is no longer marketed in the USA, but is imported for microscopy work by PocketScope

I have a used laptop I received from a friend, but it is an older model with no USB port and no O/S installed. I installed Slackware Linux, but the Linux PCMCIA support doesn't include any USB cards. I've been completely unsuccessful at getting Windows 95/98 installed; something is flaky with the CDROM. Even with Slackware Linux, I was unable to install from the CDROM and had to do a network install.

60mm Refractor

60mm Refractor on CG-5 Mount

About a year ago, someone on sci.astro.amateur mentioned that they had a couple of old 60 mm refractors in the closet. At the time, I was looking to buy one used and had been scanning garage sales and for sale ads without any luck. So I half-in-jest asked if you wanted to donate one. He sent me a private email and offered to send it for the only cost of shipping! Shipping was only $5, but I sent him a $20 check since I would have happily paid that for one at a garage sale.

The picture to the right is one of me with Matthew (age 3 years and 3 months) and Jonathan (age 11 months) "setting up" the telescope for a photography session of the 2001 Leonid meteor shower. You can see the telescope, the CG5 mount and a homemade box that functions as mounting "rings." The box design was used to give me a place to attach the ball heads I use for holding the cameras.

While functional, the box was heavy. I subsequently replaced the box with a more light-weight structure that also hold the cameras to either side of the telescope instead of mounting both on top. This improves the balance of the mount by keeping the weight closer to the equatorial head's axis. Here is a picture taken in June 2002 of the modified bracket just before being replaced with my Orion 127 mm Mak-Cas.

Close-up of 60mm to CG-5 Mounting "Ring"

Subsequent to that "replacement" I returned the 60 mm Tasco to service as a guide scope and added two more ball mounts on either side of the finder, which I moved to attach to the OTA, so I can now shoot four cameras at once.

If you look closely, you'll notice the finder has a piece of transparent tape holding the eyepiece on. This finder is the original 5x30 finder from my Orion XT8 and the threads were damaged when I foolishly packed the scope into its carrying case with the finder still atached. The scope is held on the wooden base by a couple of webbing straps which are pulled very tight. This arrangement is not entirely satisfactory as the straps do loosen over time. Still, it works for now.

 

 

 

127 mm Orion Maksutov-Cassegrain

The 60 mm Tasco was great for getting me started on the road to photography with a good polar alignment. It's chief failing is its small aperture which leaves me with a small selection of alignment and guide stars. So I went in search of something better (i.e., bigger)

I had already found I really liked what I was hearing about Orion Telescope's (then new) Mak-Cas telescopes. The 127 mm version was getting some good reviews as being a good performer for the price. Since I was looking for a budget scope that could also serve for decent planetary views and hopefully some imaging of Mars during the 2003 approach, this looked like a good choice. The trick was that I didn't need the whole equatorial setup Orion was selling but if I chose to purchase the spotting scope version I would have to go buy some additional parts that would put the price right back at that of the equatorial version. Enter astromart and Astronomy Mall, great places to search for used astronomy equipment. On Astronomy Mall, I found an ad from Ken Dauzat for a used 127 mm Orion Mak-Cas with some nice mods included a 2-inch diagonal with a Crayford focuser for about the same price as Orion's equatorial version. I jumped at it, but someone had already contacted Ken. Fortunately for me, that deal fell through and the scope is now mine.

 

Orion Maksutov-Cassegrain 127mm mounted on CG-5

 

In the photo above, the Mak-Cas is shown with the camera mount bar and a (dead) Pentax A3000 on one of the ball mounts so you can better see how things are attached. Since I set this up solely for the purpose of taking a quick photo, I didn't bother to attach any counterweights.

A month after the purchase, I went to NEAF where I picked up an additional counterweight for the CG5 mount and an extra dovetail bracket. The biggest question was how to attache the cameras. Ideally, I should have a nice bracket that would attach them to the OTA, and some stock versions are available, but I wanted to be able to mount at least two cameras and buying one ring for every camera seemed excessive.

I started out by ordering a small steel bar from McMaster-Carr to replace the finder mount. The original that had come with the scope was a bit too short after I replaced the Losmandy GM-8 bracket with the CG-5 dovetail. I discovered that I made a small error; the original was aluminum which is a lot easier to cut through (especially by hand with a hacksaw) than steel. I took the remainder of the bar and drilled three holes, one in the center and one near each end. The center hole is used to secure the bar to the CG-5 dovetail, the ones on each end hold a camera ball-joint mount. The arrangement is a bit kludgey, but it does work. I used it that July and August to take a series of shots which mostly came out well.

The arrangement is far from ideal. The long moment arm of that steel bracket allows vibrations. However, I have only one shot that shows anything that might be due to vibrations and even there I have convinced myself that the real culprit was something else, possibly a loose bracket on that camera (I was shooting both cameras, and one only end shows the blurring). The bigger issue is something most Mak-Cas owners are quite familiar with: mirror flop when crossing the meridian. I should have known that, but just didn't think about it. So I have a few botched shots that were taken while crossing the meridian. The mirror flop for this scope is small, and I have no shots taken with a 50 mm lens that show it; only a couple with 135 mm and 200 mm lenses. Until I work out some scope mod to get a mirror lock in place, I've gone back to using the 60 mm Tasco as my guide scope.

A Very Old Resume

Professional Interests

I have an interest in all phases of software development: design, implementation, quality control, support and management. I am particularly interested in software simulation and modelling problems requiring analytical and mathematical skills.

Computer Skills

Programming Languages

My primary work is now done in C with a fair amount of scripting in shell, Tcl/Tk and Perl. I have also worked with various common code management tools such as make, CVS, RCS, MMS, and CMS. I have even done small projects in Pascal, PL/1, 8086 Macro, and VAX Macro. I deny any knowledge of COBOL so don't ask....

Operating Systems

Unix
Including SunOS 4/5, HP-UX, Linux, Irix, and Digital Unix. Primary focus has been on interprocess communications and network programming with some work using Xt and Motif. I have a small heterogenous network at home running SunOS 4, Solaris 7, MacOS 8, and Linux 2 which has given me a solid base in systems configuration and management (I have succefully configured sendmail without using the m4 macros...).
VAX/VMS
Interprocess communication methods; general purpose mathematical software in C and Fortran; simulating physical processes; writing utility programs and user interfaces; streamlining system management procedures; installing, configuring and developing public domain and free software. Have also been involved in the development of GNU Emacs for VMS and the GNU VMSLIB project. For those of you who think this is trivial, I was doing this before the existence of GNU autoconf.... Alas, this whole project seems to have fallen by the wayside.

Numerical Techniques

Experience with data modelling and simulation, linear algebra problems, solutions to ordinary and partial differential equations, sorting methods, data filtering and smoothing, and various integral transform techniques.

Education History

University of Rochester Rochester, NY
M.A. Physics, May 1988.
Ph.D. Physics, February 1994.
Ph.D. Thesis title: "Measurements of Sub-barrier Transfer Yields in 32S+93Nb,98Mo,100Mo Reactions at 180°."

Massachusetts Institute of Technology Cambridge, MA
B.S. Physics, June 1984.
Thesis title: "A Simple Two-Parameter Model for First-Order Phase Transitions."

Additional Training

Employment History

FT Interactive Data Corporation New York, NY
Senior Programmer/Analyst November 1996-present

Wrote significant portions of a "near-time" relay system for keeping an Oracle database in sync with a Sybase database. Maintenance and redesign of a data delivery system using async, bisync and FTP protocols.

Prior to August, 1999, I worked for Muller Data Corporation which was acquired by FT/Interactive Data.

Market Arts / WebFacts New York, NY
Project Lead December 1995-November 1996

Responsible for design, implementation, and day-to-day operations of a web-server hit-tracking system for use in third-party audits. Also performed various unix system adminstration activities including web and mail server configuration.

Market Arts WebFacts has significantly changed since 1996 and became (was acquired by?) as Metis Technologies which seems to no longer have anything to do with the business I was once a part of.

Reuters Analytics Group Stamford, CT
Programmer/Analyst January 1995-December 1995
Responsible for design and development of term structure estimation algorithms and programs in C. Also designed and implemented C++ classes related to option-adjusted spread calculations for Reuter Bond Window.

Tobin and Associates, Inc. Rochester, NY
Programmer/Analyst March 1994-September 1994
Contract assignment to Martin Marietta Internal Information Systems in Utica, NY. Design and development of: a customized client-server transaction system for quality control project "SQS"; a customized asynchronous message queuing package to optimize response for a multi-platform factory-management project.

University of Rochester Rochester, NY
Graduate Research Assistant 1987-February 1994
Graduate Research Assistant in Experimental Nuclear Physics at the tandem Van de Graaff accelerator facility. Experience in instrument design and CAD use, nanosecond electronics, data acquisition and analysis. Wrote a Monte Carlo simulation for use in comparison with and identification of experimental data. Assistant to the VAX/VMS system manager in maintenance and system programming tasks including software installation and development.

University of Rochester Rochester, NY
Graduate Teaching Assistant Fall 1986
Graduate Teaching Assistant for an introductory physics course. Corrected and graded assignments, planned and taught recitations, and provided tutoring.

Charles Stark Draper Laboratory Cambridge, MA
Software Engineer 1983-1986
Responsible for simulating an inertial guidance system in an oversight role for hardware development by General Electric. Also analyzed CID image data from hardware test equipment. Written in Fortran, Pascal, Assembler and PL/1 on an IBM mainframe, PCs, and VAX/VMS. Work during 1983 was part-time while attending MIT.

Project Details

Communications Support

FT/Interactive Data Corporation
As part of a major rewrite effort, designed and implemented communications software to support product delivery (financial data) via async, bisync, and FTP while maintaining a full audit trail which could be viewed in near real-time by operators using a Powerbuilder front-end.

"Near-Time" Database Synchronization

FT/Interactive Data Corporation
As part of a migration effort, database updates on a VAX/VMS system running Sybase had to be mirrored in near real-time to an Oracle database under HP-UX. This was accomplished via triggers in Sybase which would caption the data and queue it for transmission via as separate TCP/IP based program to the HP where it was inserted into Oracle. As a later supplement, the ability to split the update stream to multiple Oracle databases was added. This was to facilitate the decision to move from HP-UX to Sun/Solaris before the former migration was complete.

WebFacts Audit System

Market Arts WebFacts
Developed and managed the "audit" software used as a web-server plug-in to provide an audit-trail of web-server accesses suitable for third-party verification of usage claims. The primary challenges of this project were managing the large data transmissions over a public network.

Option-Adjusted Spread Calculations

Reuters Analytics Group
Developed an option-adjusted spread model which used the term structure model described below and volatility information from history treasury yields as input. This model was designed for use in the "Reuter Bond Window" software package.

Term Structure Analysis

Reuters Analytics Group
Developed a term-structure model suitable based on U.S. Government Treasury bond prices. This model was designed for use in the "Reuter Bond Window" software package.

VAX-IBM "Real-Time" Data Transfers

Martin Marietta
Part of a quality control and inspection software package used to track incoming lots of material for construction. When such a lot of material arrived, data was transferred from the IBM to the VAX via ftp and required a batch process to periodically poll for data availability. The modified package initiated a process from the IBM to the VAX, passing the VAX process the data. This reduced a 10--20 minute delay (due to the polling interval) to less than one minute with less system load. The VAX side of the task involved moving the data between several machines in a WAN and utilized several IPC methods. The application was written in C and made extensive use of VMS system services. Because of the "critical data" nature, and due to audit requirments, considerable care went into fail-safe design.

Asynchronous Message Queuing Package

Martin Marietta
Part of a factory management system that tracked material on the shop floor. Serious performance problems due to requiring considerable initialization of X resources and database resources were reduced by allowing the database queries to be done in a separate process. The asynchronous message queuing package was written in C under SunOS 4.1.3 in a general fashion freeing the developer from issues of interprocess communication.

Simulation of Projectile Breakup Reactions

University of Rochester/NSRL
Development and maintenance of a Monte Carlo simulation of the 7Li --> α+t reaction. Included customized random number generators, kinematics, and graphical display of data. This simulation was used for comparison with and identification of experimental data.

Thin Film Vacuum Deposition

University of Rochester/NSRL
Argon-beam sputtering was used to deposit thin films of various isotopically enriched metals on carbon backing foils. Carbon backing thicknesses varied from 5--100μg/cm 2, metal foil thickness varied from 40--200 μg/cm2.

Introductory Fortran Seminars

University of Rochester/NSRL
Organized and led a six-week introduction to programming in the Fortran 77 language as a supplement to a required course on Mathematical Physics. Each session was attended by 8--12 graduate students and covered: language elements and data types, syntax, simple structured programming, examples of physical computation, and issues of numerical stability.

Charged-Particle Detection and Identification

University of Rochester/NSRL
The Rochester Recoil Mass Spectrometer was used to separate reactants from reaction products at a level of 1:108. Additional discrimination of approximately 1:104 was obtained by measuring gas ionization and energy deposited in solid-state silicon detector. Responsibilities included equipment selection and testing, design of detector mounts, system optimization (gas pressures, voltage levels, noise suppression), electronics assembly, fabrication of thin polypropylene transmission windows, and software for data analysis.

Simulation of CID Image Acquisition

Charles Stark Draper Laboratory
A charge-injected device (CID) was to be used for feedback in a missile guidance system. The system was required to identify a stellar image in a noisy background. The simulation included effects of Gaussian optics, various CID noise sources (e.g., shot noise, read-out noise, dark current), hardware image filtering, and image identification.

CID Image Processing

Charles Stark Draper Laboratory
The CID imaging system mentioned above was partially implemented in hardware. This partial implementation required all image processing to be performed in software. An HP9000 microcomputer was used for data collection. The data transferred to an IBM PC/XT using the IEEE488 protocol. The image data was then processed using various techniques, including finite-difference methods to simulate electronic bandpass filtering. Responsibilities included data transfer and image processing.

GNU Emacs

Pretester and developer since 1989. Contributed numerous minor fixes to both the main code line and the VMS branch, most notably the mail handling code in the VMS branch. Around 2000, the emacs pretesters mailing list effectively became defunct. Somewhere, there is still a development team, but I no longer participate in pretesting or hacking it's internals.

Keystone

Keystone is a problem tracking system which was available from Stonekeep Consulting and later by White Pajamas. I worked to maintain the PostgreSQL compatibility until Keystone was acquired by White Pajamas (PostgreSQL is an open-source RDBMS with excellent standard SQL compliance).

Miscellaneous

Foreign Experience

Languages

Personal Interests

I've taken up astronomy as a hobby and have acquired several telescopes and some imaging equipment. I first fell in love with astronomy as a child and had expected to make it my career but took something of a detour.

I enjoy outdoor activities; camping, hiking, bicycling are occasional hobbies of mine; not as regular as I would like! Until 1993, I avoided owning a car and relied on my bicycle (a 1985 Peugot Canyon Express) for any transportation needs over three or four miles. Shorter than that and I would walk.

I love to read, and am particularly fond of science-fiction. I've been subscribing to Analog since 1978. I probably spend too much on SF books; twice I've given away my collection of books, each time 300-400 titles. I have that many now and am starting to run out of space (bummer).

Affiliations and Offices

Publication History

Papers, Etc.

Invited Talks

Contributed Talks

class.rFastTemplate.php

Long ago, in a galaxy far, far, away....

Seriously, I encountered class.FastTemplate.php while doing a consulting job in in the last millenium. It had a lot of nifty features I liked, but there were some rough edges with some incomplete features, the biggest of which was it's recursive template feature. Since LISP was the first programming language I learned, I'm kind of fond of recursion, so I started writing my own replacement with class.FastTemplate.php compatibility as a major goal. In the process, I also took advantage of some things which may not have existed when class.FastTemplate.php was written, namely the ability to return and pass around variable by reference. That trick made class.rFastTemplate.php really fast compared to the original. Okay, at least for my cases and I've had others tell me the same thing. I don't have any benchmarks---you'll have to do your own.

One of the things I like about the template approach in general is the ability to separate code from content. And, in fact, I like to separate things into code, layout, and content. That's sort of the point of the template, it provides the layout, the content lives elsewhere, and there is some code that puts its all together. My original website quickly morphed into something that used my new class.rFastTemplate.php exclusively to maintain consistency throughout. Eventually, the world passed me by and I found I really wanted a content management system to make my life easier. Ah, but using a CMS comes with a price: I get what the authors think are cool features which for me meant reduced flexibility in a number of areas. Oh well, life is about trade-offs.

Even then, I decide that I liked my own templating system enough that I wrote a new theme for Drupal called (tada!) astrofoto. The obvious things it includes are all the CSS changes to get the lovely color scheme you are currently viewing. But I didn't like the mixture of code and format information in the default Drupal themes, so I split them apart using (you're way ahead of me, I see) class.rFastTemplate.php.

My use of class.rFastTemplate.php is not really a new theme engine in Drupal, it works in conjunction with the default theme engine in a sort of hybrid mode. XTemplate loads my PHP fragments which use class.rFastTemplate. But for me, the big win is that my layout is easy to read and I don't have to touch the code to change it. And much of it can be modified via CSS (like the default Drupal theme on which is was based).

Your old templates should work just fine. If they don't, please let me know. Comptability was one of the goals; to have a real drop-in replacement for class.FastTemplate. I like the nested template structure, but I didn't want to have to go back and change all my templates. Grab a copy and try it out. Let me know what you think. I called it "rFastTemplate" for "recursive" but it's not really any different in functionality than the original. It's hard to come of with a name as catchy as FastTemplate and stealing the original name didn't seem quite right (not to mention the potential for confusion.

Oh, there is one thing you will have to change in your PHP code that uses the new class: the name. You will need to change

require "class.FastTemplate.php3";
...
$t = new FastTemplate ($template_directory);

to

require "class.rFastTemplate.php";
...
$t = new rFastTemplate ($template_directory);

Around June 1, 2001, I modified the code to no longer emit the

<!-- BEGIN DYNAMIC BLOCK: foo -->
<!-- END DYNAMIC BLOCK: foo -->

HTML comments when it spits out the parsed template. This makes it easier to hide the fact that you are using a template and also reduces the amount of text flowing over the net (in some cases by a lot).

class.rFastTemplate.php ChangeLog

2002-10-01  Roland Roberts  

* class.rFastTemplate.php: Added /s qualify to PCRE regexps. This
makes multiline comments following the
{BEGIN,END}_DYNAMIC_TEMPLATE work as intended.

2002-09-24 Roland Roberts

* class.rFastTemplate.php (append): New function, equivalent to
$t->assign($t->getkey($key).$x). Actually its better than that
since it takes the same arguments as assign/setkey, i.e., it can
process an array argument.

2002-02-15 Roland Roberts

* class.rFastTemplate.php (quiet): was ignoring argument.

* class.rFastTemplate.php (missing_dir_okay) allows you to include
directories in the template path array which do not exist. The
default is 'false'. Think about organizing a web site into
sections which correspond to directories. The template tree
includes a generic menu plus specific menus for each section.
The specific menus are arranged in a directory tree parallel to
the main web site. If there is no specific menu, the generic
one is used. Previously, you had to create the directory tree
even if you had no templates to go in there.

2001-10-18 Roland Roberts

* class.rFastTemplate.php (clear): Made compatible with
FastTemplate. It wasn't even working consistently.

* class.rFastTemplate.php (clear_dynamic): New function,
compatible with FastTemplate. This will clear a dynamic
template so that on the next parse() of an outer template,
the inner template will be complately blanked; i.e., *all*
of the text will be removed including surrounding constant
text.

Note that this behavior may be surprising to users of
FastTemplate since that package completely and permanently
removes the template text from the template; as if the
template were an empty string. For a simple dynamic
template, the effect is the same, but for nested templates
where the inner template is used in a loop, the effect is
different. The rFT behavior allows the contents to be
temporarily blanked until the next loop. This allows you
to, for example, make a two-level list where some list
elements have not sub-lists but subsequent ones do.

* class.rFastTemplate.php (quiet): Added quiet() to allow you
to pass through template variables unchanged without
generating an error. I.e., normally, if something like
{FOO} appears in the text, it is either removed with
no_strict() or you get a warning message with strict().
This does neither, i.e., no warning and no removal.

2001-10-11 Roland Roberts

* class.rFastTemplate.php: Miscellaneous cleanup to run clean
with error_reporting(E_ALL).

2001-10-03 Roland Roberts

* class.rFastTemplate.php: Fixed
$t->parse(MAIN,array('table','main')) bug to be compatible
with FastTemplate. This will change the behavior for people
who were using the array() form, but I can't imagine how it
worked satisfactorily before.

2001-09-29 Roland Roberts

* class.rFastTemplate.php: Added define_raw() for shoving text
directly into a template.

2001-08-08 Roland Roberts

* class.rFastTemplate.php: Fixed problem with clearing
template results. Fixed typo in fetch that prevented
default from working.

2001-07-25 Roland Roberts

* class.rFastTemplate.php: Added "if($debug)" to all
$this->logwrite(...) calls.

* class.rFastTemplate.php: clear() and parse_internal_1() both
referenced an array element [results] which should have been
[result]. The meant neither were correctly clearing the
element.

2001-06-28 Roland Roberts

* class.rFastTemplate.php: Typo/thinko due to failed testing!

2001-06-27 Roland Roberts

* class.rFastTemplate.php: Fixed handling of no_strict() which
was broken after then last set of changes.

2001-06-18 Roland Roberts

* class.rFastTemplate.php: Fixed problem with templates being
parsed multiple times. Fixed problem with extra append of
template contents if the first call to parse() is in append
mode instead of overwrite mode.

* class.rFastTemplate.php: Fixed incorrect test for trailing
whitespace after END block.

* class.rFastTemplate.php: Fixed problem with double append in
[result] element.

* class.rFastTemplate.php: Added several logwrite sections to
help track differences with class.FastTemplate.php3. Added
class.FastTemplate.php3 compatible define_dynamic() to allow
dynamic templates to be declared. Added second optional
argument to define() to allow dynamic templates to be
defined by file rather than parent. If you have lots of
nested templates, this might be easier. Added support for
smarter autoloading so a declared dynamic template will try
to declared location first. If there is no declared
location, it will load all templates trying to find a match.

2001-06-15 Roland Roberts

* class.rFastTemplate.php: Skipping whitespace could back up
over a linefeed inappropriately. If a dynamic template
began at the start of a "part" it would be duplicated in the
output.

2001-06-14 Roland Roberts

* class.rFastTemplate.php: Fixed typo/thinko in unsetkey;
isempty changed to empty.

2001-06-12 Roland Roberts


* class.rFastTemplate.php: Merged in changes from Alister
Bulman . These include: (1) Changed
quotes from double to single where possible to avoid
unnecessary variable interpolation, (2) Allow multiple
template roots, (3) Remember last handle parsed for use with
FastPrint(), and (4) changed `if ($die == 1)' to simple `if
($die)'.

* class.rFastTemplate.php: Calls to $this->error() now use
"true" as the second argument rather than integer values.

* class.rFastTemplate.php: Formatting cleanup.

2001-06-13 Roland Roberts

* class.rFastTemplate.php: Fixed problem with trailing
comments in BEGIN/END blocks not being ignored.

* class.rFastTemplate.php: If the BEGIN/END block lives on a
line by itself, remove the complete line. More
specifically, if the only thing before the opening HTML
comment marker and after the closing HTML comment marker is
whitespace, we delete the whitespace as well. This prevents
unwanted whitespace from creaping into the file.

class.rFastTemplate.php CVS Log


Working file: class.rFastTemplate.php
head: 1.26
branch:
locks: strict
access list:
symbolic names:
start: 1.1.1.1
rlenter: 1.1.1
keyword substitution: kv
total revisions: 27; selected revisions: 27
description:
----------------------------
revision 1.26
date: 2002/10/01 20:47:48; author: roland; state: Exp; lines: +3 -3
Added /s qualify to PCRE regexps. This makes multiline comments
following the {BEGIN,END}_DYNAMIC_TEMPLATE work as intended.
----------------------------
revision 1.25
date: 2002/09/24 21:54:42; author: roland; state: Exp; lines: +16 -1
Added $t->append($x) function to be equivalent to
$t->assign($t->getkey($key).$x). Actually its better than that since
it takes the same arguments as assign/setkey, i.e., it can process an
array argument.
----------------------------
revision 1.24
date: 2002/09/23 16:52:01; author: roland; state: Exp; lines: +19 -5
Modified load() to not throw an error if the template file is empty.
The previous work around was to create a template with at least one
byte.
----------------------------
revision 1.23
date: 2002/02/15 20:51:21; author: roland; state: Exp; lines: +24 -5
quiet() was ignoring argument.

Added missing_dir_okay() which allows you to include directories in
the template path array which do not exist. The default is 'false'.
Think about organizing a web site into sections which correspond to
directories. The template tree includes a generic menu plus specific
menus for each section. The specific menus are arranged in a
directory tree parallel to the main web site. If there is no specific
menu, the generic one is used. Previously, you had to create the
directory tree even if you had no templates to go in there.
----------------------------
revision 1.22
date: 2001/10/18 21:36:53; author: roland; state: Exp; lines: +15 -4
Added quiet() to allow you to pass through template variables
unchanged without generating an error. I.e., normally, if something
like {FOO} appears in the text, it is either removed with no_strict()
or you get a warning message with strict(). This does neither, i.e.,
no warning and no removal.
----------------------------
revision 1.21
date: 2001/10/18 15:25:16; author: roland; state: Exp; lines: +81 -25
Added clear_dynamic(). Changed clear() to behave like FastTemplate
version. A few more cleanups to be quiet with E_ALL.
----------------------------
revision 1.20
date: 2001/10/11 20:17:16; author: roland; state: Exp; lines: +76 -64
Clean up under error_reporting(E_ALL).
----------------------------
revision 1.19
date: 2001/10/03 21:24:01; author: roland; state: Exp; lines: +9 -6
Fixed $t->parse(MAIN,array('table','main')) bug to be compatible with
FastTemplate. This will change the behavior for people who were using
the array() form, but I can't imagine how it worked satisfactorily
before.
----------------------------
revision 1.18
date: 2001/09/29 02:12:45; author: roland; state: Exp; lines: +114 -95
Added define_raw() for shoving text directly into a template
----------------------------
revision 1.17
date: 2001/08/08 01:50:35; author: roland; state: Exp; lines: +5 -8
Fixed problem with clearing template results.
Fixed typo in fetch that prevented default from working.
----------------------------
revision 1.16
date: 2001/07/25 18:31:14; author: roland; state: Exp; lines: +3 -3
clear() and parse_internal_1() both referenced an array element
[results] which should have been [result]. The meant neither were
correctly clearing the element.
----------------------------
revision 1.15
date: 2001/07/25 18:06:06; author: roland; state: Exp; lines: +9 -5
Added "if($debug)" to all $this->logwrite(...) calls.
----------------------------
revision 1.14
date: 2001/06/28 01:42:54; author: roland; state: Exp; lines: +2 -2
Typo/thinko due to failed testing!
----------------------------
revision 1.13
date: 2001/06/28 00:56:05; author: roland; state: Exp; lines: +14 -8
Allow '.' as a valid character in a template name.
Allow class.FastTemplate.php3 compatible use of define_dynamic.
----------------------------
revision 1.12
date: 2001/06/27 16:51:04; author: roland; state: Exp; lines: +23 -31
Fixed handling of no_strict() which was broken after then last set of changes.
----------------------------
revision 1.11
date: 2001/06/18 20:59:13; author: roland; state: Exp; lines: +78 -35
o Added several logwrite sections to help track differences with
class.FastTemplate.php3.
o Added class.FastTemplate.php3 compatible define_dynamic() to allow
dynamic templates to be declared.
o Added second optional argument to define() to allow dynamic
templates to be defined by file rather than parent. If you have
lots of nested templates, this might be easier.
o Added support for smarter autoloading so a declared dynamic template
will try to declared location first. If there is no declared
location, it will load all templates trying to find a match.
----------------------------
revision 1.10
date: 2001/06/18 19:08:48; author: roland; state: Exp; lines: +49 -38
Fixed problem with double append in [result] element.
----------------------------
revision 1.9
date: 2001/06/18 16:46:49; author: roland; state: Exp; lines: +9 -5
Fixed incorrect test for trailing whitespace after END block.
----------------------------
revision 1.8
date: 2001/06/18 03:51:21; author: roland; state: Exp; lines: +67 -57
o Fixed problem with templates being parsed multiple times.
o Fixed problem with extra append of template contents if the first
call to parse() is in append mode instead of overwrite mode.
----------------------------
revision 1.7
date: 2001/06/15 19:17:19; author: roland; state: Exp; lines: +79 -65
o Skipping whitespace could back up over a linefeed inappropriately.
o If a dynamic template began at the start of a "part" it would be
duplicated in the output.
----------------------------
revision 1.6
date: 2001/06/14 17:52:23; author: roland; state: Exp; lines: +2 -2
Fixed typo/thinko in unsetkey; isempty -> empty.
----------------------------
revision 1.5
date: 2001/06/14 02:56:51; author: roland; state: Exp; lines: +204 -74
o Merged Alister Bulman's changes.
o Fixed problem with trailing comments in BEGIN/END blocks.
o Discard space on BEGIN/END lines if those lines contain ONLY
whitespace.
----------------------------
revision 1.4
date: 2001/06/12 19:04:20; author: roland; state: Exp; lines: +18 -21
Additional copyright cleanup.
----------------------------
revision 1.3
date: 2001/06/12 03:43:17; author: roland; state: Exp; lines: +52 -17
Updated copyright notice, minor comment changes.
----------------------------
revision 1.2
date: 2001/06/07 15:28:46; author: roland; state: Exp; lines: +222 -222
Whitespace cleanup
----------------------------
revision 1.1
date: 2001/06/07 15:10:58; author: roland; state: Exp;
branches: 1.1.1;
Initial revision
----------------------------
revision 1.1.1.1
date: 2001/06/07 15:10:58; author: roland; state: Exp; lines: +0 -0
class.FastTemplate replacement
=============================================================================

class.rFastTemplate.php Documentation

class.rFastTemplate.php is a PHP class to help build web pages based on templates, i.e., fill-in-the-blank HTML. class.rFastTemplate.php allows you to build your pages as full-blown HTML with simple "blanks" to be filled in, with repeating blocks, with block which can be deleted, or as fragments where you can mix-and-match.

Synopsis

// Creating a template object.
require ('class.rFastTemplate.php');
$template = array ('.', 'template/fancy', 'template/simple');
$t = new rFastTemplate ($template);
$t->set_root ($template);

// Declaring templates.
$t->define (array ('main' => 'index.thtml',
'motd' => 'motd.thtml'));
$t->define (array ('list' => 'index.thtml'), true);
$t->define_dynamic ('table', 'main');
$t->define_nofile (array ('main' => $main_string), true);
$t->define_raw (array ('main' => $main_string), true);

// Assigning/clearing template variables.
$t->assign (TITLE, 'Hello, World!');
$t->setkey (TITLE, 'Hello, World!');
$value = $t->get_assigned (TITLE);
$value = $t->getkey (TITLE);
$t->unsetkey (TABLE);
$t->clear_href (TABLE);

// Substituting variables into a template.
$t->parse (MOTD, 'motd');
$t->subst (MOTD, 'motd');
$t->parse (array (MAIN => 'main', MOTD => 'motd'));

// Obtaining the output from completed template.
$t->xprint (MAIN);
$t->FastPrint ();
$string = $t->fetch ();

// Clearing/resetting a template.
$t->clear ('main');
$t->clear (array ('main', 'motd'));
$t->unload ('main');
$t->clear_dynamic ($template);

// Template debugging options.
$t->debug ('parse');
$t->debug ('parse', false);
$t->debugall ();
$t->debugall (false);
$t->debugfile ($path);
$t->logwrite ($message);

// Template parsing options.
$t->no_strict ()
$t->strict ();
$t->quiet ();
$t->dynamic (false);
$t->missing_dir_okay (true);

// Other internal functions.
$t->FindTemplate ($file);
$t->load ($file);
$t->parse_internal ($tag);
$t->parse_internal_1 ($tag, $rest = '');

Functions/Methods

rFastTemplate

Creates a new rFastTemplate object.

class rFastTemplate ([mixed TEMPLATE_PATH]);

If $template_path is omitted, it must be defined via set_root before calling define. If $template_path is a scalar, it is taken to be the path where the define'd templates should be found. If it an an array, it is taken as a list of directories which will be searched to located define'd templates.

set_root

Set the root directory which will be searched for any define'd templates.

void set_root (mixed TEMPLATE);

TEMPLATE may be a scalar in which case it is the name of the directory where the templates will be stored. If TEMPLATE is an array, the elements are the names of directories which will be searched in sequence to find the template files. See also missing_dir_okay.

About Multi template-roots

The most obvious use for multi template-roots are for website theming. The array of template roots are searched in order of being listed for a matching filename (that filename may also include a relative path). This leads to the advantage that entire groups of templates do not have to be duplicated, only templates that have changed. Others which would be the same will be 'fallen-back' to.

Example of multi template-roots

In the examples below, set_root is given an array argument which holds a list of directories which will be searched when trying to find the templates declared via define. In the first example, template/fancy/ need only contain a index.thtml if, say, the other templates were identical beween the two. In the second example, template/simple is assumed to contain a generic set of template while $HolidayThemeDir holds holiday specific templates.

// PHP 4; PHP 3 uses require().
require_once ('class.rFastTemplate.php');
$t = new rFastTemplate ($template);

// Example 1: look in 'template/fancy' then fall back to 'template'.
$t->set_root (array ('template/fancy/',
'template/'));

// Example 2: directory names may be passed via variables to set a
// holiday theme, e.g., 'template/Xmas/', 'template/Valentines/' etc.
// Fallback is as before. If any of the directories do not exist,
// they will be skipped.
$t->set_root (array ($HolidayThemeDir,
'template/simple/'));

// Declare some templates; paths are relative to the declared root(s).
$t->define (array ('main' => 'index.thtml',
'motd' => 'motd.thtml',
'weather' => 'weather/weatherforcast.thtml'));


// 'list' is a dynamic template contained in the file 'index.thtml'
$t->define (array ('list' => 'index.thtml'), true);

// 'table' is also a dynamic template. 'main' must be declared via
// define() because loading 'table' will check to see what
// file 'main' was declared to use.
$t->define_dynamic ('table', 'main');

define

Define an association between a template name and a template file.

void define (array TEMPLATE [, boolean DYNAMIC = false]);

$template is an array of one or more elements whose keys are the names of the templates and whose values are the associated files. $dynamic is an informational declaration that tells the class that the templates being defined are not independent but are inferior templates embedded within a parent template.

It is not necessary to declare any dynamic/inferior templates; they will be automatically found when the parent template is loaded. However, if you wish to predeclare many templates only some of which will be actually be used, declaring the dynamic templates can greatly reduce the amount of file I/O that takes place. The reason for this is simple: if you try to parse an undeclared dynamic template, class.rFastTemplate.php will have to load each of the declared templates until it finds the one being parsed. If you have tens or hundreds of predeclared templates, this can generate a lot of file I/O as well as waste CPU and memory loading files which are ultimately discarded. On the other hand, if you have only a couple of templates, all of which are actually used, there is no benefit to explicitly declaring dynamic templates. There is almost no cost to actually do so however (see code).

define_dynamic

Declare a dynamic template and its associated parent template.

void define_dynamic (mixed TEMPLATE [, string PARENT]);

This function is for compatibility with class.FastTemplate.php3 where declaring dynamic templates is required. With class.rFastTemplate.php, this declaration is not required, but can optimize the template loading process; see define for more details.

This function call can take two forms:

  • declare one dynamic template and its the parent
  • declare multiple dynamic templates and their parents

Here is an example of each:

// Single dynamic template and its parent.
define_dynamic ('dyn1', 'parent1');

// Multiple dynamic templates and their parents.
define_dynamic (array('dyn1' => 'parent1',
'dyn2' => 'parent2'));

define_nofile

See define_raw.

define_raw

This provides a way to define a template without having to read the template contents from a file.

$t->define_raw (array TEMPLATE [, boolean DYNAMIC]);

The first argument is an array of template definitions just like define except instead of having a template name point to a file it points to a string:

$t->define_raw (array ('main' => $main, 'trailer' => $trailer));

The dynamic flag defaults to false and the state is automatically set to 'loaded'. Use this if you store your templates elsewhere, e.g., a database. Another use is to create a template from a partially parsed template which still has template forms (bracket-enclosed variables) and then reparse using the newly created template, that is,

$t->define (array ('main' => 'main.thtml'));

// Do all your normal processing and assigning.
// ....

$t->parse ('MAIN', 'main');
$t->define_raw (array ('content' => $t->fetch ('MAIN')));

// Now process the "raw" template.
// ....

$t->parse ('CONTENT', 'content');
$t->FastPrint ();

assign

assign sets the value of a template variable for use during the parse/substitution phase. Internally, the function is setkey.

$somevariable = "some value";
$t->assign (MYVAR, "some value");
$t->setkey (MYVAR, "some value");
$t->assign (MYVAR, $somevariable);
$t->setkey (MYVAR, $somevariable);
$t->setkey (array (MYVAR => $somevariable));

$t->assign (array (MYVAR1 => "one",
MYVAR2 => "two"));

All of the calls above, except the last, are equivalent. The last call illustrates how one can assign multiple variable with a single call.

setkey

See assign. In hindsight, perhaps this should have been called setval.

get_assigned

This allows you to retrive the value of a previously assigned variable. It is completely equivalent to getkey. You should note that get_assigned will only retrive the value associated with a variable set via setkey or assign. This is the only place where the results of parse and assign are treated differently.

$somevariable = $t->get_assigned (MYVAR);
$somevariable = $t->getkey (MYVAR);

getkey

See get_assigned.

clear_href

This provides a mechanism for clearing the value of a key prior to parsing a template. The primary utility of this is in the case where a variable might be used in multiple contexts or in a dynamic template where the current iteration should be empty. If no_strict has been called, this is functionally equivalent to setting the variable to be an empty string.

$t->clear_href (MYVAR);
$t->unsetkey (MYVAR);

For the no_strict case, if the variable is not set or unset, during the substitution phase, the variable will be treated as if it were assigned to an empty string.

unsetkey

See clear_href.

parse

Not yet written, try again later.

subst

See parse.

FastPrint

See xprint.

xprint

When I first wrote rFastTemplate, I found having a member function named the same as a PHP function was not a good idea. It can be made to work, but internally you keep having to say something like $this->print instead of just print. Being confused at the time, I named the function xprint to avoid the problem.

xprint will print out the contents of the specified handle. Note that variable contents will not be printed, only handles. If no handle is specified, whatever handle was last used wil be parsed will be used.

$t->define (array ('main' => 'main.thtml'));
// ....
$t->parse ('CONTENT', 'main');
// This will print the same thing twice; both xprint statements
// are equivalent.
$t->xprint ();
$t->xprint ('ROW');

fetch

fetch provides a method to retrive the current contents of a handle without having to reach behind the class interface.

$t->fetch ([string HANDLE]);

It is equivalent to $t->HANDLE[$handle] with the exception that if no handle name is specified, the last one passed to parse will be used.

$t->define (array ('main' => 'main.thtml'));

// ....
$t->parse ('CONTENT', 'main');

// This will print the same thing twice; both xprint statements
// are equivalent.
$mystring = $t->fetch ();

// You can now manipulate the "finished" template before printing.
// ....
print $mystring;

clear

This provides a method to "null out" the results of a template. This is most useful when one sub-element of a dynamic template needs to be blank.

$t->define (array ('main' => 'main.thtml'));
$t->define_dynamic (array ('row' => 'main',
'col' => 'main'));
// ....
$row = 'row';
for ($i = 0; $i < $nrows; $i++) {
$col = 'col';
for ($j = 0; $j <= $ncols; $j++) {
<determine value of element (i,j)>
if (<element i,j should be omitted>) {
$t->clear ('col');
}
$t->parse (COL, $col);
$col = '.col';
}
$t->parse (ROW, $row);
$row = '.row';
}

What is perhaps not so obvious from the above code is why you would want to use clear instead of clear_href. The latter is designed to simply clear the setting of a key from an assign call. The former will clear out the entire block inside a dynamic block including any fixed HTML that is part of that dynamic block.

unload

Not yet written, try again later.

clear_dynamic

Clears a dynamic block from a template. The intent is to remove an inferior template from a parent as it the text were never present in the first place.

$t->clear_dynamic ([string TAG]);

If TAG is NULL, clear_dyanmic will clear all result elements.

clear_dyanmic will work even if the template has already been parsed by going straight to the internal results element of the parsed template and clearing it. It will also work on templates which have not yet been loaded by forcing a load via parse_internal.

debug

Turn on diagnostic printing for a particular function. This does not enable debugging via the PHP debugging mechanism; this is purely a "print some information" function.

$t->debug (string WHAT [, boolean ON]);

The first parameter is the name of the function for which diagnostic messages should be enabled, the second is a boolean flag to indicate whether printing is being turned on (true) or off (false). Whether or not anything happens is dependent on whether or not the function supports diagnostic printing.

debugall

Sets a global flag to turn on printing in all class function which support diagnostic messages.

$t->debug ([boolean ON]);

The default is to turn on debugging. If the ON parameter is set to false, debugging is turned off.

debugfile

Specify the name of the file to which diagnostic messages should be printed.

$t->debugfile (string DEBUGFILE);

There is no default for DEBUGFILE but it is intialized in the class to /tmp/class.rFastTemplate.php.dbg. When debugging is turned on, class members which support diagnostic printing will print to this file. But be warned: don't try this on a live site! First you will significantly slow things down. Second, the output from different hits on the same page will likely be intermixed making it impossible to decypher.

logwrite

logwrite is an internal function used for all of the diagnostic print statements in rFastTemplate member functions. It is not intended to be called directly.

$t->logwrite (string MESSAGE);

logwrite opens the diagnostic file (if not already open) and write the specified text with a time stamp prepended.

strict

Sets template parsing to "strict" mode; no template variables (matching regular expressions) may be present in the final output.

$t->strict ([boolean ON]);

This is the opposite of no_strict and is the default behavior. The following two calls are equivalent:

$t->no_strict ();
$t->strict (false);

no_strict

Set template parsing to "no strict" mode. At the end of the substitution phase, any remaining template variable (matching regular expressions) will be treated as if that template variable had been assigned a value of an empty string.

$t->no_strict ();

If no_strict is not used, class.rFastTemplate.php will both complain (display an error message on the page) and leave the template variables as-is in the output. It may be desirable to separate this behavior in the future, i.e., to make it possible to leave the variables in the template but not issue an error message. Among other things, it is difficult to write templates which contain examples of templates.

quiet

One of the problems with the strict/no_strict division is that switching modes does more than one thing. When in strict mode, the template form is left intact but an error message is produced. When in no-strict mode, the error message is suppressed and the template form is removed. But what if you have a form where you expect to have things which look like template forms and you want them to be passed through?

Quiet mode allows you to do just that. It suppresses the error messages but still allows the template forms to pass through to the final output. Before I added quiet mode, I couldn't insert an actual template form (e.g., {F_SOME_FIELD}) into the HTML text of this page!

dynamic

Turn on dynamic template parsing.

$t->dynamic ([boolean ON]);

By default, dynamic template parsing is on.

missing_dir_okay

Suppress errors if the template path array has non-existent members.

$t->missing_dir_okay ([boolean ON]);

The default value for ON is true if the function is called; the default behavior for a newly created template is equivalent to missing_dir_okay(false).

I originally wrote this function to get around the problem of some dynamically generated template paths. In particular, I had some code which would prepend a template path parallel to the HTML path for every page. This let me do things like have a generic navigation menu which could be superceded by a more specific one. If the more specific one did not exist the more general one was used. However, if the template path did not exist, PHP would throw an error that prevented me from doing any processing.

FindTemplate

Not yet written, try again later.

load

Not yet written, try again later.

parse_internal

Not yet written, try again later.

parse_internal_1

Not yet written, try again later.

Known Bugs

If missing_dir_okay has called, set_root can actually produce an empty ROOT array which means no templates will exist. This can only happen if, in fact, there are no valid template locations specified in the call to set_root. Still, an error should be produced at the time set_root is called to better localize the error.

Credits and References

Jason Moore wrote the original Perl version of FastTemplate for use with mod_perl. It was last known to be available at www.sober.com.

CDI from thewebmasters.net wrote class.FastTemplate.php as PHP "port" of the original Perl version.

Alister Bulman of www.minotaur.nu contributed some cleanups and allowed the template root to be a search list (array of paths).

html_vardump: printf on steroids

html_vardump()

So how exactly do you debug you PHP scripts? I'm not expert on this, but I find it inconvenient trying to debug an interpreted file living in a daemon process. I mean, with a real program, you can attach to it with something like GDB. But with PHP, I find myself resorting back to the old printf school of debugging.

html_vardump() is a slight improvement for dumping out data structures. It is more-or-less the same as PHP's vardump but with two modifications. First, all of the output is run through htmlentities() and addcslashes() so that everything will print in a web page. Second, you can decide whether or not you want html_vardump() to print everything or simply return a string which can be printed wherever you like. Not printing is the default.

Here's a simple example of using html_vardump():

$image = "mypic.jpeg";
$exif  = read_exif_data ($image);
$vardump = html_vardump ($exif, 0);
echo $vardump;

And here is what the output from a real picture looks like:

  array(64) =>
[FileName] =>
string(17) =>
"20010601-0001.jpg"
[FileDateTime] =>
integer(991436204)
[FileSize] =>
integer(307155)
[FileType] =>
integer(2)
[MimeType] =>
string(10) =>
"image/jpeg"
[SectionsFound] =>
string(50) =>
"ANY_TAG, IFD0, THUMBNAIL, EXIF, INTEROP, MAKERNOTE"
[COMPUTED] =>
array(11) =>
[html] =>
string(25) =>
"width="1280" height="960""
[Height] =>
integer(960)
[Width] =>
integer(1280)
[IsColor] =>
integer(1)
[ByteOrderMotorola] =>
integer(0)
[CCDWidth] =>
string(3) =>
"5mm"
[ExposureTime] =>
string(14) =>
"0.016 s (1/64)"
[ApertureFNumber] =>
string(5) =>
"f/3.6"
[Copyright] =>
string(10) =>
"          "
[Thumbnail.FileType] =>
integer(2)
[Thumbnail.MimeType] =>
string(10) =>
"image/jpeg"
[Make] =>
string(8) =>
"FUJIFILM"
[Model] =>
string(15) =>
"FinePix1400Zoom"
[Orientation] =>
integer(1)
[XResolution] =>
string(4) =>
"72/1"
[YResolution] =>
string(4) =>
"72/1"
[ResolutionUnit] =>
integer(2)
[Software] =>
string(38) =>
"Digital Camera FinePix1400Zoom Ver1.00"
[DateTime] =>
string(19) =>
"2001:06:01 17:56:44"
[YCbCrPositioning] =>
integer(2)
[Copyright] =>
string(10) =>
"          "
[Exif_IFD_Pointer] =>
integer(276)
[THUMBNAIL] =>
array(8) =>
[Compression] =>
integer(6)
[Orientation] =>
integer(1)
[XResolution] =>
string(4) =>
"72/1"
[YResolution] =>
string(4) =>
"72/1"
[ResolutionUnit] =>
integer(2)
[JPEGInterchangeFormat] =>
integer(1100)
[JPEGInterchangeFormatLength] =>
integer(5700)
[YCbCrPositioning] =>
integer(2)
[FNumber] =>
string(5) =>
"36/10"
[ExposureProgram] =>
integer(2)
[ISOSpeedRatings] =>
integer(125)
[ExifVersion] =>
string(4) =>
"0210"
[DateTimeOriginal] =>
string(19) =>
"2001:06:01 17:56:44"
[DateTimeDigitized] =>
string(19) =>
"2001:06:01 17:56:44"
[ComponentsConfiguration] =>
string(4) =>
"\001\002\003\000"
[CompressedBitsPerPixel] =>
string(3) =>
"2/1"
[ShutterSpeedValue] =>
string(5) =>
"60/10"
[ApertureValue] =>
string(5) =>
"37/10"
[BrightnessValue] =>
string(6) =>
"-13/10"
[ExposureBiasValue] =>
string(4) =>
"0/10"
[MaxApertureValue] =>
string(5) =>
"37/10"
[MeteringMode] =>
integer(5)
[Flash] =>
integer(1)
[FocalLength] =>
string(6) =>
"180/10"
[MakerNote] =>
string(214) =>
"FUJIFILM\f\000\000\000\017\000\000\000\a\000\004\000\000\0000130\000\020\002\ ...
[FlashPixVersion] =>
string(4) =>
"0100"
[ColorSpace] =>
integer(1)
[ExifImageWidth] =>
integer(1280)
[ExifImageLength] =>
integer(960)
[InteroperabilityOffset] =>
integer(952)
[FocalPlaneXResolution] =>
string(6) =>
"2453/1"
[FocalPlaneYResolution] =>
string(6) =>
"2453/1"
[FocalPlaneResolutionUnit] =>
integer(3)
[SensingMethod] =>
integer(2)
[FileSource] =>
string(1) =>
"\003"
[SceneType] =>
string(1) =>
"\001"
[InterOperabilityIndex] =>
string(3) =>
"R98"
[InterOperabilityVersion] =>
string(4) =>
"0100"
[Version] =>
string(4) =>
"0130"
[Quality] =>
string(7) =>
"NORMAL "
[Sharpness] =>
integer(3)
[WhiteBalance] =>
integer(0)
[FlashMode] =>
integer(3)
[FlashStrength] =>
string(4) =>
"0/10"
[Macro] =>
integer(0)
[FocusMode] =>
integer(0)
[SlowSync] =>
integer(0)
[PictureMode] =>
integer(0)
[ContTake] =>
integer(0)
[UndefinedTag:0x1200] =>
integer(0)
[BlurWarning] =>
integer(0)
[FocusWarning] =>
integer(1)
[AEWarning ] =>
integer(1)

I originally wrote html_vardump() in order to debug class.rFastTemplate.php so I could see exactly what was inside that big class variable I was creating. So, yes, it will handle class variables, too. The file containing html_vardump() has a couple of other functions I've been working on (off and on). Feel free to discard them if you don't like them.