Tuesday, April 23, 2013

Asynchronous banner management for TYPO3

Today I published my banner management extension sf_banners for TYPO3. It is able to show image, flash and HTML banners on a TYPO3 website. Each banner contains a statistic which shows the banners' impressions and clicks. The banners can be limited to an maximum amount of clicks/impressions and you can control the date on which the banners are shown by using the TYPO3 start- and stop function.


One of the main features of the extension is the ability to load banners asynchronously, so the main load time af a page is not being affected by the plugins rendering process.


The extension has been developed using Extbase and Fluid to ensure compatibility to existing and future TYPO3 versions. Also test driven development was one of the main aspects in the development process to ensure, that new features and code changes do not break existing functionality. The extension has been tested with all current versions of TYPO3 from 4.5.x to 6.0.x

If you have any comments or suggestions, feel free to post them on the extensions GitHub projectpage.

Development process

Below follows a short summary about the development process of the extension.

The first approach of the extension was to use pure Extbase/Fluid functionality to display the banners on a page. Since the extension has to update impressions and also has to select the banners from the repository on each request, the plugin has to be non-cached. After having finished this approach, I was disappointed by the performance of the page rendering time. As I tested the extension on several TYPO3 versions, I also found out, that the page rendering time decreased the higher the TYPO3 version got.

So I read a lot of discussions on the TYPO3 mailinglists and the internet about Extbase and performance tuning and ended up with the solution to load all banners asynchronously by Ajax. To do so, I implemented JQuery and added an action to the controller which delivered the banners content as pure HTML. After that, everything seemed to run fine. Since the plugin now was cached and content fetched by Ajax, the page load time was'nt mainly affected by the extension. Sadly my integration tests showed, that there were problems with HTML/JS banners containing document.write JavaScript code. As the banners HTML/JS code was loaded asynchronously, a document.write statement would be executed after the page DOM is loaded. The result was, that the main page was loaded and shortly after that, the HTML/JS banner was shown and the formerly rendered page output was completely removed.

The solution to get rid of the document.write problem was postscribe. This standalone JS library overrides document.write and enables the usage of document.write after the DOM is ready.

All development steps are filed on GitHub and you can look at each of the approaches described above, as the different steps have been tagged.


Saturday, March 16, 2013

Setting up Jenkins CI, Selenium grid and PHPUnit Selenium to perform integration testing

When developing bigger TYPO3 websites with a lot of own extensions and complex functionality, it is nescessary to make sure, that the integration of new features or changes to existing code does not break the functionality of the website.

To meet those requirements, it is recommended to use a continuous integration platform (like Jenkins CI) to automate the testing of the software. The platform can be used to automatically run the unit tests of your TYPO3 ExtBase extensions. If you use the testing framework included in the TYPO3 extension "phpunit", the tests can also help you testing your code with real data from the database.

Another thing you can (and should) test is the website and it's functionality itself. To do so, you can use a browser automation tool to run automated tests against real browsers. One tool available is the Selenium Server.

In this article I will show you how to build up a continuous integration solution consiting of Jenkins CI, Selenium Grid and 3 nodes with different webbrowsers and operating systems. Finally I will show you how to create some simple selenium tests with PHPUnit selenium and show, how to automatically run them against different environment configurations. Please note, that I will not go into deep details installing and configuring each software.

Setting up Jenkins CI and Selenium Grid

First of all, you need to install Jenkins CI on a server. For this article, a fresh Debian Server has been installed with all dependencies for Jenkins CI and finally, the latest release of Jenkins CI has been downloaded from the Jenkins CI homepage. Installation and configuration is really simple as described here. After installation and configuration, Jenkins CI is ready for use. To run PHPUnit tests, make sure you have installed PHPUnit, PHPUnit Selenium and all necessary extensions you need to run your tests.

The next step is to install and configure Selenium on the Jenkins CI server. This instance of Selenium will run Selenium Grid, which will act as the master Selenium grid hub, where all other Selenium nodes connect to. Open the Jenkins Plugin manager and install the Selenium plugin. Installation is really easy and you just have to install the plugin and restart your Jenkins CI. In the Jenkins CI web interface you now have the new menu "Selenium grid" as shown on the screenshot below.


Selenium Grid is ready to handle nodes. Now it is time to configure the Selenium nodes.

Configuring the Selenium nodes

For this article, 3 virtual machines with different browser configurations have been created and configured.

  • Windows XP 32 bit with the following webbrowsers
    • Internet Explorer 8
    • Firefox 19
    • Opera 12
    • Chrome 25
  • Windows 7 32 bit with the following webbrowsers
    • Internet Explorer 9
    • Firefox 19
    • Opera 12
    • Chrome 25
  • Ubuntu 12.10 64 bit with the following webbrowsers
    • Firefox 19
    • Chrome 25

For all virtual machines, JAVA and the browsers listed above has been installed. Chrome, Opera and Internet Explorer requires drivers, so the locally installed Selenium Server can remote control the local webbrowser. Those drivers can be downloaded here or directly via the Selenium homepage. Finally, the latest release of  Selenium has been downloaded to the machines.

For all nodes, the following command has been used to start Selenium.


java -jar \path\to\selenium-server-standalone-2.29.0.jar -role node -hub http://jenkins-server:4444/grid/register -browser "browserName=internet explorer,version=8,maxInstances=1" -browser "browserName=firefox,version=19,maxInstances=5" -browser "browserName=opera,version=12,maxInstances=5" -browser "browserName=chrome,version=25,maxInstances=5"




The node connects to the master Selenium hub and registers the local browsers to the hub. Note, that the parameter "-browser" does not accept spaces in between the individual arguments.

After all nodes have been configured and the local Selenium Server has been started, the Selenium Grid plugin in Jenkins CI should show all registered nodes as shown on the screenshot below.


The Selenium Grid and all nodes are now ready for usage.

The first Selenium tests

Now you are ready to write the first test. Create a new PHP file (selenium-tests.php) and include the following contents.

<?php
class DefaultTest extends PHPUnit_Extensions_Selenium2TestCase {

    /*
     * Setup
     */
    protected function setUp() {
        $this->setHost('your-jenkins');
        $this->setBrowser('internet explorer');
        $this->setBrowserUrl('http://www.google.com');
    }

    /**
     * @test
     */
    public function testTitle() {
        $this->url('http://www.google.com');
        $this->assertEquals('Google', $this->title());
    }
}
?>

Use the setHost() method to set the hostname of your jenkins. This can be an IP-Address or a hostname. Do not include any ports - PHPUnit Seleniums does this for you.

Before setting up a job in jenkins (which I do not show in this article), you can run the test locally by using the following command.

phpunit selenium-tests.php

Now the test is sent to the Selenium Grid server and executed an a node matching the desired browser.

The result should look like shown below

PHPUnit 3.7.13 by Sebastian Bergmann.

.

Time: 6 seconds, Memory: 6.00Mb

OK (1 test, 1 assertion)

Now we want to execute the test on a node with Internet Explorer version 8. To do so, we need to set the desired capabilities of the test. Modify the file selenium-tests.php to the following:

<?php
class DefaultTest extends PHPUnit_Extensions_Selenium2TestCase {

    /*
     * Setup
     */
    protected function setUp() {
        $this->setHost('your-jenkins');
        $this->setDesiredCapabilities( array('version' => '8') );
        $this->setBrowser('internet explorer');
        $this->setBrowserUrl('http://www.google.com');
    }

    /**
     * @test
     */
    public function testTitle() {
        $this->url('http://www.google.com');
        $this->assertEquals('Google', $this->title());
    }
}
?>

Now run the test again and you should see on the Windows XP machine, that Internet Explorer 8 is launched and the URL www.google.com is opened.

That's all. You can modify the desired capabilities to suit the needs of your tests. Since the parameter accepts an array, you can also set the browser version and the target platform together.

The last step is to check in your tests to a repository (e.g. GIT) and setup a new job in Jenkins to execute the selenium tests periodically.

Saturday, March 2, 2013

Integrating a JQuery Cycle image slider in TYPO3 6.0 without the need of installing an extension

There are a lot of JQuery image slider or slideshow extensions in TYPO3 TER, which (hopefully) all do work very well. Integration is mostly very easy - just install the extension, include some static TS and configure the plugin and there you go with a nice "Out of the box" Image Slider. Thit is surely good for a lot of people using TYPO3.

But some extensions come with their own included version of JQuery, which can't be disabled. Others include a lot of inline CSS and/or JS into the frontend, which also can't be disabled. And some extensions do not work correctly with TYPO3 6.0.

On the way looking for the "perfect" solution for a JQuery Image Slider in TYPO3, I decided not to use an extension (no worry about extension updates, breaking changes or incompatibility), but integration the slider directly into the TYPO3 website using default and well known TYPO3 techniques. The advantages of this is: full flexibility, easy administration and easy usage for editors.

This article shows how to create a JQuery image slider using Jquery Cycle, which is generated from a normal TYPO3 image content element. The slider includes a bullet navigation depending on the number of images.

Prerequisites
You need a working TYPO3 6.0 (lower versions should work as well) installation with CSS Styled Content installed and at least one template, so you actually are able to insert content on a page and see it's output in the frontend.

Integration into TYPO3
First of all, you need download the JQuery Cycle Plugin and upload it somewhere in your fileadmin directory (in this example fileadmin/templates/js/jquery.cycle.all.js).

Next, create a new JS file (fileadmin/templates/js/slider.js), where you put the JS for the JQuery Cycle slider. Insert the following content to the file.

$(document).ready(function () {
    $(".imageslider .csc-textpic-imagewrap").cycle({
        fx:'fade',
        pause:1,
        pager:'.slidernav',
        pagerAnchorBuilder:function paginate(idx, el) {
            return '<a class="' + idx + '" href="#" >•</a>';
        }
    });
});

Now, include the JQuery Cycle Plugin and the newly created JS file to your template. If you have not already included a version of JQuery to your site, make sure to include one.

page.includeJS {
  jquery = http://ajax.googleapis.com/ajax/libs/jquery/1.8.3/jquery.min.js
  jquery.external = 1
  cycle = fileadmin/templates/js/jquery.cycle.all.js
  slider = fileadmin/templates/js/slider.js 
}

The slider also requires some CSS for positioning of the bullet navigation. Include the following CSS to your sites CSS file.

.imageslider {
    position: relative;
    width: 300px;
    height: 225px;
    overflow: hidden;
}

.slidernav {
    position: absolute;
    z-index: 10;
    top: 170px;
    right: 20px;
}

.slidernav a {
    text-decoration: none;
    color: #ffffff;
    font-size: 40px;
    margin: 0 0 0 5px;
}

.slidernav a.activeSlide {
    color: #bbbbbb;
}

/* remove default bottom margin */
.imageslider .csc-textpic-image {
  margin: 0;
}

Please notice, that in this example I set the width and height of the image slider to a width of 300 pixel and a height of 225 pixel. This is'nt really necessary, but it makes it easier to position the bullet navigation to the bottom right.

As I don't like to override the default settings of CSS styled content or tt_content, I create a new frame, which the editor can select in the frame-dropdown of each content element.

Include the following to your root Page TSConfig.

TCEFORM.tt_content.section_frame {
     addItems.100 = Slider 
}

Now you must enable the new frame and include the HTML tags for the slider with the following TS.

tt_content.stdWrap.innerWrap.cObject {
  100 = TEXT
  100.value = <div class="imageslider"><ul class="slidernav"></ul>|</div>
}

That's all - the JQuery Cycle image slider is now ready for usage.

Usage
Create a new content element with images only and insert some images.


Set the "Indentation and Frames" to "Slider", the width of the images and the image alignment to 1 column.

Save the content element and you're done.

If you open the page in the frontend, you should see an image slider like shown on the screenshot below.


Conclusion
I hope this article gives you a perspective on what is possible with TYPO3's image content element and just some lines of TS, JS and CSS. If you want a next and previous button for the slider, no problem - just use the "prev" and "next" option of JQuery Cycle plugin.

As you have seen, it is not always necessary to install an extension to integrate an image slider to TYPO3. With the shown solution, editors can use TYPO3's default content elements and the site administrator has full control of the sliders features and can use all nice options of the JQuery Cycle plugin.

Please notice, that everything shown in this article is just an example on how a JQuery Cycle image slider could be integrated into TYPO3. Feel free to modify the settings to your own needs.

Update 15.05.2013
You have to make sure that the JS file, which enables the JQuery Cycle slider, gets the DIV-tag, which contain the container elements for the images. Below is an example for images, which are aligned "above, center". The second line contains the part, where you select the DIV with elements to cycle.

$(document).ready(function () {
    $(".imageslider .csc-textpic-center-inner").cycle({
        fx:'fade',
        pause:1,
        pager:'.slidernav',
        pagerAnchorBuilder:function paginate(idx, el) {
            return '';
        }
    });
});

Saturday, February 23, 2013

Using FAL media in TYPO3 6.0 for inline CSS header images

Last year I wrote an article about how to use a page resources to create an "sliding" header-image, which is included by inline CSS.

In TYPO3 6.0 the FAL (File Abstraction Layer) was introduced, which changes a lot of things regarding file handling. The technique I described in the article mentioned before does not work with TYPO3 6.0, since page resources now are handled by FAL.

In this article I will describe how to create a sliding header-image in TYPO3 6.0 using FAL and the resources of a page.

First you should upload an image which should be uses as the header image. Just upload it somewhere in fileadmin.

Next you select the page, where the header image should be shown. Create a new relation to the formerly uploaded file.



Now you must add the following TS snippet to your TypoScript template

page.cssInline {
  10 = FILES
  10 { 
     references.data =  levelmedia:-1, slide
     references.listNum = 0
     renderObj = TEXT
     renderObj.data = file:current:publicUrl
     renderObj.wrap (
      .header {
        background-image: url(../|);  
      }
    ) 
  }  
}

Please notice, that the snippet above just is an example which uses the first file (listNum = 0) from the resources of the page.

The result is a new inline CSS stylesheet in the frontend of your website, where the formerly uploaded image is used as a background-image for the class "header". Below is the content of the CSS file.

.header {
        background-image: url(../fileadmin/images/typo3-logo.png);  
      }

Sunday, February 17, 2013

Using an Extbase extension in Typoscript

Using typoscript to insert or configure an Extbase extension is quite easy. I use the following typoscript code to assign an Extbase extension to a typoscript object.


myObject = USER
myObject {
     userFunc = tx_extbase_core_bootstrap->run
     extensionName = YourExtensionName
     pluginName = YourPluginName
     switchableControllerActions {
       YourControllerName {
         1 = youraction
       }
     }
     settings =< plugin.tx_yourextensionname.settings
     persistence =< plugin.tx_yourextensionname.persistence
     view =< plugin.tx_yourextensionname.view
}

The first thing to notice is, that the name of your Extension must be in UpperCamelCase. so if your extension key is "your_extension_name", then you have to set it to "YourExtensionName". This also applies to the plugin name.

The next thing you have to do is to configure the section switchableControllerActions with the controller- and the action-name you wish to use.

Last but not least you should assign the settings, the persistence- and the view-configuration to the typoscript object. Now you`re ready to use your Extbase extension in typoscript.

Notice in the example above, that the extension`s typoscript settings are imported to the new typoscript object. With this, you can modify the settings for the typoscript object individually. The same applies to the persistence- and the view-configuration. With this, you are very flexible using your Extbase extension in typoscript.

Friday, January 25, 2013

Configuring Jenkins CI to use multiple TYPO3 versions as build target for Extbase extensions


If you develop TYPO3 extbase extensions, you should know the concepts of test driven development (TDD). Covering as much as possible of your code with tests ensures, that new code or code changes don't break the functionality of your extension. In bigger projects, where several developers work together on an Extbase extension, it is helpfull to use a continuous integration server to automate testing and to ensure code quality.

If the Extbase extension must be compatible with different TYPO3 versions, you have to ensure this during the development process. In this situation, it can be helpful to run automated tests with different TYPO3 versions as build target.

In this article, I will show how to configure a single job in Jenkins CI to use multiple TYPO3 versions as a build target for  running Extbase extension tests.

Before you can start to configure the job in Jenkins CI, you must configure different TYPO3 installations on the server where Jenkins CI is located. This is necessary, because running phpunit tests against an Extbase extension requires the extension to be installed on an working TYPO3 installation.

Configuring the TYPO3 installations

TYPO3 basic setup
On the Jenkins CI Server, you create 3 new virtual hosts. Each virtual host contains a TYPO3 installation with a different version of TYPO3 (4.5.x, 4.7.x and 6.0.x). To keep the TYPO3 installation maintainable, you can symlink each TYPO3 source to a central place on the server, so you easily can update TYPO3 build versions (e.g. version 4.5.20 to 4.5.21)

After the TYPO3 setup, each TYPO3 installation can be opened locally by a hostname like the following
  • http://typo3-45.build.jenkins.local/
  • http://typo3-47.build.jenkins.local/
  • http://typo3-60.build.jenkins.local/
Setting permissions
Next you have to login to each TYPO3 installation and update some settings in the install tool.

Set the file mode mask to:
[BE][fileCreateMask] = 0666 
[BE][folderCreateMask] = 0777

This is necessary for TYPO3 6.0, because there seems to be some problems with local permissions in typo3temp/ (Uncaught TYPO3 Exception: #1294586098: Lock file could not be created) when running the tests through Jenkins CI. 

Installing and configuring the TYPO3 extension "phpunit"
In order to run automated tests in a TYPO3 installation, you have to install the extension "phpunit" from TER. Be sure to get a compatible version of phpunit for each TYPO3 version you use. 

After the extension "phpunit" has been installed, you must create a backend user named "_cli_phpunit". Just create the user and set a random password. 

Make sure, that you can at least execute the tests which came with "phpunit" successfully. This step only ensures, that tests actually can be run successfully.

Setting up the job in Jenkins

The next step is to configure the job in Jenkins. First of all, we create an empty job in Jenkins.



The next step is to create an ANT Build File (built.xml), which contains all settings for  the job. Below is an example ANT Build File for the job described in this article.

<project name="TYPO3-Extbase-Extension" default="build" basedir=".">
        <property name="output" location="${basedir}/build/"/>
        <property file="build.properties" />

        <target name="init">
                <mkdir dir="${output}"/>
                <mkdir dir="${output}/phpcs/"/>
        </target>

        <target name="build" depends="init, typo3-45-unittests, typo3-47-unittests, typo3-60-unittests, phpcs, phpmd, phpcpd">
        </target>

        <target name="typo3-45-unittests">
                <exec executable="php" failonerror="true">
                        <arg path="${typo3path-45}/typo3/cli_dispatch.phpsh" />
                        <arg value="phpunit" />
                        <arg path="${basedir}/src/Tests" />
                </exec>
        </target>

        <target name="typo3-47-unittests">
                <exec executable="php" failonerror="true">
                        <arg path="${typo3path-47}/typo3/cli_dispatch.phpsh" />
                        <arg value="phpunit" />
                        <arg path="${basedir}/src/Tests" />
                </exec>
        </target>

        <target name="typo3-60-unittests">
                <exec executable="php" failonerror="true">
                        <arg path="${typo3path-60}/typo3/cli_dispatch.phpsh" />
                        <arg value="phpunit" />
                        <arg path="${basedir}/src/Tests" />
                </exec>
        </target>

        <target name="phpcs">
                <exec executable="phpcs">
                        <arg line="--report=checkstyle
                                --report-file=${output}/phpcs/checkstyle.xml
                                --standard=/var/lib/jenkins/external_libraries/PHP_CodeSniffer/TYPO3/ruleset.xml
                                ${basedir}" />
                </exec>
        </target>

        <target name="phpmd">
                <exec executable="phpmd">
                        <arg line=" . xml codesize,unusedcode,naming,design --reportfile ${output}/messdetector.xml --exclude Tests/" />
                </exec>
        </target>

        <target name="phpcpd">
                <exec executable="phpcpd">
                        <arg line=" --log-pmd ${output}/phpcpd.xml ." />
                </exec>
        </target>
</project>

The ANT Build File also requires a configuration file (built.properties) with some properties.

php=/usr/bin/php5
typo3path-45=/var/www/path-to-your-typo3-45-root
typo3path-47=/var/www/path-to-your-typo3-47-root
typo3path-60=/var/www/path-to-your-typo3-60-root

After both files have been created, copy them to the /workspace directory of your job. At his point, the workspace directory should not exist and you have to create it manually. Make sure you set the correct permissions, so the jenkins user has read-write permissions to that directory.

The next thing you have to do is to configure the repository, where Jenkins CI checks out the TYPO3 Extbase extension. In this article, the Extbase extension is located in a GIT Repository. Configure the Repository URL, the Branch and set the "Local subdirectory for repo (optional)" to "src". Below is a screenshot of the settings.



Now you have to configure the ANT Build File. Just insert the path to the Build File as shown below.



The ANT Build File above also contains some settings for phpcs, phpmd and phpcpd. If you want to use Checkstyle, PHP messdetection and PHP duplicate code detection, you can configure those settings in the Post-Build Actions as shown on the screenshot below.



Now your job is ready to run the first time. Actually it will fail, since the configuration process is not finished yet, but it is required to run the job, so the Extbase extension is checked out from the GIT repository.

Installing the Extbase extension and running the job

After running the job the first time, you should have the folder /src inside the jobs workspace directory. This folder contains the extension, which we now symlink to the /typo3conf/ext directory of each TYPO3 installation we created earlier. Make sure, that the name of the symlink is identical to the extension key.

The symlink ensures, that updates to the extension automatically are available in all TYPO3 installations.

Now you have to login to each TYPO3 installation and install the Extbase extension with the extension manager.

When the Extbase extension is installed, you are ready to run the job and will (hopefully) see, that your Extbase extension´s tests will run on all configured TYPO3 versions.



You can also configure the job only to use a special TYPO3 version as build target as shown below.

The above example will only run tests against TYPO3 version 4.5.

Additional notes

During the development process of an extension, the table-structure may change due to new or changed fields. Those changes are not automatically updated in the local TYPO3 installations, where the extension is installed, so you have to make sure, that you update the extension´s table structure by using the extension manager in each TYPO3 installation, if you made changes to the extension´s table structure.



Thursday, January 3, 2013

Logwatch filter for ModSecurity 2

I often use ModSecurity 2 and the OWASP ModSecurity Core Rule Set (CRS) to protect a website from potential attacks. ModSecurity 2 is able to write blocked attacks to a audit logfile, so you actually can see, which Core Rule and which data matched the attack that has been blocked. The logfile can also help you to analyze false positives, so you can modify the CRS to your needs.

As a server admin, you regulary should check the logfiles of your server. One tool to help you analyzing your server´s logfiles is Logwatch, which can send reports by e-mail with a summary of the logfile analysis. Sadly Logwatch was´nt able to analyze ModSecurity 2 audit logfiles and I could´nt find a filter for Logwatch, which fullfilled my needs.

So I wrote a filter for Logwatch, which analyzes a ModSecurity 2 audit logfile for blocked attacks and collects those information for a given time period as a report. The report is seperated by vhost, so you can have a quick overview on which attacks have been blocked on which vhost. Also the reports contains a top 10 summary of blocked IP addresses.

Here is a sample output from the filter:
--------------------- ModSecurity2 (mod_security2) Begin ------------------------

ATTACKS BLOCKED ON VHOSTS:

subdomain.domain.tld - 2 time(s)
[ip: xxx.xxx.xxx.xxx] [id: 981231 ] [msg: SQL Comment Sequence Detected.]  - 1 time(s)
[ip: xxx.xxx.xxx.xxx] [id: 981231 ] [msg: SQL Comment Sequence Detected.]  - 1 time(s)

www.site.tld - 1 time(s)
[ip: xxx.xxx.xxx.xxx] [id: 990012 ] [msg: Rogue web site crawler]  - 1 time(s)
[ip: xxx.xxx.xxx.xx] [id: 981318 ] [msg: SQL Injection Attack: Common Injection Testing Detected]  - 5 time(s)
[ip: xxx.xxx.xxx.xx] [id: 950901 ] [msg: SQL Injection Attack: SQL Tautology Detected.]  - 2 time(s)

www.anothersite.tld - 1 time(s)
[ip: xxx.xxx.xxx.xxx] [id: 958291 ] [msg: Range: field exists and begins with 0.]  - 1 time(s)

TOP 10 BLOCKED IPS:
xxx.xxx.xxx.xxx - 2 time(s)
xx.xxx.xxx.xxx - 1 time(s)
xxx.xxx.xx.xx - 1 time(s)
xxx.xxx.xxx.xx - 1 time(s)
xxx.xxx.xxx.xxx - 1 time(s)

---------------------- ModSecurity2 (mod_security2) End -------------------------

The filter has been tested with ModSecurity 2 version 2.6.0 (CRS 2.2.0) and version 2.7.1 (CRS 2.2.6)

I published the Logwatch filter for Mod Security 2 on Github, so feel free to submit change requests or bug reports.