Squiz Labs Blog - The latest news from the R&D division of Squiz®

Subscribe to our RSS feeds

PHP_CodeSniffer 2.0.0 alpha1 released

I've just released the first alpha of PHP_CodeSniffer version 2.0.0. This update brings an often requested feature; the ability for PHP_CodeSniffer to automatically fix the problems that it finds. It also contains a complete rewrite of the comment parsing sniffs, finally removing what I feel is the poorest code in PHP_CodeSniffer; the comment parsing classes.

Fixing Errors Automatically with PHPCBF

PHP_CodeSniffer now comes with a second script; phpcbf, the PHP Code Beautifier and Fixer. This script piggy-backs off PHP_CodeSniffer to provide fixes for a lot of common errors. It will never fix 100% of the errors PHP_CodeSniffer finds as many require a developer to make a decision (e.g., can you use === here?) or may cause the code to execute differently if changed (e.g., uppercasing a constant name). But there are still a lot of errors that can be corrected without causing issues. Out of the 566 unique error messages that PHP_CodeSniffer can currently produce, version 2.0.0a1 is able to correct 202 of them automatically, which is about 35%. When you run PHP_CodeSniffer and get a report of the errors found, you will now be able to see which of those errors can be automatically corrected.

Along with this new script, PHP_CodeSniffer adds a new report type; the diff report. If you don't like the idea of PHP_CodeSniffer fixing errors automatically, you can instead ask it to output a diff of the fixes that it would make using the command line argument --report=diff. If you like what you see, you can simply change the phpcs command to phpcbf, leave all the command line options the same, and let PHP_CodeSniffer patch your files.

All this new functionality is documented on the wiki, and includes sample output, so please take a read: https://github.com/squizlabs/PHP_CodeSniffer/wiki/Fixing-Errors-Automatically

Plugin for Sublime Text

I use Sublime Text 2 for development, as do some of the other developers at Squiz Labs. I've been working with one of these developers to build a plugin for Sublime Text that will run PHP_CodeSniffer on the current file, show which errors can be fixed automatically, fix the errors for you if you decide to have them fixed, and show a diff of what it did. I've added quite a few features to PHP_CodeSniffer to make this plugin feel as integrated as possible and I find it incredibly useful for tidying up my code before committing.

The plugin is still being documented, and made to work with Sublime Text 3 due to some issues with the diff library, but it will be released through Package Control as soon as they are worked out (or sooner, for ST2 only if needed). In the meantime, you can clone the repository yourself or just watch it for activity if you are interested in knowing when it is ready: https://github.com/squizlabs/sublime-PHP_CodeSniffer

Adding Fixes to Custom Sniffs

If you have your own custom sniffs and want to correct errors automatically, you need to make a couple of changes. The first thing you need to do is call the addFixableError() or addFixableWarning() methods instead of addErorr() and addWarning(), to let PHP_CodeSniffer know the error can be fixed. You can then make use of the new PHP_CodeSniffer_Fixer class to replace token values and add content to tokens, modifying the token stack as you go.

Here is a simple example, to ensure that comments don't appear at the end of a code line ($stackPtr is the comment token):

$error = 'Comments may not appear after statements';
$phpcsFile->addError($error, $stackPtr, 'Found');

The fix this, we just need to add a newline before the comment. Other sniffs will do things like fix alignment and spacing of the comment for us. It is also important we check if the fixer is enabled and if we are supposed to be fixing this specific error message. We end up with code like this:

$error = 'Comments may not appear after statements';
$fix   = $phpcsFile->addFixableError($error, $stackPtr, 'Found');
if ($fix === true && $phpcsFile->fixer->enabled === true) {
    $phpcsFile->fixer->addNewlineBefore($stackPtr);
}

If you are changing multiple tokens in a single fix, using a changeset will ensure that they are either all applied at once, or not applied at all. This is important if a partial change would lead to a parse error, or another equally bad outcome. In the following example, a changeset is used to ensure that all content between the array braces is removed, even if the content spans multiple lines. If one of the tokens to be removed has already been modified by another sniff, the whole changeset will be ignored and PHP_CodeSniffer will attempt to apply this changeset on a second run through the file.

$error = 'Empty declaration must have no space between parentheses';
$fix   = $phpcsFile->addFixableError($error, $stackPtr, 'SpaceFound');
if ($fix === true && $phpcsFile->fixer->enabled === true) {
    $phpcsFile->fixer->beginChangeset();
    for ($i = ($arrayStart + 1); $i < $arrayEnd; $i++) {
        $phpcsFile->fixer->replaceToken($i, '');
    }

    $phpcsFile->fixer->endChangeset();
}

Take a look at the PHP_CodeSniffer_Fixer class for all the methods you can use: https://github.com/squizlabs/PHP_CodeSniffer/blob/phpcs-fixer/CodeSniffer/Fixer.php

Removal of the Comment Parser

The other major change is the removal of the comment parsing classes. If you have written custom sniffs that either use the comment parsing classes or extend sniffs that do, you are going to need to review your sniffs and possibly rewrite them. This has already been done for all included sniffs, so there are quite a few examples to help you get started.

The best way to explain the change is to show an example of how PHP_CodeSniffer has changed the way it handles doc comments internally. If PHP_CodeSniffer is processing the following comment:

/**
 * PHP_CodeSniffer tokenises PHP code.
 *
 * @author    Greg Sherwood <gsherwood@squiz.net>
 * @copyright 2006-2012 Squiz Pty Ltd
 */

It would have previously tokenized it like this (spaces have been replaced by periods):

T_DOC_COMMENT => /**\n
T_DOC_COMMENT =>  * PHP_CodeSniffer.tokenises.PHP.code.\n
T_DOC_COMMENT =>  *\n
T_DOC_COMMENT =>  * @author....Greg.Sherwood.<gsherwood@squiz.net>\n
T_DOC_COMMENT =>  * @copyright.2006-2012.Squiz.Pty.Ltd\n
T_DOC_COMMENT =>  */

This format makes it very hard to look for specific things like a comment tag name, and makes it very hard to make fixes to the comment automatically. So PHP_CodeSniffer will now tokenize the comment like this:

T_DOC_COMMENT_OPEN_TAG => /**
T_DOC_COMMENT_WHITESPACE => \n
T_DOC_COMMENT_WHITESPACE => .
T_DOC_COMMENT_STAR => *
T_DOC_COMMENT_WHITESPACE => .
T_DOC_COMMENT_STRING => PHP_CodeSniffer.tokenises.PHP.code.
T_DOC_COMMENT_WHITESPACE => \n
T_DOC_COMMENT_WHITESPACE => .
T_DOC_COMMENT_STAR => *
T_DOC_COMMENT_WHITESPACE => \n
T_DOC_COMMENT_WHITESPACE => .
T_DOC_COMMENT_STAR => *
T_DOC_COMMENT_WHITESPACE => .
T_DOC_COMMENT_TAG => @author
T_DOC_COMMENT_WHITESPACE => ....
T_DOC_COMMENT_STRING => Greg.Sherwood <gsherwood@squiz.net>
T_DOC_COMMENT_WHITESPACE => \n
T_DOC_COMMENT_WHITESPACE => .
T_DOC_COMMENT_STAR => *
T_DOC_COMMENT_WHITESPACE => .
T_DOC_COMMENT_TAG => @copyright
T_DOC_COMMENT_WHITESPACE => .
T_DOC_COMMENT_STRING => 2006-2012.Squiz.Pty.Ltd
T_DOC_COMMENT_WHITESPACE => \n
T_DOC_COMMENT_WHITESPACE => .
T_DOC_COMMENT_CLOSE_TAG => */

As you can see, this is a significant number of extra tokens, but allows for much finer control over how a comment is processed. The T_DOC_COMMENT token has also been removed, replaced instead by T_DOC_COMMENT_OPEN_TAG. If you have a sniff listening for T_DOC_COMMENT, make sure you change it in your register() method and anywhere else it is used throughout your sniffs.

Here is a fairly complex example of a sniff rewrite; the Squiz FunctionComment sniff:

old: https://github.com/squizlabs/PHP_CodeSniffer/blob/master/...
new: https://github.com/squizlabs/PHP_CodeSniffer/blob/phpcs-fixer/...

And here is the commit of the changes required for the new comment tokenizer: https://github.com/squizlabs/PHP_CodeSniffer/commit/...

Essentially, instead of using the comment parser functions to get at tag values, you can use the standard PHP_CodeSniffer functions to navigate the token stack and look for what you need. This allows you to get a precise location of each piece of the comment and make fixes to it if you need to. You can also report more accurately on where an error has occurred.

Everything Else

Besides these major changes, there are a few important new features that have made it into version 2.0.0a1, including the ability to write your own custom report classes, the ability to set default command line argument values in ruleset XML files, and an easier way for custom sniff developers to skip through the token tree.

View the full 2.0.0a1 changelog at PEAR or Github

Stay up to date on all PHP_CodeSniffer changes, including new features and releases, by subscribing to the RSS feed or following me on Twitter.


PHP_CodeSniffer 1.4.7 and 1.5.0RC4 released

PHP_CodeSniffer versions 1.4.7 and 1.5.0RC4 have just been uploaded to PEAR and are now available to install. Version 1.4.7 is primarily a bug fix release, but also contains a new JUnit report format, a few new sniff settings, and a change to the PSR2 standard based on recently added errata.

Version 1.5.0RC4 additionally adds the ability to restrict violations to specific error messages by using the --sniffs command line argument. Previously, this only restricted violations to an entire sniff and not individual messages.

Special thanks to the 7 developers who directly contributed code to these releases. Your help is always very much appreciated.

View the full 1.4.7 changelog at PEAR or Github
View the full 1.5.0RC4 changelog at PEAR or Github

Stay up to date on all PHP_CodeSniffer changes, including new features and releases, by subscribing to the RSS feed or following me on Twitter.


PHP_CodeSniffer 1.4.6 and 1.5.0RC3 released

PHP_CodeSniffer versions 1.4.6 and 1.5.0RC3 have just been uploaded to PEAR and are now available to install. Version 1.4.6 is primarily a bug fix release, but also contains a new JSON report format, a huge number of sniff docs, and a few new sniffs (mostly in the Squiz standard).

Version 1.5.0RC3 additionally contains a fix for the --report-file command line argument, support for a new T_GOTO_LABEL token, and a change to PHP_CodeSniffer::isCamelCaps() to allow acronyms at the start of a string if not performing a strict check.

Special thanks to the 9 developers who directly contributed code to these releases. Your help is always very much appreciated. And special thanks to Spencer Rinehart for writing so much documentation for the included sniffs.

View the full 1.4.6 changelog at PEAR or Github
View the full 1.5.0RC3 changelog at PEAR or Github

Stay up to date on all PHP_CodeSniffer changes, including new features and releases, by subscribing to the RSS feed or following me on Twitter.


PHP_CodeSniffer 1.4.5 and 1.5.0RC2 released

PHP_CodeSniffer versions 1.4.5 and 1.5.0RC2 have just been uploaded to PEAR and are now available to install. Version 1.4.5 is primarily a bug fix release, although there are a few new sniffs and sniff settings that some developers may find useful. In addition to these changes, 1.5.0RC2 contains big changes to the way rulesets are processed to make them more predictable and to add a couple of new features.

From version 1.5.0RC2 onwards, ruleset processing has much better support for relative paths and detection of directories of sniffs. This may mean that sniffs that were not previously being included in a standard are now included correctly. Please check your standards to see if any new sniffs are being included. The best way to do this is to use the -e command line argument. For example, phpcs --standard=mystandard.xml -e , which will print a list of sniffs that will be run over your code.

Version 1.5.0RC2 also includes the ability to exclude whole directories of sniffs inside a ruleset and the ability to pass multiple standards to PHP_CodeSniffer on the command line. For example, phpcs --standard=PEAR,Squiz,mystandard.xml /path/to/code , which will run 3 standards against your code.

Special thanks to the 4 developers who directly contributed code to these releases. Your help is always very much appreciated.

You can view the full 1.4.5 changelog on the PHP_CodeSniffer 1.4.5 download page and the full 1.5.0RC2 changelog on the PHP_CodeSniffer 1.5.0RC2 download page.

Stay up to date on all PHP_CodeSniffer changes, including new features and releases, by subscribing to the RSS feed or following me on Twitter.


PHP_CodeSniffer 1.4.4 released

PHP_CodeSniffer version 1.4.4 has just been uploaded to PEAR and is now available to install. This is primarily a bug fix release, although there are a couple of nice new sniff features that some developers may find useful, including a new sniff to run CSS Lint on your CSS files.

Special thanks to the 6 developers who directly contributed code to this release. Your help is always very much appreciated.

You can view the full changelog on the PHP_CodeSniffer download page.

Stay up to date on all PHP_CodeSniffer changes, including new features and releases, by subscribing to the RSS feed or following me on Twitter.


PHP_CodeSniffer 1.4.3 released

PHP_CodeSniffer version 1.4.3 has just been uploaded to PEAR and is now available to install.

This is primarily a bug fix release, although support for the upcoming PHP 5.5 T_FINALLY token has been added, a few PSR-2 issues have been fixed and a change has been made to improve Composer support.

Special thanks to the 4 developers who directly contributed code to this branch. Your help is always very much appreciated.

You can view the full changelog on the PHP_CodeSniffer download page.

Just a special note to say that my wife and I are expecting another baby in less than 2 weeks, so PHP_CodeSniffer development is likely to reduce significantly over the Christmas/New Year period. But please keep sending in bug reports and pull requests. I'll review them all when I get back, or if I get some time over the holidays.   

Stay up to date on all PHP_CodeSniffer changes, including new features and releases, by subscribing to the RSS feed or following me on Twitter.


PHP_CodeSniffer general memory improvements

PHP_CodeSniffer version 1.3.6 introduced memory improvements when using the summary report. You can take a look at the improvements that were reported at the time when running over the Symfony2 codebase.

Obviously, the summary report is only useful when running PHP_CodeSniffer from the command line and viewing the output. It wont be used in continuous integration systems, or in text editors, or by developers actually fixing errors.

But these improvements were just the start of a bigger change to try and restructure the PHP_CodeSniffer reporting system to stop it relying on so much memory during a run over a large number of files with a large number of errors. These changes are now in development and are available in a new git branch for testing right now.

To test these new changes, I again ran the PEAR coding standard over a Symfony2 checkout. Symfony2 doesn't use the PEAR coding standard, so this is a good way to generate a lot of errors and warnings over a large code base.

The PEAR standard generates 29,572 errors and 11,752 warnings in 2049 different files. Here is a summary of the time and memory usage, as reported by PHP_Timer:

Type of run Time (seconds) Memory (Mb)
Old code with warnings
(--report=full)
54 189.25
Old code without warnings
(--report=full -n)
52 140.75
New code with warnings
(--report=full)
52 75.00
New code without warnings
(--report=full -n)       
51 75.00

Clearly, the memory improvements are significant. There is probably a bit more that can be squeezed out depending on the type of report being shown, but that is pretty close to what can be expected from reports like CSV, XML and Checkstyle, that are typically used by automated tools and continuous integration systems.

Smaller code bases and/or less errors and warnings will further reduce the memory usage and you may actually see larger improvements on your own projects.

To summarise the changes: instead of keeping errors and warnings in memory so reports can be generated at the end of a run, PHP_CodeSniffer now writes a partial report to a file after each file is processed. At the end, the reporting system is given this cached data and able to add headers and footers, before it is finally output to screen. If the report is going to be written to a file instead, that file will be used throughout the run for the partial reports. Otherwise, a temp file is written to the current directory and removed once the run has been completed.

If you would like to try out these changes, you can grab the code from a new branch on the git repository. The easiest way to do this is to run the following commands:

git clone git://github.com/squizlabs/PHP_CodeSniffer.git
cd PHP_CodeSniffer
git checkout report-memory-improvements
php scripts/phpcs /path/to/code ...

To achieve these improvements, it has been necessary to remove a couple of rarely used features. So far, only support for multi-file sniffs (of which there are none in the core distribution) has been removed and there is no longer a shortcut to print both the summary and source reports at the same time, but this can still be done using the standard reporting arguments.

Other than that, PHP_CodeSniffer should still work exactly the same. If not, please get in touch and let me know. The best way is to contact me on Twitter, or submit bug reports and pull requests.


PHP_CodeSniffer 1.4.1 released

PHP_CodeSniffer version 1.4.1 has just been uploaded to PEAR and is now available to install. This release includes a few important changes for developers who maintain their own standards and sniffs.

Ignore Patterns

In version 1.3.6, ignore patterns were changed so that they are checked against the relative path of a file instead of the absolute path. This change was done to allow standards to define ignore patterns that didn't have to assume where the code was installed. But there were only very specific cases where using relative paths was better than absolute paths, and all existing ignore patterns needed to be checked to ensure they still worked. Some didn't, and I felt that was important enough to revert the change.

So from version 1.4.1, ignore patterns are now checked against the absolute path of a file again. If you need the ability to check an ignore pattern against the relative path of a file, you can specify this in the ruleset.xml file:

<!--
    Patterns can be specified as relative if you would
    like the relative path of the file checked instead of the
    full path. This can sometimes help with portability.

    The relative path is determined based on the paths you
    pass into PHP_CodeSniffer on the command line.
-->
<exclude-pattern type="relative">^/tests/*</exclude-pattern>
<exclude-pattern type="relative">^/data/*</exclude-pattern>

The T_INLINE_ELSE Token

Natively, PHP doesn't tokenize the question mark or colon in an inline IF statement as a special type of token. PHP_CodeSniffer has always converted the question mark into a token called T_INLINE_THEN but it has always left the colon as T_COLON. Sniffs that look for inline IF statements typically look for the T_INLINE_THEN token and then look ahead for a T_COLON to find the ELSE component.

But now, the colon in an inline IF statement is tokenized as T_INLINE_ELSE. For example:

<?php
$foo = ($bar === true ? 'yes' : 'no');

Will tokenize as:

Process token 0 on line 1 [lvl:0;]: T_OPEN_TAG => <?php\n
Process token 1 on line 2 [lvl:0;]: T_VARIABLE => $foo
Process token 2 on line 2 [lvl:0;]: T_WHITESPACE =>  
Process token 3 on line 2 [lvl:0;]: T_EQUAL => =
Process token 4 on line 2 [lvl:0;]: T_WHITESPACE =>  
Process token 5 on line 2 [lvl:0;]: T_OPEN_PARENTHESIS => (
Process token 6 on line 2 [lvl:0;]: T_VARIABLE => $bar
Process token 7 on line 2 [lvl:0;]: T_WHITESPACE =>  
Process token 8 on line 2 [lvl:0;]: T_IS_IDENTICAL => ===
Process token 9 on line 2 [lvl:0;]: T_WHITESPACE =>  
Process token 10 on line 2 [lvl:0;]: T_TRUE => true
Process token 11 on line 2 [lvl:0;]: T_WHITESPACE =>  
Process token 12 on line 2 [lvl:0;]: T_INLINE_THEN => ?
Process token 13 on line 2 [lvl:0;]: T_WHITESPACE =>  
Process token 14 on line 2 [lvl:0;]: T_CONSTANT_ENCAPSED_STRING => 'yes'
Process token 15 on line 2 [lvl:0;]: T_WHITESPACE =>  
Process token 16 on line 2 [lvl:0;]: T_INLINE_ELSE => :
Process token 17 on line 2 [lvl:0;]: T_WHITESPACE =>  
Process token 18 on line 2 [lvl:0;]: T_CONSTANT_ENCAPSED_STRING => 'no'
Process token 19 on line 2 [lvl:0;]: T_CLOSE_PARENTHESIS => )
Process token 20 on line 2 [lvl:0;]: T_SEMICOLON => ;
Process token 21 on line 2 [lvl:0;]: T_WHITESPACE => \n

Existing sniffs will need to be modified to ensure they work correctly.

Changing the Type of Messages

A problem coding standard developers used to face was that messages could not be changed from errors to warnings, or from warnings to errors. This meant that a new sniff had to be written, or they'd have to live with the existing one, even though it didn't match their coding standard. Sometimes severity levels could be used to work around the problem. But version 1.4.1 now allows you to change the type of any message:

<!--
    You can also change the type of a message from error to
    warning and vice versa.
-->
<rule ref="Generic.Commenting.Todo.CommentFound">
  <type>error</type>
</rule>
<rule ref="Squiz.Strings.DoubleQuoteUsage.ContainsVar">
  <type>warning</type>
</rule>

Mixed Line Endings

PHP_CodeSniffer has trouble tokenizing files that contain mixed line endings. The newline character that is found at the end of the first line is used throughout the tokenizing process to save a lot of processing time, but this may result in line endings being missed. Even the PHP tokenizer can give mixed results when the line endings do not match, although you are unlikely to see any errors on the screen. If processing JS code, you are more likely to see PHP notices from sniffs that get confused.

In version 1.4.1, a special internal warning is added to every file that contains mixed line endings. The warning lets you know that PHP_CodeSniffer may have problems checking that file. It wont stop  all the PHP notices from being shown, but it will at least tell you why they are there. And for continuous integration systems that hide the notices, you'll get a notification in the error report so you are informed.

This warning has the code Internal.LineEndings.Mixed and can be overriden in a ruleset.xml file in the same way the Internal.NoCodeFound message can be. This allows you to change the message, the type to an error or hide it completely by setting the severity to 0.

Everything Else

Apart from these changes, a lot of work has gone into testing and fixing issues with the new PSR-1 and PSR-2 standards that were released in version 1.4.0.

Special thanks to the 5 developers who directly contributed code to this branch. Your help and contributions are always very much appreciated.

You can view the full changelog on the PHP_CodeSniffer download page.

Stay up to date on all PHP_CodeSniffer changes, including new features and releases, by subscribing to the RSS feed or following me on Twitter.


PHP_CodeSniffer 1.4.0 released

PHP_CodeSniffer version 1.4.0 has just been uploaded to PEAR and is now available to install. This release includes two new coding standards; PSR-1 and PSR-2.

A lot of effort has gone into compiling these standards from existing sniffs, writing new sniffs, and making core changes to PHP_CodeSniffer to support new features that they require. I think they are a good representation of the written standards and another couple of great generic coding standards that you may choose to adopt in your own projects.

Special thanks to the 3 developers who directly contributed code to this branch. Your help is always very much appreciated.

I'd like to also thank everyone who tested the PSR-1 and PSR-2 standards as they were being developed over the last couple of months, and those developers who helped me on the PHP-FIG mailing list as I tried to decipher them. Your bug reports, pull requests and general feedback were always helpful.

But a lot more testing of these new standards needs to be done, so please keep the feedback coming through.

Apart from the new standards, version 1.4.0 contains a couple of other nice changes, including a new notify-send report and the ability to explain a standard. You can view the full changelog on the PHP_CodeSniffer download page.

Stay up to date on all PHP_CodeSniffer changes, including new features and releases, by subscribing to the RSS feed or following me on Twitter.


PHP_CodeSniffer memory improvements to summary report

Memory is the first thing to run out during a really big PHP_CodeSniffer run when a large number of errors and warnings are generated. The reason for this is pretty simple; PHP_CodeSniffer keeps the errors and warnings in memory so it can print consolidated error reports at the end.

The problem is that when you first introduce a coding standard to an existing code base, you're probably going to have a lot of errors and warnings being generated over a lot of files, so you might run out of memory.

So how do you identify the files that need the most work (so you can cut down the number of generated errors) when you can't view the report?

A new memory usage improvement for PHP_CodeSniffer's summary report can help. When you are printing the summary report by itself, PHP_CodeSniffer will no longer generate any error or warning messages. The summary report only shows the number of violations per file and not the detail, so this does not affect the functionality of the summary report in any way.

Note: if you tell PHP_CodeSniffer to also show sources in the summary report (the -s option) the errors and warnings have to be generated and stored, so you will not get any memory usage improvements.

To test this new change, I ran the PEAR coding standard over a Symfony2 checkout. Obviously, Symfony2 doesn't use the PEAR coding standard, so this is a good way to generate a lot of errors and warnings over a large code base.

The PEAR standard generates 29,091 errors and 11,446 warnings in 2007 different files. Here is a summary of the time and memory usage, as reported by PHP_Timer:

Type of run Time (seconds) Memory (Mb)
Old code with warnings
(--report=summary)
56 178.00
Old code without warnings
(--report=summary -n)
56 130.50
New code with warnings
(--report=summary)
51 79.25
New code without warnings
(--report=summary -n)       
51 79.25

When running with the old code, you can save a significant amount of memory by just ignoring warnings. When you do this, PHP_CodeSniffer wont even generate the warning messages and instead just generate the error message. This is a memory usage improvement that was implemented quite a while ago.

But the new code still uses far less memory than the existing code, even when the existing code ignores warnings. With warnings, the memory usage is less than half.

Obviously, these figures will change depending on the number of files being checked and the number of errors and warnings being generated, but you should see some memory improvements when running the summary report from now on.

This change will be released in PHP_CodeSniffer 1.3.6. I don't have a release date set, but it should be in the next couple of weeks. In the meantime, you can grab and run the lastest code from Github.


Prev Next

Squiz Labs

R & D division of Squiz Pty Ltd

Open source web experience management solutions

Squiz Labs is the research and development division of Squiz, the company behind the Squiz Suite of web experience management and development tools.

Our PHP and JavaScript developers are responsible for producing innovative enterprise-quality software while our interface designers and testing team ensure our products both look great and are easy to use.