Swiftmailer $record Hash Format

Swiftmailer is cool. It’s a really useful PHP library to make sending email messages really simple. The problem is that it lacks documentation, or the documentation is out there some where, but I can’t find it.

One issue that I kept running into was, what’s the structure of the $record hash that the handler’s write() method uses?

Here it is.

Array
(
    [message] => [rqswqiurqzz8fzziu8f] Request took 1 seconds
    [context] => Array
        (
        )

    [level] => 200
    [level_name] => INFO
    [channel] => blurp-service
    [datetime] => DateTime Object
        (
            [date] => 2016-03-31 15:17:38.505357
            [timezone_type] => 3
            [timezone] => America/New_York
        )

    [extra] => Array
        (
        )

    [formatted] => [2016-03-31 15:17:38] blurp-service.INFO: [rqswqiurqzz8fzziu8f] Request took 1 seconds

)

SOAP Request Generates 500 with Nothing in the Apache or PHP Log

ELISHA CUTHBERT

ELISHA CUTHBERT

I ran into an odd error to track down. I’ll start off with the fact that I’m not a Soap expert, so this is probably obvious to someone who’s worked with Soap more than myself, but regardless, here’s what happened.

I’m setting a new Soap web service, but for some reason I kept getting a 500 http error every time I sent a request through. It was working before, then it stopped working. There was nothing in the error logs indicating what is causing the error.

127.0.0.1 - - [29/Feb/2016:09:58:05 -0500] "POST /SoapServer/index.php HTTP/1.1" 500 572 "-" "-"

I figured it was something to do with the XML being invalid, so I tried a different XML and it worked. Hmmm, what’s the difference between the two? It was a namespace issue.

In my WSDL, the targetNamespace was set to something like this http://www.example.com/Soap/Server/

But in the XML that was failing, the namespace was set to

xmlns:ns3="http://www.example.com/SomethingDifferent/"

That namespace ns3 referred to the actual Soap request portion of the XML document and it needs to match the targetNamespace. Once I synched those two up, I was back in business.

Soap is cool, but it can be a real pain in the arse to troubleshoot. There should be, and possibly there is a way to flip some switches on PHP’s SoapServer to log errors for this sort of issue.

The above photos are of Elisha Cuthbert. Cuthbert is a Canadian actress. Born in 1982, Cuthbert played Kim Bauer alongside Keifer Sutherland in the TV series “24.” I thought she was pretty funny in the TV show “Happy Endings.” I was bummed when ABC canceled it after just three seasons. Cuthbert apparently only dated NHL hockey players and is married to Dion Phaneuf – a defenceman for the Ottawa Senators.

How to Customize PHP Monolog

Big Lebowski Only a fool writes their own PHP logger. Smart PHP programmers use Monolog. Here’s how you can customize Monolog using inheritance.

My problem was that I wanted to programmatically control what gets in the logs. So if I’m in development, I want to see all of the logging down to DEBUG level. But when I’m in production, I only want to see anything at a log level of INFO or greater.

For reference, Monolog supports the following log levels.

DEBUG (100): Detailed debug information.
INFO (200): Interesting events. Examples: User logs in, SQL logs.
NOTICE (250): Normal but significant events.
WARNING (300): Exceptional occurrences that are not errors. Examples: Use of deprecated APIs, poor use of an API, undesirable things that are not necessarily wrong.
ERROR (400): Runtime errors that do not require immediate action but should typically be logged and monitored.
CRITICAL (500): Critical conditions. Example: Application component unavailable, unexpected exception.
ALERT (550): Action must be taken immediately. Example: Entire website down, database unavailable, etc. This should trigger the SMS alerts and wake you up.
EMERGENCY (600): Emergency: system is unusable.

To do that I extended Monolog’s StreamHandler like this. I chose StreamHandler because it can handle writing to a log file. There are many handlers that you can leverage to meet your needs.

class DurpLoggerHandler extends StreamHandler {
    public function __construct() {
        parent::__construct(Configuration::logFile(), Configuration::logLevel());
        $formatter = new LineFormatter(NULL, NULL, FALSE, TRUE);
        $this->setFormatter($formatter);
    }

    protected function write(array $record) {
        if (!($this->getLevel() >= Configuration::logLevel())) {
            return;
        }
        parent::write($record);
    }
}

The important part is overriding the write() method. If the log level is greater than or equal to the level I’m setting in my Configuration class.

The Configuration class could look like this, although mine is slightly more complicated because I’m pulling values from a configuration file rather than setting them in the Configuration source with Logger::DEBUG (I don’t like to have to modify any source code on production).

use Monolog\Logger;

class Configuration {
    const LOG_LEVEL = Logger::DEBUG; 
    const LOG_FILE = '../logs/application.log';

    public static function loglevel() {
        return self::LOG_LEVEL;
    }

    public static function logFile() {
        return self::LOG_FILE;
    }
}

And the to use this custom Monolog logger, I do this in my application.

$this->logger = new DurpLogger('durp-service');
$this->logger->pushHandler(new DurpLoggerHandler());
$this->logger->addDebug('Durp Service Started');
$this->logger->addInfo("That's like your opinion, man.");

That’s it. Now if I change my Configuration::LOG_LEVEL to something greater than DEBUG, like say INFO, I won’t see “Durp Service Started,” but I’ll still get “That’s like your opinion, man.” The dude abides.

If you’re curious about that LineFormatter stuff, That’s just me tweaking the LineFormatting to not include a couple of trailing brackets [] [] that are automatically included with each Monolog log entry. They have a purpose, but I don’t need them.

(h/t) Seldaek answer on Stack Overflow about the Line Formatter (h/t) chalasr Stack Overflow member helped me think through some of this logic here

Security Upgrade Breaks Composer

Screen Shot 2016-02-22 at 9.52.58 AM While setting up a fresh Symfony installation, I discovered my composer was broken.

When I ran this.

composer update

I got this.

The "https://packagist.org/packages.json" file could not be downloaded: SSL operation failed with code 1. OpenSSL Error messages:
error:14090086:SSL routines:SSL3_GET_SERVER_CERTIFICATE:certificate verify failed
Failed to enable crypto
failed to open stream: operation failed
https://packagist.org could not be fully loaded, package information was loaded from the local cache and may be out of date

I’m running the development version of composer, so I ran this to see if a self update would help.

composer self-update

But I got this instead.

[Composer\Downloader\TransportException]
  The "https://getcomposer.org/version" file could not be downloaded: SSL operation failed with code 1. OpenSSL Error messages:
  error:14090086:SSL routines:SSL3_GET_SERVER_CERTIFICATE:certificate verify failed
  Failed to enable crypto
  failed to open stream: operation failed

I’ve been messing around with my LAMP stack, so I don’t know if I introduced this issue or if something recently changed with packagist or composer, but here’s the fix.

Run this.

wget http://curl.haxx.se/ca/cacert.pem

Then run this.

curl -sS https://getcomposer.org/installer | php -- --cafile=cacert.pem

I store my composer.phar /usr/local/bin so I moved it there.

Now it works again.

For some background, on March 10, 2014, composerista member Seldaek (Jordi Boggiano) said this, “The core issue is just that yesterday I merged his PR to do properly verified SSL (as opposed to stock PHP SSL which really only checks SSL is in use but doesn’t check the certificate matches anything).”

Symfony Rebuild bootstrap.php.cache

Screen Shot 2015-11-28 at 2.42.04 PM
If you feel the urge to rebuild your bootstrap.php.cache located in your app directory, run this from the command-line.

php ./vendor/sensio/distribution-bundle/Sensio/Bundle/DistributionBundle/Resources/bin/build_bootstrap.php

I’ve not actually found rebuilding the cache to be particularly useful. I just needed to it once because I thought it was causing me problems, it wasn’t.

How to Setup a LAMP Stack Using VirtualBox on a Mac

Before I get started, none of what you are about read is necessary if you can setup a bridged network with VirtualBox. The reason I had to do all of this is because I’m on a Macbook Air connecting to the network wirelessly. For some reason, bridged networking with VirtualBox on a Mac using wireless Internet connectivity doesn’t always work. Sometimes it does. Sometimes it doesn’t. So this is what I did.

I got tired of managing my web development stack on my Mac. It especially became a problem with El Capitan. Until El Capitan, I was reasonably happy using MAMP, but then El Capitan came out and dicked up a bunch of stuff with Open SSL. MAMP runs and old version of Open SSL and now Apple has it’s own implementation. Anyway, it became a headache to keep messing with running Apache, MySQL and PHP on my Mac – again.

So instead of cobbling together another solution, I was thinking about using brew, I decided to say, “Screw this, I’m must going to run Linux in a VM and be done with it.”

So I setup Ubuntu in VirtualBox and set out to solve how to integrate that LAMP stack into my Eclipse development environment on my Mac.

Here are just some notes I made that might help someone else, or myself when I have to do this again.

Connecting to the VM
Since bridged networking didn’t work for me, I had to use VirtualBox port forwarding to access the Ubuntu VM. I mapped 9999 to 80 for Apache. I mapped 9906 to 3306 for MySQL. I mapped 2222 to 22 for SSH.

For MySQL, you have to allow TCP connections, disabled by default. To do that enter a bind-address in your /etc/mysql/my.cnf on the Ubuntu VM. It should be 10.0.2.15, the VM’s private IP address.

Using VPN
If you have to access resources on a VPN from the VM, just connect with the host VPN client and VirtualBox’s NAT will take care of it. You can configure the VM to make a VPN connection as well, but I’ve found that to be unnecessary.

Symfony Suppress Header Output

Zooey Deschanel

Zooey Deschanel


Here’s how to suppress the header out in a Symfony controller.

I was busting out a simple controller to handle the csv download of a log file and I kept getting this in the output.

HTTP/1.0 200 OK 
Cache-Control: no-cache 
Date: Mon, 01 Feb 2016 21:39:07 GMT

The problem was that I was calling render to load my Twig template.

$response = new Response();
$log = unserialize(file_get_contents(__DIR__ . '/../Resources/logs/example.log'));
$response->setContent($this->render(
            'MyBundle:Order:log.csv.twig',
            array(
                'log' => $log,
            )));
$response->headers->set('Content-type', 'text/csv');
$response->headers->set('Content-Disposition', 'attachment; filename=example.log.csv');
return $response;

To fix this, all I needed to was call renderView instead.

$response = new Response();
$log = unserialize(file_get_contents(__DIR__ . '/../Resources/logs/example.log'));
$response->setContent($this->renderView(
            'MyBundle:Order:log.csv.twig',
            array(
                'log' => $log,
            )));
$response->headers->set('Content-type', 'text/csv');
$response->headers->set('Content-Disposition', 'attachment; filename=example.log.csv');
return $response;

How We Define Success

Screen Shot 2016-01-25 at 9.30.05 AMCurrently, Twitter, as a company, is in upheaval. Executives are getting fired. Workers are getting laid off. There’s widespread panic that Twitter will fail as a company as shareholders grow skittish about the company’s future. Twitter’s stock as fallen more than 50 percent in the last 12 months.

What’s got everyone so twisted up about Twitter is that its user base isn’t growing fast enough.

“The social networking service, used by presidential candidates such as Donald J. Trump and sports stars like the basketball player Stephen Curry, has failed to attract droves of new users,” according to the New York Times. “That has investors questioning how useful the service is for people and whether it will become a mainstream hit on the scale of Facebook or Instagram. Shares of Twitter have plunged nearly 55 percent in the last year.”

Every day 320 million users tweet. The social networking platform gets 1 billion unique visitors every month. Yet, that’s not enough. As a publicly traded company, shareholders want to see growth. Grow. Grow. Or. Die.

But why can’t Twitter just be happy to maintain its 1 billion unique visits a month and it’s 320 million active daily users?

Wall Street demands growth, but if Twitter were a privately held company, could they just be satisfied with what they’ve got and just do a good job servicing their user base? I’ve worked at pre-IPO companies and have had this very conversation. Everyone always goes for the stock options and cash from the public offering, but most of them live to regret it. You lose control of your company when you go public. It can make a lot of sense for a lot of companies, but private ownership can be a really wonderful thing, especially if you want to be in the news business, which Twitter does want to be in very much.

As a media company, you can’t expect 20 percent growth and 20 percent profit every year. It’s just not how the industry works.

Rakudo Star Breathes New Life into the Perl Corpse with Perl 6 Implementation

Larry Wall Perl

Larry Wall Perl


It took 15 years, but there’s finally a usable Perl 6 implementation released in December by Rakudo Star.

I don’t know anyone who is still using Perl, but apparently some people are out there blessing objects in 2016.

I used to be way into Perl and wrote Perl professionally for several years, but then it became largely irrelevant as other languages do the same thing better, more elegantly and don’t have the Christian orthodoxy embedded in the language.

There will never be an official Perl 6 implementation, as long as an implementation passes the test suite it’s kosher.