Educating the world

Our blog has over 10,000 readers a month

Understanding Yii Layouts and Views

July 5th, 2013

When learning Yii I found it difficult to match the different layout strategies used in the demo applications that are bundled with Yii, specifically Helloworld, Hangman and Blog.

A layout is essentially another view. Layouts are optional as everything can be done in the view. If all your pages share a common look or feel then you may want to refactor the majority of the static (or nearly static) content into the Layout, leaving the view to provide the body of the content that is specific to that page.

If you’ve written a lot of PHP applications then you’ll recognise the following:


The page and maybe some more PHP.

If “The page and maybe some more PHP.” is the view then the rest is the layout. Or to put it another way a layout is a decorator for a view.

A nice example of this is the Blog demo. The view contains all the page specific body but the menus and side bars are held in the layout. You could add the layout to each view and not use layouts at all but this would mean repeating a lot of the same code across all the views.

The first thing to understand is the precedence of the layout overrides. As with all these things the closer to the code that’s running the higher the priority.

  1. Action: With the highest priority, this layout can be set inside the body of the controller action.


    class SiteController
       extends CController
      public function actionIndex()
        $this->layout "mylayout";
  2. Controller:The layout can be set at the controller level by overriding the layout variable from the base class.


    class PostController
       extends Controller
      public $layout='column2';
  3. Theme: The layout may be taken from the current theme.
  4. Module: The layout may be taken from the current module.
  5. Parent Modules: If the current module has no layout, then traverse up its parents until you find one.
  6. Default: Finally the Yii application defines the default layout [Yii::app()->layout] which is meant as a catch all.
  7. None: All these places are searched but if at the end of the day they don’t point to anything then a layout won’t be used.

This demo is the simplest because it does not render a view, it only outputs raw text (or data). Let’s trace the path through the application.

  1. /helloworld/ is accessed and Yii looks for the configuration file /helloworld/protected/config/main.php in order to find the first controller to load.
  2. The main.php configuration file is not found so Yii then looks for the default controller called Site. It loads /helloworld/protected/controllers/SiteController.php
  3. The default action for a controller is Index so actionIndex() is called which just echos some stuff to the screen.

This demo uses a single layout for all pages.

  1. /hangman/ is accessed and Yii looks for the configuration file /hangman/protected/config/main.php in order to find the first controller to load.
  2. The defaultController is game, so Yii loads /hangman/protected/controllers/GameController.php
  3. The default action has been set to “play” by overriding the defaultAction field of the GameController class. So actionPlay() is called first.
  4. At the end of actionPlay() the function render() is called with either “guess” as the view or “play". Let’s continue assuming “play” was selected.
  5. Now Yii will render /protected/views/game/play.php into a variable.
  6. Next it will look for a layout to place that rendering. Following the priorities from above it will eventually get to the default layout for the application (CWebApplication) which is layouts/main.php
  7. Yii will make sure that layouts/main.php exists then it will render that layout, setting $content to the result of rendering the view file.

This demo uses 3 layout files to render the site. main.php is the default catch-all layout and column1.php & column2.php are intermediate layout files.

  1. /blog/ is accessed and Yii looks for the configuration file /blog/protected/config/main.php in order to find the first controller to load.
  2. The defaultController is post, so Yii loads /blog/protected/controllers/PostController.php
  3. PostController.php sets the class layout to “column2″, so all views will use “column2″ as their layout.
  4. The default action is Index so actionIndex() is called next. When it gets to the end it calls render() to render the index view.
  5. /blog/protected/views/post/index.php is used to draw the blog posts and the result is returned to the renderer.
  6. The renderer uses the result of the view-render as the $content in the column2 layout.
  7. The column2 layout has the following form. It means that stuff between beginContent and endContent will be given to /layouts/main as its $content.



There’s another pretty decent article on Larry Ullman’s site, Working with Layouts in Yii.

Setting up XDebug under XAMPP

July 3rd, 2013

I would like to debug PHP in Eclipse PDT while it runs under an Apache server with a bit of MySQL thrown in. In order to do the remote debug one needs to configure PHP to use XDebug which is a standard cross-platform debugger that is used by a variety of languages to debug over the wire. It is based on DBGp, a common debugger protocol for languages and debugger UI communication.

I downloaded and installed XAMPP which bundles together a LAMP stack in one easy download and installs them so they all work together (or so I thought).

I followed the standard instructions to switch on XDebug except that I installed it under e:\xampp instead of the default c:\xampp.

  1. Launch the XAMPP Control Panel.
  2. On the Apache row click Config, then PHP (php.ini) to load the PHP configuration file.
  3. Forward search for [XDebug]
  4. Make sure the following options are uncommented (i.e. remove the semi-colon at the front of the line) and fill in the entries to match those below.

    zend_extension = “E:\xampp\php\ext\php_xdebug.dll”
    xdebug.remote_enable = 1
    xdebug.remote_handler = “dbgp”
    xdebug.remote_host = “″
    xdebug.remote_port = “9000″

  5. Stop Apache
  6. Start Apache

On starting Apache the following message pops up:

The procedure entry point zend_unmangled_property_name_ex could not be located in the dynamic link library php5ts.dll

After a lot of really boring reading in the usual forums and help web sites I find out that the php_xdebug.dll is not compiled correctly for the version of PHP I’m using. This is very strange because it was downloaded as a bundle so everything should be compatible with everything else, but it wasn’t.

To confirm this type:

cd e:\xampp\php
php -m

which gives the following output:

Failed loading E:\xampp\php\ext\php_xdebug.dll
[PHP Modules]

[Zend Modules]

Microsoft Windows dictates an internal DLL binary format which coincidentally is released with a new version of Microsoft’s Visual studio. This makes programs compiled with different versions of compiler incompatible with each other - thanks for that. It causes problems in every computer language that is compiled with a Microsoft compiler. PHP is just one of them. Python is another. If you compile Python under Visual Studio 9 you will have to recompile all the support modules with the same compiler. So not only do you have to care about whether it was compiled into 32 or 64 bit code but you also have to care about which compiler was used too.

The name of the XAMPP binary tells you which version of Visual ‘C’ was used to create the application suite. In my case I downloaded xampp-win32-1.8.2-0-VC9-installer.exe. From the file name we can see that this is a windows 32 bit version compiled using Visual ‘C’ 9.

This only gives us some of the story. For the rest we need to run XAMPP and get it to tell us how it was compiled. In the document root E:\xampp\htdocs create a file called p.php and fill it with:

<?php phpinfo(); ?>

Next open you browser and go to:

There are several lines of importance:

PHP Version 5.4.16
Compiler MSVC9 (Visual C++ 2008)
Architecture x86
Zend Extension Build API220100525,TS,VC9
PHP Extension Build API20100525,TS,VC9

The phpinfo() confirms that Microsoft’s Visual ‘C’ version 9 (MSVC9) was used as the compiler which was built in Visual C++ 2008. The Visual C++ 2008 tells us that the Apache needs the Visual C++ Redistribution libraries to be installed. You wouldn’t be able to run Apache with out them. If may explain why XAMPP may work on a newer server but give DLL errors on an older one.

x86 is the hardware architecture and indicates that it is a 32 bit build.

Zend Extension Build and PHP Extension Build have their compiler options although in this case the only important part of this is the TS bit. I think that in some builds of PHP the TS may not exist or it might be NTS instead.

Next we have to download a new version of XDebug that will fit into our environment. So navigate to:

In the Releases section look for the version that has the compiler flags we need. We’ll start with the latest version (XDebug 2.2.3 at the time of writing). I’m using PHP version 5.4 compiled using VC9 with TS and for a 32 bit build. So I download PHP 5.4 VC9 TS (32 bit) (php_xdebug-2.2.3-5.4-vc9.dll).

There are 2 ways to install it.

  1. Rename php_xdebug-2.2.3-5.4-vc9.dll to php_xdebug.dll
  2. Stop Apache
  3. Copy php_xdebug.dll into E:\xampp\php\ext
  4. Start Apache

Windows being what it is with locking files means that you have to stop Apache before copying the DLL in to the correct place which will slightly increase the downtime. This might work better as a tested upgrade on a production system where you don’t want to touch the configuration files.

Alternatively you can:

  1. Copy php_xdebug-2.2.3-5.4-vc9.dll into the E:\xampp\php\ext directory
  2. Edit the zend_extension line in the php.ini to point to this version.

    zend_extension = “E:\xampp\php\ext\php_xdebug-2.2.3-5.4-vc9.dll”
    xdebug.remote_enable = 1

  3. Stop Apache
  4. Start Apache

Most people choose this option because it gives you a better infrastructure for testing different versions as well as an easy rollback or upgrade path in case anything goes wrong. It also reminds you which version of XDebug you are using. The DLLs stay in place and you are only changing the configuration files. As a result there is no gap between the Apache restart.

Finally navigate to your phpinfo() page and there should be a section for XDebug.

SD card is read-only on Mac

June 11th, 2013

I spent almost half a day trying to figure out why the SD card plugged into the side of my MacBook Pro suddenly became read-only.

After wading through an awful lot of Apple forums containing “are you sure you have the SD card read-only lock in the correct position” I discovered several aspects of this problem that will hopefully save other people from pulling their hair out.

  1. The problem happens more often than not on SDHC type cards.
  2. Mac has some out-of-specification code to write to SD cards which is not compatible with other card readers.
  3. There is a fault with the onboard card reading which falsely reports that the physical read-only lock is active.
  4. It matters how you insert the SD card into the SD reader’s slot.
  5. All problems can be solved by using an external card reader.

The problem I was suffering from was that of the false positives on the SD card reader’s read-only sensor. The device file for the onboard SD card reader was /dev/disk1 so I’ll use that in the work-around procedure that follows:

  1. Open a terminal window and type:

    $ ls -l /dev/disk1*
    br–r—– 1 mrn operator 14, 0 11 Jun 00:24 /dev/disk1

  2. Make sure the SD card’s physical switch is pressed down in the unlocked position. There should be a label on the card itself to remind you.
  3. Insert the card firmly applying the pressure directly along the line of insertion.
  4. Run the above line again to check the read-only status.
  5. If the device still reports as read-only, pull the card out and insert your fingernail in between the physical lock switch. The gap should remain when you remove your nail, then repeat the test.
  6. Increase the width by about a fingernail’s worth each time you run the test and eventually you will reach the sweet spot. The test will report:

    $ ls -l /dev/disk1*
    brw-rw—- 1 mrn operator 14, 0 11 Jun 00:24 /dev/disk1

It took me about 3 or 4 iterations to find the right point.

How can I stop a Facebook App filling up my wall and annoying my friends?

April 17th, 2013
  1. Go to Settings > Account Settings > Apps > Apps you use.
  2. Find the game, click Edit.
  3. Change Visibility of App to Only me.
  4. Also delete the This app can also post on your behalf bit.

Installing OpenMeeting with MySQL

March 14th, 2013

From Wikipedia OpenMeeting is:

OpenMeetings is software used for presenting, online training, web conferencing, collaborative whiteboard drawing and document editing, and user desktop sharing. The product is based on OpenLaszlo RIA framework and Red5 media server, which in turn are based on a bunch of open source components. Communication takes place in meeting rooms which are set to different communication, security and video quality modes. The recommended database for backend support is MySQL. The product can be set up as an installed server product, or used as a hosted product.

Today we will be installing OpenMeeting on CentOS 6.3 (64-bit).
Find a nice place to work:

mkdir /home/dev
cd /home/dev

Go to and download and unpack latest binary.

  1. wget

  2. mkdir openmeeting

  3. cd openmeeting

  4. tar -xzvf ../apache-openmeetings-incubating-2.0.0.r1361497-14-07-2012_1108.tar.gz

The default installation of OpenMeeting uses an integrated Apache Derby database to persist data at the back end. They recommend MySQL (or a real database) for production installations. I however, like to easily poke around the database and investigate how the product works. The trouble with an integrated database is that it won’t be available when the application is down and it may not be available to clients outside the application.

OpenMeeting requires UTF8 so we’ll install MySQL and configure the collation.

  1. Install PHP and MySQL with yum
  2. yum install php mysql-server mysql

  3. There are a few problems of setting the collation with MySQL so. Edit /etc/my.cnf and add the following lines to the mysqld section:

    collation-server = utf8_unicode_ci
    init-connect=’SET NAMES utf8′
    character-set-server = utf8

  4. Then restart MySQL with:

    /etc/init.d/mysqld restart

Now that we have MySQL installed, we’ll have to create a MySQL account for OpenMeeting to use.

  1. Login to MySQL:

    mysql -uroot

  2. Create the database:

    CREATE DATABASE openmeetings;

  3. Create a MySQL user for the application:

    CREATE USER openmeetings;

  4. Set permissions:

    GRANT ALL ON openmeetings.* TO openmeetings@localhost;

  5. Set password (change **** to your password):

    SET PASSWORD FOR openmeetings@localhost=PASSWORD(’****’);

  6. Log out of MySQL:


  7. Now we will just check that our new user is set up properly. (Where **** is the password)

    mysql -uopenmeetings -p**** openmeetings

OpenMeeting isn’t bundled with all the database connectors so we’ll have to download and install the MySQL connector in order to talk to the database.

  1. Start off in our dev area:

    cd /home/dev

  2. Go to and download the latest ConnectorJ (at the time of writing this was 5.1.24)
  3. Unpack it:

    tar -xvzf mysql-connector-java-5.1.24.tar.gz

  4. Move the connector to the correct place in the OpenMeeting directory structure so it can be found by the application:

    mv mysql-connector-java-5.1.24/mysql-connector-java-5.1.24-bin.jar openmeeting/webapps/openmeetings/WEB-INF/lib/

We are not using the default database type so we must change the configuration files so that the OpenMeeting installation process uses the MySQL configuration file instead of the integrated Derby configuration file.

  1. Go to the connectors folder:

    cd /home/dev/openmeeting/webapps/openmeetings/WEB-INF/classes/META-INF

  2. Use the MySQL configuration template:

    cp mysql_persistence.xml persistence.xml

  3. Edit persistence.xml and change the MySQL credentials. At the bottom of the file you will see

    , Url=jdbc:mysql://localhost:3306/openmeetings?autoReconnect….
    …. , MaxActive=100
    , MaxWait=10000
    , TestOnBorrow=true
    , poolPreparedStatements=true
    , Username=openmeetings
    , Password=****"/>

    Change the Username and Password to what you set earlier. If you want to change the database name localhost:3306/openmeetings? will become localhost:3306/my_database?.

Now we are going to set up Enabling Image Upload and import to whiteboard.

To install ImageMagick we’ll use the package manager:

yum install ImageMagick

Installing ImageMagick will install GhostScript as a dependency so we get part 1 of Enabling import of PDFs into whiteboard for free. Part 2 requires installing SWFTools which we will do now:

  1. Start in our development directory:

    cd /home/dev

  2. Go to and get the latest version:


  3. Unpack with:

    tar -xvzf swftools-0.9.2.tar.gz

  4. If this is a minimal version of CentOS (or you type gcc and get bad command) then you’ll need to install the C compiler and tools:

    yum install gcc* automake zlib-devel libjpeg-devel giflib-devel freetype-devel make

  5. Prepare to build the software:

    cd /home/dev/swftools-0.9.2

  6. Run the pre-build configuration script:


  7. Build SWFTools:


There is a bug in the make install step so we’ll just fix that before running it.

  1. Edit /home/dev/swftools-0.9.2/swfs/Makefile
  2. Search for the install: directive and change:

            rm -f $(pkgdatadir)/swfs/default_viewer.swf -o -L $(pkgdatadir)/swfs/default_viewer.swf
            $(LN_S) $(pkgdatadir)/swfs/simple_viewer.swf $(pkgdatadir)/swfs/default_viewer.swf
            rm -f $(pkgdatadir)/swfs/default_loader.swf -o -L $(pkgdatadir)/swfs/default_loader.swf
            $(LN_S) $(pkgdatadir)/swfs/tessel_loader.swf $(pkgdatadir)/swfs/default_loader.swf


    <TAB>rm -f $(pkgdatadir)/swfs/default_viewer.swf
    <TAB>$(LN_S) $(pkgdatadir)/swfs/simple_viewer.swf $(pkgdatadir)/swfs/default_viewer.swf
    <TAB>rm -f $(pkgdatadir)/swfs/default_loader.swf
    <TAB>$(LN_S) $(pkgdatadir)/swfs/tessel_loader.swf $(pkgdatadir)/swfs/default_loader.swf

    Make sure that the first and only character at the start of the replacement lines is a TAB and not a space.

  3. Now we can run:

    make install

Next we’ll install the dependencies for Enabling import of .doc, .docx, .ppt, .pptx, … all Office Documents into whitebaord. This also installs Oracle’s Java which is why we didn’t install it earlier.

  1. Install Libre Office:

    yum install libreoffice-writer

Enabling Recording and import of .avi, .flv, .mov and .mp4 into whiteboard requires FFMpeg which is not available via standard yum so we’ll add another repository that does contain it. Thanks to needlessly does a “yum update” which would probably update everything seeing as CentOS keep stable older version instead of the bleeding edge.

  1. Edit /etc/yum.repos.d/dag.repo
  2. Add:

    name=DAG RPM Repository

  3. Import keys so we can talk to the repository securely:

    rpm −−import

  4. Start installation:

    yum install ffmpeg

Enabling Recording and import of .avi, .flv, .mov and .mp4 into whiteboard also requires SOX but that is available on the standard yum so just install that.

yum install sox

I have read through the installation instructions for OpenMeeting and they are as clear as mud. Half the documents seem to say that JODConverter is needed and the other half say that it isn’t. Even the project page for JODConverter says that the project isn’t even maintained. It has some connection to OpenOffice/LibreOffice, so I’m installing it anyway just in case.

  1. Change back to our scratch folder:

    cd /home/dev

  2. Go to
  3. And download the latest version:


  4. Then unzip it


Well that’s it for the dependencies. Hopefully OpenMeeting will find all the things it needs during it installation.

After following the original instructions for installing OpenMeeting, the Oracle Java had been replaced by the GNU version of the Java runtime. When I started the OpenMeeting container it use that version instead of the Oracle implementation and didn’t work.
If you install the dependencies in the order that I described above then Oracle’s Java should come out on top. We need to check to make sure though:

  1. Get which version of Java are you running:

    java -version

  2. You should get:

    java version “1.7.0_13″
    Java™ SE Runtime Environment (build 1.7.0_13-b20)
    Java HotSpot™ 64-Bit Server VM (build 23.7-b01, mixed mode)

  3. If you don’t then you’ll have to uninstall the GNU version:

    yum remove gij
    rpm -e jre

  4. And reinstall Oracle’s Java over the top:

    1. Navigate to:
    2. And download the appropriate version I selected “Linux x64 RPM".
    3. Install via the Redhat Package Manager, you might see a couple of errors like “Error: Could not open input file” but you can ignore these.

      rpm -i jre-7u13-linux-x64.rpm

OpenMeeting uses a couple of ports to communicate with so make sure your firewall allows traffic on them. For development purposes the following will remove all firewall rules until you reboot.

iptables -F

To start OpenMeeting:

  1. Change directory:

    cd /home/dev/openmeeting

  2. Type:


It should print a lot of information on the screen. There will be pauses and gaps but when it starts repeating no Appointments in range you are ready for the next step.

You can check [crudely] that the database has been created in MySQL by ensuring that there are plenty of files in:

The final part of the installation is run from the web interface so navigate to:
where localhost is the machine you have installed OpenMeeting on.

Click the link Continue with STEP 1. This will take you to the initial configuration screen where you can set up the application:

In the Userdata section fill in the admin user

Username: admin
Password: admin

In the Configuration section I didn’t touch anything but the names seem pretty self explanatory if you know how to set up your mail system (which is beyond the scope of this document).

In the Converters section we need to add the paths to the support utilities as they won’t be available to the servlet container.

All the Converter support applications should be in your path except jodconverter-core. I still don’t understand if or how JODConverter is needed, so add a reference to the JOD path anyway.


I leave all the other stuff to their defaults.

Finally click INSTALL. The screen will spend a couple of minutes spewing out data, so let it get on with it. When it has finished your web browser will sent you to the “Installation Complete!” page.

Click Enter the Application and login with Username as admin and Password as admin.

The rest is up to you! Good luck.