Coming back to Linux

Five years ago I was using Ubuntu Linux at my job exclusively. After my new Macbook Pro arrived I have switched to OS X exclusively but I still had an old Windows 7 machine at home that was being used more or less as a NAS.

The time finally came to move from from proprietary OS to something free. As I am used to running Debian on the servers, the choice of Linux distribution was simple, Debian Wheezy.

Here are some of the things I had to do to make things work the way I wanted them to.

Graphics

Installation guide for ATI cards is available on Debians Wiki page. For making fonts look nicer check the section on font smoothing that is also available on Debians Wiki page on fonts.

Mounting Windows drives

Since I am still not sure if this switch is going to be a permanent decision I have decided to keep my storage drives on the NTFS file system. Because of this I was forced to enter the root users password every time I wanted to mount them, this was a no go since I wanted to share those drives via NFS to my Mede8er media player.

For this I had to install ntfs-config and ntfs-3g packages.

apt-get install ntfs-config ntfs-3g disk-manager

Running ntfs-config gives you an option to Enable write support for external and internal devices. After checking this options all the drives where available for reading and writing in the /media folder.

Exporting shares via NFS

Since my media player (Mede8er) supports NFS shares I opted to use it instead of Samba. The setup is simple once you get the export options right. To install NFS on the server

apt-get install nfs-kernel-server nfs-common portmap

Instead of portmap, rpcbind will be installed but that doesn’t matter.

Edit /etc/exports and add:

/media     10.29.10.0/255.255.255.0(rw,sync,root_squash)

Replace the IP address and netmask with the ones in your network.

Restart NFS with

/etc/init.d/nfs-kernel-server restart

Or if NFS is already running you can just run

exportfs -a

On the Mede8er, go to NFS, Add and enter the IP address of your host and “/media” as the folder.

OSX Time Machine backup

Since I still have two Apple machines, the idea is to use this Debian NAS as a Time Machine backup server so I do not have to rely on plugging in the USB hard drive. As far as I can see there are lots on guides on how to accomplish this. I will update this section once I get the time to implement this.

Using APC cache with Doctrine & Symfony? Check again!

If you have read the documentation you probably know that having a Metadata cache for Doctrine is something you really want to have in production.

The setup in Symfony is pretty easy, you just have to edit the config_prod.yml:

doctrine:
    orm:
        metadata_cache_driver: apc
        query_cache_driver: apc

The problem is that the Dependency Injection Container is generated through the Command Line Interface, and if you do not have apc.enable_cli=1 in your php.ini DIC will use FileCacheReader instead.

You can check your /app/cache/prod/appProdProjectContainer.php to see if you are using APC cache.

    protected function getDoctrine_Orm_DefaultEntityManagerService()
    {
        $a = $this->get('annotation_reader');
        $b = new \Doctrine\Common\Cache\ApcCache();
        $b->setNamespace('sf2orm_default_5cdc3404d84577b226d7772ca9818908');
        $c = new \Doctrine\Common\Cache\ApcCache();
        $c->setNamespace('sf2orm_default_5cdc3404d84577b226d7772ca9818908');
// ...
        $g = new \Doctrine\ORM\Configuration();
        $g->setMetadataCacheImpl($b);
        $g->setQueryCacheImpl($c);
// ...
    }

If you can not find \Doctrine\Common\Cache\ApcCache you are not using APC to cache your metadata.

For a simple page with one query the difference between APC and File based caching can be quite big. Take a look at the numbers I got from XHProf for a simple page:

Cache type Wall time CPU time Memory usage
APC 254,972 µs 242,020 µs 10,352,536 bytes
File 355,617 µs 325,320 µs 11,579,568 bytes
Difference 39.47 % 34.42 % 11.85 %

Free eBook on configuring a mail server with Postfix

Today I finally managed to release a first public version of a book I have been working on for a while.

If you ever wanted to build a mail server but all the tutorials and howtos on the internet where too vague or old, this is a book for you.  It will guide you through the setup of a complete email server on a latest Debian 6.0 (Squeeze) distribution. I tried to go beyond just listing steps needed to get a working email server online. Hopefully this book explains a little bit more about the why and not just how.

As everything else in life, this book is a work in progress and I would really appreciate all the feedback I could get. Both positive and negative. I have tried to give credit, where credit is due, but there is always a chance I missed to attribute somebody for the work they did. Don’t hesitate to point that out.

The book was written in Docbook 5.0 format and when my free time allows it I will try to explain a little bit more about the whole process because finding tried and tested information about myriad of choices and tools in the Docbook publishing chain proved to be a not so easy task.

I hope you will enjoy reading Building a mail server on Debian 6.0.

The Rename refactoring cannot be applied in this context

I have been using NetBeans for a couple of months now, and I must admit that except for a quirk here and there the overall experience of switching from Zend Studio was a pleasant one.

Since switching to 6.9 I had some trouble using the integrated Refactoring utility. There error I got was: The Rename refactoring cannot be applied in this context.

The solution is a simple one, use the built in shortcut “Ctrl + R” (or “Cmd + R” on a Mac).

The other thing that bothered me is that when you select a method or class and use the context menu to navigate to the declaration of the method/class Netbeans doesn’t do a thing. To make this work the method/class name must not be selected (or you can use the + click shortcut).

Blank page after a quick reply (vBulletin)

While launching the Google Adsense on Gameplay and its forum (vBulletin 3.8) we ran into a strange issue while posting quick reply messages to the forum with Firefox. After hitting submit the page turned blank although the comment was apparently posted.

We have integrated our Adsense code into the postbit vBulletin template after the last post on the page using this syntax:

<if condition="$post['islastshown']">
     Adsense code here.
</if>

The problem happend because Quick Reply uses asynchronous javascript to submit the reply and render the new reply at the and of the page. Since we are embedding the Adsense code if the post is “last shown” this renderd the Google Adsense code twice and FF “broke”.

The fix is quite simple, you just have to check if the post is being sent as a response to the asynchronous request, so the new and working code looks like this:

<if condition="$post['islastshown'] AND !$GLOBALS['vbulletin']->GPC['ajax']">
    Adsense code here.
</if>

Of course this is not the only case which causes vBulletin forum to render a blank page. For a list of other possible reasons take a look at this chapter in the  official documentation.

If you are interested you can also take a look at this exhaustive list of conditionals which you can use in your vBulletin templates.

Set filenames with Nginx secure download module

When we switched from Lighttpd to Nginx a couple of months ago we were faced with an annoying problem.

Paying subscribers to our site have an option of downloading PDF files of the magazine. With Lighttpd we were using mod_secdownload to provide this functionality without exposing the files to the public. We compiled Nginx with the secure_download_module and it kinda worked.

Files were downloading as expected but the file names where all messed up. Download links where generated for each user and they looked something like this: /pdf/645.pdf/097ac16cb19ff6c163d6f813fdd44b4d/4b283bfa and the browser saved the file to the users hard drive with the file name of 4b283bfa. Since the file name didn’t have an extension it was impossible for the OS to know that is has to use a PDF reader to open the file.

Finally we managed to force the file name to the browser (download client) with a configuration directive that looks something like this:

# PDF download
 location /pdf {
    secure_download on;
    secure_download_secret $request_addr;
    secure_download_path_mode file;
    root /path/to/dir/with/pdfs

    # Extract the name of the PDF
    if ($uri ~ "^/pdf/(.+\.pdf)$") {
        set $filename $1;
    }

    # Set appropriate headers
    add_header Content-Disposition "attachment; filename=$filename";
 }

And that’s all there is to it.

UTF-8 encoding and the TinyMCE SpellCheck plugin

If you have tried using the the TinyMCE spell check plugin on UTF-8 encoded page with the PSpellShell adapter you probably noticed that the implementation is broken. The spelling suggestions do not contain properly encoded UTF-8 characters.

Since the creators of TinyMCE moved to Github it was a great opportunity to try and push these changes to the master branch. If you need this you can look at the changes that need to be made to the PSpellShell adapter or just clone my fork of the spellcheck plugin.

p.s. Have I mentioned how awesome Git and Github are?

Give your .02$ to the ZF project

Zend Framework project is about to start working on the 2.0 version. If you are using ZF in your projects, but you are not interested in contributing ideas to the project by joining the zf-contributors mailing list, the least you could do is provide feedback about your ZF experience by answering a survey.

You can find more info at the devzone.

Google confused with 301 redirects

It has been almost I year since we launched nacional.hr. During the migration from the old content management we thoroughly went through the whole system and made sure that all the old URIs are still working. Although cool URIs don’t change sometimes you have no choice and that was the case with this site. We had to enhance some of the URIs for SEO purpose and some of them were just clashing with our URI scheme it we did not want to maintain a large list of legacy URIs in our rewrite rules.

We hooked a legacy URI “plugin” in our error controller so that checking for old URIs does not interfere with the loading times of our system unless really necessary and created 301 (permanent) redirects to our new URI scheme patted ourselves on the back an forgot all about it until recently.

While checking the access logs for some unusual traffic spikes we where getting we noticed that Google stills checks our old category URIs and follows the redirects that we have created. The most unusual things was that the URIs where checked very often. Links to our news category pages where crawled by Google a couple of times a minute during the course of couple of days. To add to the confusion the categories that are most often crawled our the ones that list articles from our print issue which get updated once a week, the ones that are updated many times a day get crawled at a regular pace.

Any ideas what could cause something like this?

Hudson and PHP Howto

After a couple of weeks of playing with phpUnderControl and reading some nice reviews of Hudson I decided to give Hudson a try. And boy am I glad I did.

Hudson definitively won me over with its clean interface and easy to setup tasks. Even plugin installation is a breeze and you can even do it right out of the comfort of your browser.

I found a nice tutorial about setting up Hudson with PHP here but I had some question marks hovering over my head during the installation so I have decided to write a more detailed installation tutorial.

If you are running a Debian flavored distribution (yes I mean Ubuntu) take a look at the tutorial, you should have Hudson working with your PHP projects in no time.

Bonus points if you integrate your Hudson installation to act as your staging server.

Install phpUnit on Mac OSX 10.6

Here is another quick How-to so I don’t have to look it up next time.

Open up Terminal.app and enter “sudo su” and enter your password when asked (I guess you must be using an account with administrator privileges).

pear upgrade PEAR
pear channel-discover pear.phpunit.de
pear install --alldeps phpunit/PHPUnit

That’s it. phpunit binary should be in your path now.

p.s.

For some reason phpUnit that is being used by Zend Studios (6.1) does not have mbstring extension compiled and that makes it unusable for me. I guess there is a way to force PHP interpreter that is being used in the Zend Studio to run with the mbstring extension, but this is a faster approach. Hudson or phpUnderControl (whichever you like) will take care of the code coverage reports.

Munin on Debian Lenny – Howto

I have been playing with an excellent monitoring tool Munin. Since I had some glitches while trying to install it on my server a have decided to update my Wiki a little bit and add a tutorial about setting up Munin on Debian Lenny. It is quite late and I do not feel like proofreading this entry right now so you will have to forgive me if I forgot something.

Fix the Tab key on your Mac

One of the things that bugged me the most after switching to Mac on my job was an inability to use the Tab key to move across all of the elements in a form. Using the Tab key after a fresh install of your Mac will move you over the text input fields only.

Since a have reinstalled my computer with a fresh copy of Snow Leopard couple of weeks ago I found myself browsing through the System preferences looking for the same option again.

So, as a future reminder for myself you have to press the Ctrl + F7, or open up System Preferences -> Keyboard -> Keyboard Shortcuts and select “All controls” in the bottom of your screen.

Continue reading

From DocBook to PDF using Apache FOP

Creating user manuals for the software you are building is an important task. Sometimes it is a project requirement but more often than that it is just more efficient having a document to which you can refer users to and stop waisting you precious time explaining the fundamentals of content management systems to novice users instead of actually doing what you are payed for.

Since I do not like to repeat myself I wanted a system that is capable of generating documentation in variety of formats, PDF being the most important one.

DocBook is the first thing that came to mind, but as it is usually the case the things are not so simple as they should be. After playing fore the most part of the day with DocBook and various utilities I decided to write it down for future reference. Continue reading

Adding filters automatically to your Zend_Form_Element_Text objects

Although you can create a custom form element as described in ZF manual and set the properties for all instances of this element I really did not like this solution since my application already has a lot of already working forms.

I wanted to add the Zend_Filter_StringTrim filter to all of my text form elements so I decided to just add them on the fly.

Since my forms already extend a custom “MyApp_Form” object (MyApp_Form extend Zend_Form) it was just a matter of intercepting the addElement() method.

So, here it goes, in all its glory:

public function addElement($element, $name = null, $options = null)
{
    parent::addElement($element, $name, $options);

    if (is_null($name)) {
        $name = $element->getName();
    }

    $addedElement = $this->getElement($name);

    if ($addedElement instanceof Zend_Form_Element_Text) {
        if ( ! $addedElement->getFilter('StringTrim') instanceof Zend_Filter_Interface ) {
            $addedElement->addFilter(new Zend_Filter_StringTrim());
        }
    }
}

Since the element is already added to the form using the parent method I didn’t have to check if the element is passed as a string, but does not have a name, or if it’s passed as a Zend_Form_Element object without the name property since the Zend_Form::addElement() already checks for this.