As described in a previous blog article Stubbles did not work on PHP versions built using libxml 2.7, which is the case for at least all PHP versions since 5.3.0. We fixed the issue and make it today available as a bugfix release. This means that both 1.3.1 and 1.4.1 can now be used on PHP 5.3. See the changelog for a complete list of changes. Additionally we started to provide an Upgrade Guide with more detailed instructions on what needs to be done when upgrading from a previous version.
Lately we came across the problem that the XML/XSL view engine of Stubbles stopped working when upgrading to a newer PHP version which included libxml 2.7 instead of the previous 2.6 version. As of course Stubbles should be able to run with PHP 5.3 which uses libxml 2.7 this had to be fixed. So I tried to investigate the issue, and it took me some hours to find out what the problem was. Once the problem was understood it was very easy to fix. However, to come to the point were it became clear what was wrong was quite disturbing.
But, first to the problem. In the XML/XSL view engine we provide a simple to use XSL template which allows inclusion of XML parts from other XML resource files, so that you can easily share content between different routes, e.g. the header or footer of a website. The template looks like this:
<stub:include href="foo.xml" part="bar"/>
In a first step this will be transformed to something like
<xi:include href="xinc://default/foo.xml?part=bar#xpointer(/parts/part[@name='bar']/node())"><xi:fallback> ... some fallback code ... </xi:fallback></xi:include>
So, what does the href attribute contain? First, the xinc scheme points to our internal stream wrapper which is applied to transform the given XML document first before returning it for inclusion. Second, default/foo.xml gives our stream wrapper the information which xml file from which project to read. The query with the part is only additional information for debug purposes. After this, an XPointer is appended as fragment. The XPointer is used by libxml to include only the part from the returned XML document that can be accessed using the XPath expression given with the XPointer. This works well with libxml 2.6, but stopped to work with 2.7.
First I thought it might be a problem with the stream wrapper. But it was not. Neither was the stream wrapper called nor did libxml complain about an invalid URL. Next step was to try to reproduce the issue using real file URLs instead of the stream wrapper URLs. Still did not work. So, I tried to ask Google. The answers where not really helpful. Last resort: read again in the XInclude standard. After reading the final XInclude 1.0 W3C recommendation I found out that there is a separate xpointer attribute to be used. By changing the generated XInclude statement to
<xi:include href="xinc://default/foo.xml?part=bar" xpointer="xpointer(/parts/part[@name='bar']/node())"><xi:fallback> ... some fallback code ... </xi:fallback></xi:include>
it resumes working as if nothing happened.
Turns out, the XPointer part is the problem with libxml 2.7. With version 2.7 libxml completely refuses to process the XInclude if there is such an XPointer fragment appended to the URL given with the href attribute. No warning or error is thrown for this. Luckily changing the XInclude statement to comply with the final standard works with 2.6 as well.
You may ask why we used a version which was not supported by the final recommendation. Well, it just worked. And as it turns out, the first version was the way to use XPointers in XInclude 1.0 W3C Candidate Recommendation. It seems libxml just dropped support for this with the 2.7 series.
What can we learn from this:
Read the real and final standard recommendations.
Read them again.
Provide users of your software with better hints on what is wrong. I think it would have cost much lesser time to find the problem if there would have been at least a warning about the xpointer fragment used in the href attribute instead of just doing nothing.
With the release of vfsStream 0.8.0 the status is now beta instead of alpha as it was before. New features include a umask simulation which allows you to set a umask for vfsStream URLs which is then applied for new directories and files, except if you explicitly set the permissions of a file or directory using the vfsStream API. To be backward compatible and easier to use the default umask is 0000 - so if you are not interested in using this feature just don't use it and everything stays at it is.
Another new feature is the support of .. in URLs, provided via patch by Guislain Duthieuw, which means you can now have constructs like vfs://root/path/../otherpath which is mapped to vfs://root/otherpath. However, realpath() still doesn't work - there is no way to make this work with how realpath() is currently implemented in PHP itself.
Besides this two bugs have been fixed, one where it was impossible until now to access a child of a directory via the vfsStream API if the child name is contained in the parent's name. The other one was an incomplete error message when you tried to access non-existing files on the root level.