Datasheet
Writing schemas in XML is verbose and RELAX NG has an equivalent compact syntax that is plain text.
James Clark (one of the authors of RELAX NG) has published trang, a tool to convert from one syntax
into the other that can also generate RELAX NG schemas from an example of a document and translate a
RELAX NG schema into W3C XML Schema. The same schema written with the compact syntax is:
wwaattcchh..rrnncc –– vv11..00
start = watch
watch = element watch { symbol & tag & description & title }
symbol = element symbol { xsd:NCName {maxLength = “5”}}
tag = element tag { xsd:NCName {maxLength = “16”}}
title = element title { xsd:token {maxLength = “128”}}
description = element description { xsd:token }
Both flavors are strictly equivalent. They say that the root element must be watch and that the watch
element is composed of symbol, tag, description, and title sub-elements in any order (the fact that
these sub-elements can be in any order is expressed by the interleave in the XML syntax and the symbol
& in the compact syntax). Some constraints are imposed to these sub-elements:
symbol and tag have a
type
xsd:NCName, meaning that they would be valid XML element or attribute names without colons.
The maximum length of
symbol, tag and title are also set to be respectively 5, 16, and 128.
You can find more information about RELAX NG at
http://relaxng.org and in the online book
RELAX NG by Eric van der Vlist, available at
http://books.xmlschemata.org/relaxng/.
To check that a document is conformant to this schema in PHP5, you load the document into a DOM (this
is the instruction
$dom->loadXML($HTTP_RAW_POST_DATA);) and use the $dom->relaxNGValidate()
method to perform the validity checks. If the document is valid for this schema, you can load it into a
SimpleXML object using its simplexml_import_dom() method to do the update. The schema validation
is enough to be sure that no SQL injection attack can be done using the
symbol and tag elements: they
wouldn’t meet the requirements for their
xsd:NCName datatypes if they included the apostrophe needed
for a SQL injection. However, the schema doesn’t check that there are no apostrophes in the
title or
description elements. Furthermore, it wouldn’t make sense to forbid apostrophes in these elements;
valid titles and descriptions may include this character. To defend BuzzWatch against SQL injection, you
thus have to use the
sqlite_escape_string() method again. BuzzWatch does so in a loop that adds an
attribute with the escaped value to each child element in the document. Further treatments can use this
attribute instead of the raw value to be immune to SQL injection.
The last difficulty is that BuzzWatch is using the same HTTP
POST method to create a new watch and to
update an existing one. In Chapter 11, you learn that purists consider that these two operations should
rather use different methods (
POST for creating new resources and PUT for updating existing ones).
BuzzWatch doesn’t follow this rule, and the PHP script needs to check whether you’re doing an update or
an insertion. To do so, the script performs a select query to check if the watch already exists in the database.
If that’s the case, a SQL update statement is performed. If not, a SQL insert statement is chosen.
Making BuzzWatch a Better Web Citizen
You now have a pretty good idea of what a Web 2.0 application looks like. You learned how scripting
interacts with both the user of a page and the web server hosting that page to change the page that is
being displayed, and how it can aggregate information from various sources and let users contribute to
24
Chapter 1
04_087889 ch01.qxp 5/2/07 12:56 PM Page 24