Working with navbar and ember

screenshot of drupal navbar and ember

On two sites, including this one, I have switched from Admin Menu combined with Adminimal ThemeAdmin Menu to Navbar and Ember. The reasons for this should be pretty obvious:

  1. Once I start using 7 and 8 sites simultaneously, having a very similar UI reduces mental load since I do not have to keep two ways of interacting in mind.
  2. I can evaluate how robust and power-user friendly Navbar actually is and if it is likely to need a lot of tweaks such as Admin menu was needed for Drupal 7 to work efficently.

First impressions

Both modules are still rather beta and have their minor issues but overall it's a decent look-and-feel with what's possible in D7. The most annoying thing is not being able to create a node directly from the main menu, I have now actually started using shortcuts for this (which I previously just deactivated entirely). So, as expected, it is a bit slower since the menu obviously relies on clicks but for me the responsive layout is already enough justification to relearn one or two muscle memories.

To use Devel you'll also need the sandbox Navbar Devel plus my patch for it makes it look decent. Environment Indicator also works right away with Navbar, so the only thing really missing from admin_menu is the fast user switching and command search but since I hardly use those, I don't have any major impediments currently.

I'm hoping some things like the floating settings block on the right might make it into Ember in the future but for now I have a good working alternative.

If you are in any way interested in Drupal 8 and are also maintaing any Drupal 7 sites, I highly recommend you check out "Drupal 8 Has All the Hotness, but So Can Drupal 7" as well as "Future-Proof your Drupal 7 site" for more ways to prepare for the future.

Getting Drupal's mail out of the spam folder

When your Drupal CMS sends emails, for example to deliver module update mails, password resets and so on, and they just won't arrive as you'd like them to, you can safe yourself a lot of time by checking these items first. Gmail will give you hints where to look but it's often unclear if you are actually on the right track.

#1 Is the email getting delivered?

Check the mail log of your server, typically /var/log/mail.log or /var/log/mail/something. This should tell you whether the mail gets delivered. If it doesn't google the error message pertaining to your MTA and go from there.

If that email never arrives, not even in your spam folder, consider using another email account from a different provider to get a copy to start debugging or reduce -all to ~all in your SPF records to get a processed copy, though if you had that set, you will have to wait for the TTL set in your DNS record to time out.

#2 Did you look at the email?

The headers of the email often contain sufficient information to diagnose the problem. Had I done this more thoroughly, I would have found the culprit in no time. For example, there was this:
Received-SPF: none ( does not designate permitted sender hosts) client-ip=2600:3c02::ffff:ffff:ffff:ffff;

This means, that Google cannot find my SPF record. This is odd, since I am publishing one. It turns out, that my application settings were incorrect and weren't able to set the proper from address and thus was used instead of This normally doesn't happen with sendmail but you can change the behavior either with -f in the sendmail path in php.ini or via this solutionI would not have run into this problem had myhostname not referenced the www subdomain but in this case I need it to also forward local mail without conflicting with local user accounts.

#3 Is your SPF record OK?

If you still have problems and are publishing an SPF record the headers again should tell you if your SPF record could be found and why it's not being matched. Most likely, your IP address is missing, so verify with the SPF records checking tools. Also, be on the lookout for IPv6, if you have it on your machine's network, even if you are not serving an AAAA record, you need to include such an address, because you might be connecting to it via Google and they want to verify the address they receive content from, e.g.:

Received-SPF: pass ( domain of designates 2600:3c02::ffff:ffff:ffff:ffff as permitted sender) client-ip= 2600:3c02::ffff:ffff:ffff:ffff; Authentication-Results: ... )

If that still doesn't help I'd suggest moving on to burned offerings to the cloud gods.

Shutting down

Localwiki was one of the very early projects on Kickstarter and succeeded in their funding way back in 2010. Since then they have created several great model communities to show off how (hyper) local wikis can be a community enabler. The idea still seems so obvious to me, like Wikipedia is in hindsight, that I am still confused why the idea has not taken off exponentially.

Running a localwiki

Creating a localwiki was really easy with the documentation provided by the maintainers, it amounted to spinning up a virtual machine with Ubuntu on one's preferred hosting plattform, adding one repository and installing one package, to get up and running. Which is just what I did under to get to know the platform itself (not having any Django knowledge) and to get to know my current city better. 

In the beginning of 2014 the service providing free mapping tiles went away and individual localwikis could choose to either migrate to the centrally managed architecture of the core development team or to acquire a license key to continue receiving tiles for maps. Since I have not been able to find enough people in St. Gallen to work on this project and am alone not motivated enough to work on it further I have now taken the site down.

I am writing this post to document this canceled project and provide an archive of the few pages which were created (see below) should anyone care to try something similar in the future.

First look at CentOS 7

Screenshot of CentOS 7 installer

In July, a month after the release of RHEL7, the CentOS team had released their clone of the 7 series. Time to take a look, since this will likely be the standard version for new projects I will be building, at the very latest by the middle of next year when a minor release has further stabilized the series.

New and noteworthy

  • The installer now aligns with what we have become familiar with based on the Gnome 3 desktop in Fedora, which is overall a good experience.
  • XFS is now the default root file-system including boot. That decision seems fairly bizarre when EXT4 is the default everywhere else and has an upstream path towards Btrfs.
  • Systemd is now in full effect, so I will have to take some time to finally learn the startup script changes properly.
  • Network interfaces are now carrying "Predictable Network Interface names". While that's a nice idea it also means that old common tricks such as "dhclient eth0" no longer work. Side note: Minimal install does not even contain ifconfig, so find your interfaces in /etc/sysconfig/network-scripts/ifcfg*, if you went with minimal. 
  • PHP 5.4.16, this is the part I'm most excited about, since this was the primary reason in my work to install third-party repositories such as IUS to get above ancient 5.3 versions present in the RHEL6 series.
  • You will look for the package mysql-server in vain, MySQL is now to be found via the fork mariadb-server.


Three lessons from amateur PHP code

Hacks cans
Photo CC-BY-SA by tnarik

I did not get a CS degree and thus learned web development as a self-taught amateur. While that was fun, it also meant that in the process of building things without a curriculum or a mentor to provide a foundation I wrote pretty bad code in the beginning.

I have dug up the PHP code for a site which has been superseded with a Drupal site since 2009 and it's a great way to show failure by example without anyone getting hurt.

The following shows common mistakes made by amateur PHP programmers and a few pointers on how to fix them and become a better developer.

Mistake #1: Repeating yourself

Every time you see redundant code it should give you pause. Even a decade ago I recognized this and tried to move the page header into a separate file. Here is the start of item.php and dozens of other files like it:

$pagetitle="Item Details​";
include "main.php";
echo "<div id=\"content\">";
// [...]

Viewing an item would thus be the URL /item.php?id=123. This structure exemplifies that the author has not thought enough about inheritance and overall structure. Furthermore, we can see in main.php that the file is just dumping content to the output like the all other PHP files in that application:

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "">
<html xmlns="" xml:lang="en" lang="en">
include "settings.php";

It's clear that the author has not even fully internalized procedural programming and is using includes simply to reduce redundancy in a static, linear script.

Fixing the mistakes

Point all requests to index.php as the sole entry point and use parameters to call the respective logic. Not only will you reduce errors but you can also centralize parameter checking and sanitization, as well as authentication and authorization. You can also easily add nice, readable URLs with a one-liner in htaccess.

Convert the static pages such as item.php into functions. Which is basically a given, if you restructure everything around your index.php as recommended above. In this case if we had all item.php logic wrapped in a function (or more likely a collection of them), we could call it where required through our routing logic and not attempt to build a linear script for each page. Ideally, you would follow established patterns like MVC for your program structure when doing so.

Don't solve this yourself. Seriously consider if your homebrew application should continue to exist. The above points explain how one would fix something like it if you cannot ditch it but consider carefully if a framework such as Symfony2 or a CMS like Drupal is not the better solution to start from scratch, since they provide all that essential work of handling I/O, routing pages, abstracting templating, etc. for you, if you invest the time to learn how these systems work.

Mistake #2: Mixing logic, data and display

Here is an additional excerpt from the item.php shown above:

if ($row[isbn] != NULL)
echo "<tr><td>ISBN/ISSN #:</td><td> $row[isbn] </td></tr>";
echo "<tr><td>Section:</td><td> $row[section]</td></tr>";
// [...] 20 more <tr> like that
$commentquery = mysql_query("SELECT comment FROM comments WHERE item='$row[item_id]'");
if (!mysql_num_rows($commentquery)==0)
echo "<br /><br />Comments by members about this item:";

while($row = mysql_fetch_array( $commentquery )) {
    echo "<div id=\"comdiv\">";
    echo nl2br($row['comment']);
    echo "</div>";

Thankfully, the query parameter was properly sanitized, so it is not a case of little Bobby Tables but it is a Smörgåsbord of bad patterns. Not only is redundancy a concern but the indiscriminate mix of data, html markup and query logic shows missing levels of abstraction. The weird string double escaping we'll just ignore.

Fixing the mistakes

Use PDO and prepared statements. If you write your SQL by hand and work with user input, you are asking for trouble. PDO tutorials abound.

Functions, functions, functions. The author should have seen the redundancy in his or her code and concluded that a helper function should deal with creating the table (let's ignore whether a table is the right solution here). The block on comments could equally as well be encapsulated in a function. However, that function alone would not add much readability (at least as long as it is as short as it is now), unless one takes out the markup, which the following recommendation encompasses.

Create templates. Even if you do not follow the general advice from mistake #1 on using an established base to build upon, you can improve legacy code by stripping out the markup into templates. Even if you don't want to fully commit to Symfony, you could use their Twig engine to do so and achieve much more readable and maintainable code. Again, consider not reinventing the wheel.

Mistake #3: Sloppy code conventions

if (!mysql_num_rows($commentquery)==0)
echo "<br /><br />Comments by members about this item:";

The line above we already saw in mistake #2. The problem here is that through missing brackets, spaces, and indentations the code becomes significantly harder to read. It's easy to overlook the scope of the if-loop and for example incorrectly assume that the while-loop following it is still in it's scope. The many formatting problems in the code were mainly due to the fact that I didn't use software to help me stick to a standard, since I wrote it all by hand.

Fixing the mistakes

Use an IDE. A text editor with syntax highlighting is just not enough, it's too easy to make mistakes. Your environment, whichever you decide upon, should do auto-formatting and code checking as-you-type. I use PHPStorm but the same can be achieved with free tools such as Eclipse. 

Follow PSR-1/2. If you have until now followed your personal preferences, just get over yourself and standardize to PSR-2, that way all your code and all modern libraries look the same. There are also tools to help you convert your existing code

All of the above will not make you into a great developer but I hope to have provided helpful advice to others that I wish I had been given at the time.

Goodbye comments

various spam containers
Photo CC-BY by arndog

Today I removed this blog's comment functionality after having it for over seven years. I do not host debates and do not have content which regularly inspires comments apart from "thanks" so I don't think that this will in any way diminish this blog. I'm sure if someone actually needs help or has information they want to give me, they will find the about page. 

And on the other hand, comment spam is simply out of control. At first I had Drupal's image captcha which worked well for a while but had to be exchanged for Recaptcha but when that let too many spam posts through I switched to Mollom and they have provided an excellent service but still let about one false negative through every other day for the 500+ attempts every day. 

So, to follow the spirit of @AvoidComments, no more more comments here.