. 60
( 132 .)


$args = func_get_args();
$file = NULL;
$level = NULL;
foreach ($args as $arg)
switch (gettype($arg))
344 Part IV: Not So Simple Applications

case ˜array™:
case ˜object™:
case ˜string™:
$file = $arg;
case NULL:
$level = (int)$arg;

if (!$file)
// if no file name is given, use the current
//file by default.

// we want to find the path to the file that called
//this function,
// so we can™t use __FILE__ - that™ll just give
//us the name of
// the file where this function is defined.
//use debug_backtrace()
// instead.
$backtrace = debug_backtrace();
$last = array_shift($backtrace);
$file = $last[˜file™];

if ($level === NULL)
// if we™re using a default file name, then if no level
// is passed in, set up a default level as well
$level = get_constant($file);
$rfile = realpath($file);
if ($rfile)
$file = $rfile;
Chapter 10: Threaded Discussion 345


if ($level !== NULL)
// if we™re given a level for a file (or have set one
// as a default case), make a record of it
$debug_files[$file] = $level;

// in any case, return the current level for this file,
// if there is one, or FALSE if there isn™t

if (array_key_exists($file, $debug_files))
return $debug_files[$file];
// so now do more tedious file name matching
$pat = ˜/™.str_replace(˜/™,™.™,$file).™/i™;
return current(preg_grep($pat, array_keys($debug_files)));

Most of the time, if you want to debug a section of your code, you just set
$debug to a value that you™ve set up the debug handler to watch. Sometimes,
though, you might want to turn on debugging for all the code in a particular file.
This can easily be the case with a simple Web page or an included file, where
assigning $debug a value sets it at a global scope, and possibly triggers a lot of
debugging code you don™t want to see. That™s a problem that debug_file() solves.
It stores an error level or some other value and associates with a single file. When
you get an error, or your code calls user_error(), the error-handling routine uses
debug_file() to see if you™ve set anything up for the file in which the error

When you want to define a constant to use in a bitmask, the way you use
E_WARNING with error_reporting(), it doesn™t particularly matter what the actual
value of the constant is, so long as it doesn™t collide with any other constant you™re
using for the same purpose. That™s what get_constant() manages for you:

function get_constant($constname=™™)
// start at one above E_USER_NOTICE to avoid conflicts
// (we can™t initialize a static variable to an expression,
346 Part IV: Not So Simple Applications

// so we have to start it off as NULL and then fix that.)

static $last_constant = NULL;
if ($last_constant === NULL)
$last_constant = E_USER_NOTICE << 1;
static $defined_constants = array();
static $defined_or = 0;

$output = 0;
if (!empty($constname))
if (!defined($constname))
$defined_constants[$constname] = $last_constant;
$defined_or = $defined_or | $last_constant;
$last_constant = $last_constant << 1;
$output = constant($constname);
// if no constant name is given, hand back the equivalent
// of E_ALL for the constants defined so far
$output = $defined_or;
return $output;

The other purpose of this function is to enable you to get the value of a constant
that you™ve defined elsewhere ” or that you will define, which sounds like some
kind of time-travel feature only because that definition isn™t really accurate. It
works like this: Suppose that in a function named foo(), you make a call to

function foo()
print “<h4>my constant is “.MY_CONSTANT.”</h4>\n”;
Chapter 10: Threaded Discussion 347

In the normal course of our application, this might be the fifth call made to
get_constant(), so MY_CONSTANT would end up being defined as 32768. But sup-
pose you want to watch for MY_CONSTANT somewhere else, such as in a debugging
function. You can put the same call to get_constant() in the header file of your

$global_variable = get_constant(˜MY_CONSTANT™);

This is the first call to get_constant() that is executed, so MY_CONSTANT will be
defined as 2048. The point is, it doesn™t matter. It™s the same value that will be
returned inside the foo() function when it makes its get_constant() call. As long
as MY_CONSTANT represents the same value everywhere in the application, that™s
what counts.

If you would like to see how the rest of the code comes together, take a look at the
accompanying CD. The other files are well commented and should be relatively
easy to follow.
You should come away from this chapter with an understanding of two concepts:

— First, recursion. Recursion is a nifty tool that can be very helpful at times.
— Second, the way we went about organizing the data. We didn™t follow a
strict normalization procedure, like the one described in Chapter 1. Here
we were more concerned with what gets the job done. In the end that™s
what all application developers are trying to do, right?

Finally, we covered how to set up your own error handler, and some of the uses
to which you might put it. As with the HTML functions, you might decide that you
want to use a different approach. If so, feel free to ignore our example.
Chapter 11


— Creating an affordable content-management system

— Maintaining security in your databases

— Anticipating shortcomings in MySQL™s privilege scheme

WELCOME in this book. Don™t get us wrong, we love
the guestbook, we love the shopping cart, and we adore the problem tracker. But, as
we spent our formative years dealing with Web sites that produced a steady stream
of prose, we know the importance of having some sort of content-management sys-
tem in place.
Content-management systems come in all shapes, sizes, and costs. Depending on
your needs (or your company™s), you might be inclined to make a five-figure
investment in something like Vignette or a six- to seven-figure investment in
something like Broadvision. But your choices don™t end there. Zope (http://
www.zope.org), Midgard (http://www.midgard-project.org/), and FileNet, for-
merly eGrail, (http://www.filenet.com/) are just three open-source options for
content management.
Given all of these options, you might wonder why you should consider using the
application presented here ” why not just run off one of the aforementioned appli-
cations? There is, in fact, an excellent reason. Content management is a field in
which a high degree of customization is necessary. Your company™s concerns are
going to be distinct from any other™s, and no matter what system you end up using,
you are going to need to do a lot of coding to get your systems working just the
way you want. For example, if you decide on Vignette, you™ll need to learn a nasty
little language called Tcl (pronounced “tickle”) or write in Java. If you want to use
Zope, you will have to add Python to your repertoire. Midgard is a PHP-based
application, and there™s no question that there™s a lot of good code in there. It™s
open-source, and presents a nice opportunity to contribute to the development of
an increasingly sophisticated piece of software. But you may just want something
you can call your own, an application that you know inside out, something built to
solve the problems specific to your organization. So take a look at what™s available,
350 Part IV: Not So Simple Applications

and see if your challenges, budget, and temperament make one of the ready-made
systems a good fit. If not, you can look at the framework and code presented in this
chapter and adapt them to your needs, or maybe just recode from scratch.

Determining the Scope and Goals
of the Application
For the sake of presenting this content-management application, we™ve created a
fairly basic site (which is in the /book/netsloth directory on the CD-ROM). But
given the nature of Web content, whatever site you create is going to require all the
design and editorial resources you can muster, and we™re not going to worry about
that too much here.
Our content-management system is going to need to do several things. Its most
obvious purpose is to offer an environment where writers, editors, and administra-
tors can create new stories. Additionally, it must offer a flexible series of stages
through which a story moves. For example, if originally implemented with a single
editorial stage, the application must be flexible enough to accommodate an addi-
tional editorial stage (or several of them) if needed.
Additionally, this application must meet the various demands of a staff. There
will be a series of writers, and some byline information will be presented with each
story. Further, staff members will be assigned specific functions in the editorial
process. Various levels of permission will ensure that not everyone will have the
authority to edit or proofread a particular story, or to make that story available to
the world at large.
Finally, a sort of super-user authority must exist. A few select people will have
the authority to add users and authorities to the editorial staff.

Necessary pages
First off, we need a site, a place where the articles will be displayed. As the site isn™t
really the focus of this application, we deal with it very briefly. You will obviously
need to code a site that fits your needs. Figures 11-1 and 11-2 show the Netsloth site
in all its glory.
This application manages content and the creators of the content. We will need
a series of editorial stages and a series of users. Users will have access only to the
stages that involve them. Figure 11-3 shows a page that lists sample stages and
users. Figures 11-4 and 11-5 show pages that administer these rights and stages,
Chapter 11: Content-Management System 351

Figure 11-1: Netsloth index page

Figure 11-2: Story page


. 60
( 132 .)