Using TCPDF with Symfony 2

Using TCPDF with Symfony2 is pretty simple. However there are a few problems that may arise.

namespace Acme\DemoBundle\Controller;

class PdfController extends Controller
{
    public function pdfAction()
    {
        $pdf = new \TCPDF();

        // Construct the PDF.

        $pdf->Output('filename.pdf');
    }
}

Easy enough. The PDF loads, but we get this error in the logs:

request.CRITICAL: Uncaught PHP Exception LogicException: "The controller must return a response (null given). Did you forget to add a return statement somewhere in your controller?"

We can fix that:

namespace Acme\DemoBundle\Controller;

use Symfony\Component\HttpFoundation\Response;

class PdfController extends Controller
{
    public function pdfAction()
    {
        $pdf = new \TCPDF();

        // Construct the PDF.

        $pdf->Output('filename.pdf');

        return new Response(); // To make the controller happy.
    }
}

Add some authentication and remember me tokens, close the browser, relaunch the browser, and visit the PDF page. We get a new error:

request.CRITICAL: Uncaught PHP Exception RuntimeException: "Failed to start the session because headers have already been sent by "[...]/vendor/tecnick.com/tcpdf/include/tcpdf_static.php"

Darn. TCPDF::Output() sends headers before Symfony has the chance. We can fix that too:

namespace Acme\DemoBundle\Controller;

use Symfony\Component\HttpFoundation\StreamedResponse;

class PdfController extends Controller
{
    public function pdfAction()
    {
        $pdf = new \TCPDF();

        // Construct the PDF.

        return new StreamedResponse(function () use ($pdf) {
            $pdf->Output('filename.pdf');
        });
    }
}

Perfect. Now Symfony and TCPDF::Output() can both send their headers, and everything plays nice.

OpenVZ Ubuntu 12.04 Upgrade to 14.04 Logging Problems

I recently ran do-release-upgrade on an OpenVZ VPS running Ubuntu 12.04. The process was surprisingly smooth, and I ended up with a functional install of Ubuntu 14.04. However, after a couple days, I realized that nothing was getting logged (auth.log, mail.log, syslog, etc.). Nginx logs continued working just fine. Upon further review of what was installed, upgraded, and removed, I realized that sysklogd was uninstalled, but nothing was installed to replace it. I ran:

aptitude install rsyslog

and now everything appears to be logging as expected.

I’m not sure if this was a problem because of Ubuntu, OpenVZ, or my hosting company. Regardless, it’s fixed now.

Symfony 2: Using @ParamConverter with multiple Doctrine entities

Symfony 2 describes how to use parameter converters to translate slugs to entities, but their example does not enforce the relationship between the two entities. Here’s their example:

/**
 * @Route("/blog/{date}/{slug}/comments/{comment_slug}")
 * @ParamConverter("post", options={"mapping": {"date": "date", "slug": "slug"}})
 * @ParamConverter("comment", options={"mapping": {"comment_slug": "slug"}})
 */
public function showAction(Post $post, Comment $comment)
{
}

Assuming that Post has id and slug attributes and that Comment has id, post, and slug attributes, the above example does not require that the Post slug in the URL match the Comment’s Post. Here’s an example that requires that the Post and Comment are related:

/**
 * @Route("/blog/{post_date}/{post_slug}/comments/{slug}")
 * @ParamConverter("post", options={"mapping": {"post_date": "date", "post_slug": "slug"}})
 */
public function showAction(Post $post, Comment $comment)
{
}

This example works because Post is processed first and because $post is named the same as the Comment::$post relationship. When it comes time to process the Comment, it attempts to use slug and post to find the Comment instead of just slug. (No @ParamConverter annotation is necessary for the Comment because the parameters are named the same as the attributes.) If $post doesn’t match $comment->post, a 404 is returned, no additional checks required.

Vim: Indext PHP case and default statements in a switch block

By default, Vim does not indent case and default statements inside of a switch block in a PHP file:

switch ($foo) {
case 'bar':
    // do something
    break;
}

It turns out a single line in one’s vimrc can fix that:

let g:PHP_vintage_case_default_indent = 1

Now indenting is correct:

switch ($foo) {
    case 'bar':
        // do something
        break;
}

USB Flash Drive for a 2012 Honda Civic

I recently purchased a PNY Attaché USB Flash Drive to plug into our 2012 Honda Civic. I was rather disappointed when I discovered that the drive was “unsupported” by the vehicle. It also appears that I am not the only one to have this problem. I returned the drive and purchased a SanDisk Cruzer Glide USB Flash Drive instead. The Honda Civic recognized it immediately and began playing the loaded music.

It’s worth noting that the Honda Civic only appears to show folders that contain music. Therefore, Artist > Album > Song will be displayed as Album > Song.

Fix a Seized Up Computer Fan

I’ve had some noisy and stuck 120mm computer fans in both my desktop and my server. I initially planned on replacing them but realized that all they really needed was some oil. The process is pretty simple and well outlined by TechRepublic. I removed the label and the small plug, put a drop of (sewing) machine oil on the shaft, gave it a spin, and reassembed. It’s nice to have some quiet in the home office again.

Dell Latitute D620 Laptop and NVIDIA Drivers for Ubuntu

After a recent update to Ubuntu 12.04, my Dell Latitude D620 Laptop quit mirroring the display across the laptop screen and the television connected to the dock’s S-Video port. I had previously chosen not to upgrade to Ubuntu 12.10 because of this issue, and 12.04 had worked correctly until today. It seems that the driver installed quit supporting some of the options I needed:

[email protected]:~# nvidia-xconfig --twinview
nvidia-xconfig: unrecognized option: "--twinview"

Invalid commandline, please run `nvidia-xconfig --help` for usage information.

It appears that installing an older version of the NVIDIA drivers:

aptitude install nvidia-173

and removing the current version of the drivers:

aptitude purge nvidia-current

solves the problem. Hopefully this will work for future versions of Ubuntu as well.

Upstart Job to Send Email During Boot

Since Ubuntu makes use of Upstart, I decided to take some time to figure out how to write a job to send a notification email every time one of my servers reboots. The Upstart job is below and is stored in /etc/init/boot-notify.conf.

# boot-notify - sends an email notification upon boot

description "sends an email notification upon boot"

start on started rc-sysinit

task
exec echo "$( hostname -f ) booted on $( date )" | mail -s "$( hostname -f ) booted" root

Here’s a brief explanation: The line start on started rc-sysinit says this job can’t run until after rc-sysinit has completed. I use Postfix, which still uses the init daemon. Therefore, it was easiest to send an email after the init daemon gets done running its jobs including starting Postfix. The task line simply says this is a short running process that doesn’t continue running the way a service would. The last line is the command to run identified by exec.

Barracuda Email Security Service Review

I used the Barracuda Email Security Service for the majority of the month of October 2012 to filter spam for our secondary domain name. During that period of time, we received almost 11,600 emails. Roughly 2,000 were allowed through; 8,600 were blocked, and 1,000 were quarantined. Of the 2,000 allowed, I estimate 600 of them were actually spam.

Technical Support

All calls to Barracuda technical support are routed through receptionists that only take your information and create tickets. I first called one morning and didn’t get a call back until 5:30 pm that evening after I had left for the day. When I called in the next morning to speak with a technician, I was put back in the queue and did not receiving a call until the following morning. The total time to begin addressing my issue was close to 48 hours.

Spam Filtering

I regularly reviewed the last block of 50 emails that Barracuda allowed to pass through. Of those 50, typically 15 (30%) were missed spam. (The number of missed spam ranged from 7 to 27 out of the 50.) Many of the subjects of the messages allowed through contained words that were obviously spam (think improving oneself in bed). Even after ratcheting up all of the custom scoring settings, too many messages were still getting through. To their credit, I was not able to find any false positives. All messages marked as spam were definitely spam.

The Barracuda ESS does provide a mechanism to mark messages as spam. However, it provides no useful feedback to indicate that the message is now spam. Therefore, you could easily mark the same message as spam 3 or 4 times if you
reviewed the same block of emails more than once.

Setting up custom policies to filter messages was rather limited. My only options were to enter keywords and then specify if messages matching those criteria should be allowed, blocked, or quarantined. I would have expected some fuzzy logic to handle a phrase like “orders of magnitude,” which could refer to effect of the male enhancement pills or just how off the sales projections were.

Virus Filtering

It is unclear what kind of virus scanning the Barracuda ESS is performing as it allowed through at least two zip archives containing suspicious executable applications masquerading as DHL shipment invoices.

LDAP Synchronization

LDAP integration from our Active Directory domain to the Barracuda ESS worked reasonably well. I created a non-privileged user on our domain for Barracuda to use, opened a hole in our firewall, and specified the base DN for synchronization. Unfortunately, there was no way to filter our AD contacts that did not have SAV email addresses. The Barracuda ESS also pulled in all email addresses including our internal domain savtrans.local which is not actually used for email. A simple filter could have easily prevented loading of this bogus information.

If I had chosen not to use LDAP synchronization with the Barracuda Email Security Service, all of my users would have need to verify their accounts and all corresponding email addresses one by one. I believe an administrator should have the ability to load aliases without having to manually verify each one.

Summary

While the Barracuda Email Security Service is priced below the competition, I believe the competition offers a superior product. Their major outage on October 22, 2012 brought out a lot of complaints about the service in their forum. I do believe they have now stepped up their game, especially in the communication department, but I still can’t recommend them as a service that does a good job of filtering spam.

Peplink Balance 380 Review

Last year, we purchased a pair of Peplink Balance 380s for our office. Their ability to load balance across multiple Internet connections including using a cellular USB dongle as a backup connection was very attractive. I received the pair of devices and without too much difficulty got them connected and routing traffic in and out of the blocks of IP addresses we have with two Internet service providers.

I tested the load balancing/failover by pulling the plug of one of our Internet connections. The Peplink router quickly moved all traffic to the remaining connection. Over the last year, none of our employees have ever even noticed when one of our connections has gone down.

Several months ago, I tested the reason we purchased a pair of them. Once configured in high availability mode, the secondary router is supposed to take over for the primary upon failure. I simulated this by pulling the plug on the primary while pinging the virtual gateway IP address and an IP address outside of our network. The results were impressive:

  • 7 seconds total for the secondary router to re-establish internal connectivity.
  • 13 seconds total for the secondary router to re-establish Internet connectivity.

The primary router was configured to re-establish its primary role upon rebooting. I plugged it back in, and the results were similarly impressive:

  • 2 seconds for the primary router to re-establish internal connectivity.
  • 8 seconds for the primary router to re-establish Internet connectivity.

While purchasing two of these routers cost quite a bit more than just purchasing one, the pair allows us to sleep soundly at night knowing that if one fails, our Internet connectivity will remain intact and business can continue normally while we replace the faulty router.