Dec 11 2018
Dec 11

Custom Post Types in WordPress

By Andrea Roenning

Custom post types are the key to taking a WordPress website from a simple blog to a robust system for managing many types of content and data. They help create a WordPress administrator experience which makes it easy for editors to add and edit repetitive content and gives the developer flexibility to create unique web pages to fit the site’s individual needs.

The Flexibility of Drupal 8

By Michael Miles

This article demonstrates six different methods of changing content and functionality in Drupal. Each method requires a different skill set and level of expertise, from non-technical inexperienced users to advanced Drupal developers. For each method, we describe the components, skills, knowledge, and limitations involved. The goal is to highlight Drupal’s flexibility as a Content Management framework.

How to Learn PHP Unit Testing With Katas

By David Hayes

Sometimes code is first tested when the unfortunate client or user feels like using the feature and tests the developer’s work. Hopefully, they’re not disappointed. That’s why you should be interested in unit testing and Test-Driven Development (TDD)—because it makes your life as a programmer better. It would have saved me hours of work in situations like those outlined in the last paragraph. TDD and automated testing let us focus on what we’re there for: solving complicated problems with code and leaving the computers to do more of the rest.

It’s About Time

By Colin DeCarlo

As applications scale and gain adoption, dates and time become much more of a concern than they once were. Bugs crop up, and developers start learning the woes of time zones and daylight saving time. Why did that reminder get sent a day early? How could that comment have been made at 5:30 a.m. if the post didn’t get published until 9:00 a.m.? Indiana has how man time zones?!

The Dev Lead Trenches: Creating a Culture

By Chris Tankersley

I have spent much time talking about creating and managing a working team, but there is one important piece I’ve left out of the puzzle until now—creating and crafting a culture that makes people want to work on your team and stay on your team. If you have a company culture which does not attract people, employees will be hard to find.

The Workshop: Producing Packages, Part Three

By Joe Ferguson

Over the past two months we’ve been building PHP Easy Math a purposely simple example library to demonstrate how to build a reusable package for the PHP ecosystem. Make sure to check the previous issues if you’re just now joining us! This article is the third and final installment in this series. We’re going to cover triaging and managing issues users may open as well as pull requests to your library.

Education Station: Interview Coding Challenges

By Edward Barnard

Meanwhile, the days where employees stay with the same company 20-30 years are long gone. We move around or move on from contract to contract. For many of us, this means formal job interviews. Many of those interviews include coding challenges; that can be a problem. Let’s talk about that!

Security Corner: Adventures in Hashing

By Eric Mann

Last month, the PHP community had the opportunity to come together for the excellent php[world] conference in Washington, D.C. As part of the event, we held a hackathon to work through some of the challenges posed by Cryptopals. Some of the cryptographic primitives we discussed were hashes, and it’s useful to take a more in-depth look at what they are and how to use them in PHP.

By James Titcumb

The final days of 2018 are looming on us, and I wanted to take a look back on some of the things, good and bad, that happened in and around the PHP community this year.

finally{}: The Seven Deadly Sins of Programming: Greed

By Eli White

As you are reading this magazine, we are in a time of winter holidays and typically associated with a spirit of goodwill towards others. That is embodied often as giving presents to people as a gesture of that goodwill. Unfortunately, this can have the opposite effect at times of causing greed to form as people want more and more given to them. Alternatively, they may misinterpret it as greed, as a specific green haired character learns in his holiday tale.

Dec 11 2018
Dec 11

This article demonstrates six different methods of changing content and functionality in Drupal. Each method requires a different skill set and level of expertise, from non-technical inexperienced users to advanced Drupal developers. For each method, we describe the components, skills, knowledge, and limitations involved. The goal is to highlight Drupal’s flexibility as a Content Management framework.

This article was originally published in the December 2018 issue of php[architect] magazine. To read the complete article please subscribe or purchase the complete issue.

Feb 01 2018
Feb 01

As a digital agency we need to have a good content management solution for our clients. Even in situations where we are developing more custom apps than content web applications, we still need a good, modular CMS solution. As Symfony developers, we wanted to find powerful CMS solutions built on Symfony. We wanted to use our Symfony knowledge for building custom things on our chosen CMS solution. In this article, I will show you what we learned and how you can build things using Symfony inside Drupal.

This article was originally published in the February 2018 issue of php[architect] magazine. To read the complete article please subscribe or purchase the complete issue.

Dec 01 2016
Dec 01

dec16The twelfth issue of 2016 is now available! This month we look at how to write good tests with Behat and using Test Driven Development. This issue also includes articles on using HTTPlug to decouple your HTTP Client, Decoupled Blocks with Drupal and JavaScript. Our columnists have articles on writing a Chat bot, advice on securing your application’s secrets, making better bug reports, respecting diversity, and a look back at 2016.

Download your issue and read a FREE article today.

Oscar still remembers downloading an early version of the Apache HTTP server at the end of 1995, and promptly asking "Ok, what's this good for?" He started learning PHP in 2000 and hasn't stopped since. He's worked with Drupal, WordPress, Zend Framework, and bespoke PHP, to name a few. Follow him on Google+.
Aug 09 2016
Aug 09
Screenshot of Behat tests results

If automated testing is not already part of your development workflow, then it’s time to get started. Testing helps reduce uncertainty by ensuring that new features you add to your application do not break older features. Having confidence that your not breaking existing functionality reduces time spent hunting bugs or getting reports from clients by catching them earlier.

Unfortunately, testing still does not get the time and attention it needs when you’re under pressure to make a deadline or release a feature your clients have been asking for. But—like using a version control system and having proper development, staging, and production environments—it should be a routine part of how you do your work. We are professionals, after all. After reading all the theory, I only recently took the plunge myself. In this post, I’ll show you how to use Behat to test that your Drupal site is working properly.

Before we dive in, the Behat documentation describes the project as:

[…] an open source Behavior Driven Development framework for PHP 5.3+. What’s behavior driven development, you ask? It’s a way to develop software through a constant communication with stakeholders in form of examples; examples of how this software should help them, and you, to achieve your goals.

Basically, it helps developers, clients, and others communicate and document how an application should behave. We’ll see shortly how Behat tests are very easy to read and how you can extend them for your own needs.

Mink is an extension that allows testing a web site by simulating interacting with it through a browser to fill out form fields, click on links, and so forth. Mink lets you test via Goutte, which makes requests and parses the contents but can’t execute JavaScript. It can also use Selenium, which controls a real browser and can thus test JS and Ajax interactions, but Selenium requires more configuration.

Requirements

To get started, you’ll need to have Composer on your machine. If you don’t already, head over to the Composer Website. Once installed, you can add Behat, Mink, and Mink drivers to your project by running the following in your project root:

composer require behat/behat
composer require behat/mink
composer require behat/mink-selenium2-driver
composer require behat/mink-extension

Once eveything runs, you’ll have a composer.json file with:

    "require": {
        "behat/behat": "^3.1",
        "behat/mink": "^1.7",
        "behat/mink-selenium2-driver": "^1.3",
        "behat/mink-extension": "^2.2"
    },

This will download Behat and it’s dependencies into your vendor/ folder. To check that it works do:

vendor/bin/behat -V

There are other ways to install Behat, outlined in the quick introduction.

The Drupal community has a contrib project, Behat Drupal Extension, that is an integration for Behat, Mink, and Drupal. You can install it with the requre command below. I had to specify the ~3.0 version, otherwise composer couldn’t satisfy dependencies.

composer require drupal/drupal-extension:~3.0

And you’ll have the following in your composer.json:

       "drupal/drupal-extension": "~3.0",

Configuring Behat

When you run Behat, it’ll look for a file named behat.yml. Like Drupal 8, Behat uses YAML for configuration. The file tells Behat what contexts to use. Contexts provide the tests that you can run to validate behavior. The file configures the web drivers for Mink. You can also configure a region_map which the Drupal extension uses to map identifiers (left of the :) to CSS selectors to identify theme regions. These come in very handy when testing Drupal theme output.

The one I use looks like:

default:
  suites:
    default:
      contexts:
        - Drupal\DrupalExtension\Context\DrupalContext
        - Drupal\DrupalExtension\Context\MarkupContext
        - Drupal\DrupalExtension\Context\MessageContext
        - FeatureContext
  extensions:
    Behat\MinkExtension:
      goutte: ~
      javascript_session: selenium2
      selenium2:
        wd_host: http://local.dev:4444/wd/hub
        capabilities: {"browser": "firefox", "version": "44"}
      base_url: http://local.dev
    Drupal\DrupalExtension:
      blackbox: ~
      region_map:
        breadcrumb: '#breadcrumb'
        branding: '#region-branding'
        branding_second: '#region-branding-second'
        content: '#region-content'
        content_zone: '#zone-content'
        footer_first: '#region-footer-first'
        footer_second: '#region-footer-second'
        footer_fourth: '#region-footer-fourth'
        menu: '#region-menu'
        page_bottom: '#region-page-bottom'
        page_top: '#region-page-top'
        sidebar_first: '#region-sidebar-first'
        sidebar_second: '#region-sidebar-second'

Writing a Simple Feature

Now comes the fun part. Let’s look at writing a feature and how to test that what we expect is on the page. The first time we run it, we need to initialize Behat to generate a FeatureContext class. Do so with:

vendor/bin/behat --init

That should also create a features/ directory, where we will save the features that we write. To behat, a feature is test suite. Each test in a feature evaluates specific functionality on your site. A feature is a text file that ends in .feature. You can have more than one: for example, you might have a blog.feature, members.feature, and resources.feature if your site has those areas available.

Of course, don’t confuse what Behat calls a feature—a set of tests—with the Features module that bundles and exports related functionality into a Drupal module.

For my current project, I created a global.feature file that checks if the blocks I expect to have in my header and footer are present. The contents of that file are:

Feature: Global Elements

  Scenario: Homepage Contact Us Link
    Given I am on the homepage
    Then I should see the link "Contact Us" in the "branding_second" region
    Then I should see the "Search" button in the "branding_second" region
    Then I should see the "div#block-system-main-menu" element in the "menu" region

As you can see, the tests is very readable even though it isn’t purely parsing natural language. Indents help organize Scenarios (a group of tests) and the conditions needed for each scenario to pass.

You can set up some conditions for the test, starting with “Given”. In this case, given that we’re on the homepage. The Drupal Extension adds ways to specify that you are a specific user, or have a specific role, and more.

Next, we list what we expect to see on the webpage. You can also tell Behat to interact with the page by specifying a link to click, form field to fill out, or a button to press. Again here, the Drupal extension (by extending the MinkExtension), provides ways to test if a link or button are in one of our configured regions. The third test above uses a CSS selector, like in jQuery, to check that the main menu block is in the menu region.

Testing user authentication

If you’re testing a site that is not local, you can use the drush api driver to test user authentication, node creation, and more. First, setup a drush alias for your site (in this example, I’m using local.dev. Then add the following are in your behat.yml:

      api_driver: 'drush'
      drush:
        alias: "local.dev"

You can then create a scenario to test the user login’s work without having to specify a test username or password by tagging them with @api

  @api
  Scenario: Admin login
    Given I am on the homepage
    Given I am logged in as a user with the "admin" role
    Then I should see the heading "Welcome" in the "content" region

If you’ve customized the username text for login, your test will fail. Don’t worry! Just add the following to your behat.yml file so that the test knows what text to look for. In this case, the username field label is just E-mail.

      text:
        username_field: "E-mail"

Custom Testing by Extending Contexts

When you initialized Behat, it created a features/bootstraps/FeatureContext.php file. This can be a handy class for writing custom tests for unique features on your site. You can add custom tests by using the Drupal Extension’s own sub-contexts. I changed my Feature Context to extend the Mink Context like this:

class FeatureContext extends MinkContext implements SnippetAcceptingContext {

Note that if you do that, you’ll need to remove MinkContext from the explicit list of default context in behat.yml.

No matter how you organize them, you can then write custom tests as methods. For example, the following will test that a link appears in the breadcrumb trail of a page. You can use CSS selectors to find items on the page, such as the ‘#breadcrumb’ div in a theme. You can also re-use other tests defined by the MinkContext like findLink.

/**
 * @Then I should see the breadcrumb link :arg1
*/
public function iShouldSeeTheBreadcrumbLink($arg1)
{
   // get the breadcrumb
   /**
     * @var Behat\Mink\Element\NodeElement $breadcrumb
     */
   $breadcrumb = $this->getSession()->getPage()->find('css', 'div#breadcrumb');

   // this does not work for URLs
   $link = $breadcrumb->findLink($arg1);
   if ($link) {
      return;
   }

   // filter by url
   $link = $breadcrumb->findAll('css', "a[href=\"{$arg1}\"]");
   if ($link) {
      return;
   }

   throw new \Exception(
       sprintf("Expected link %s not found in breadcrumb on page %s",
           $arg1,
           $this->getSession()->getCurrentUrl())
    );
}

If your context implements the SnippetAwareContext, behat will generate the Docblock and method signature when it encounters an unknown test. If you’re feature has the following:

    Then I should see "foo-logo.png" as the header logo.

When you run your tests, behat will output the error message below that you can copy and paste to your context. Anything in quotes becomes a parameter. The DocBlock contains the annotation Behat uses to find your test when it’s used in a scenario.

/**
* @Then I should see :arg1 as the header logo.
*/
public function iShouldSeeAsTheHeaderLogo($arg1)
{
   throw new PendingException();
}

Selenium

Follow the Behat docs to install selenium: http://mink.behat.org/en/latest/drivers/selenium2.html. When you’re testing you’ll need to have it running via:

java -jar /path/to/selenium-server-standalone-2.53.0.jar 

To tell Behat how to use selenium your behat.yml file should have:

      selenium2:
        wd_host: http://local.dev:4444/wd/hub
        capabilities: {"browser": "firefox"}

You’ll also need to have Firefox installed. OF course, at the time of this writing, Firefox is asking people to transition from use Webdriver to Marionette for automating browser usage. I have Firefox 47 and it’s still working with Webdriver as far as I can tell. I have not found clear, concise instructions for using Marionette with Selenium. Another option is to use Phantom.JS instead of Selenium for any features that need a real browser.

Once everything is working—you’ll know it locally because a Firefox instance will pop up—you can create a scenario like the following one. Use the @javascript tag to tell Behat to use Selenium to test it.

  @javascript
  Scenario: Modal Popup on click
    Given I am at "/some/page"
    When I click "View More Details"
    Then I wait for AJAX to finish
    Then I should see an "#modal-content" element
    Then I should see text matching "This is a Modal"

Conclusion

If you don’t have tests for your site, I urge you to push for adding them as part of your ongoing work. I’ve slowly added them to my main Drupal client project over the last few months and it’s really started to pay off. For one, I’ve captured many requirements and expectations about how pages on the site work that were only in my or the project manager’s heads, if not lost in a closed ticket somewhere. Second, whenever I merge new work in and before any deploy I can run tests. If they are all green, I can be confident that new code and bug fixes haven’t caused a regression. At the same time, I now have a way to test the site that makes it less risky to re-factor or reorganize code. I didn’t spend a lot of time building tests, but as I work on a new feature or fix a bug, writing a test is now just part of confirming that everything works as expected. For complicated features, it’s also become a time saver to have a test that automates a complicated interactions—like testing a 3-page web form, since Behat can run that scenario much faster than I can manually.

The benefits from investing in automated testing outweigh any initial cost in time and effort to set them up. What are you waiting for?

Apr 18 2016
Apr 18

email symbol on row of colourful envelopesWhat would a website be if it couldn’t send emails, even if just for password resets? Running your own mail server is a huge hassle, so many developers instead use a third party service to send transactional emails like password resets, new user welcome messages, and order summaries. One of the most popular services, in part because of their generous free tier, is Mandrill, owned by MailChimp.

In case you might have missed the announcement, MailChimp is changing Mandrill to be an add-on to paid MailChimp accounts, thus eliminating the generous free tier. We’re big fans of MailChimp and use its mailing list service for our own announcements, (hey, why not join that list if you’re not already on subscribed?) but a full MailChimp account isn’t going to be for everybody. They’ve already shut out the ability for new subscriptions, but if you’re a PHP developer who does things like put off your taxes until the last minute (American customers have three extra days this year, but that’s today), you’re probably sweating the April 27th deadline.

Many people also know Mandrill by reputation and will need options in the future. For you, we’ve put together this list of viable transactional email alternatives with PHP and major PHP application support. Joomla! and MODX support SMTP integration natively, so you’ll just need the SMTP configuration options from your chosen provider. If you want to use a provider’s web API, see the PHP options below.

Cal Evans did an unscientific Twitter survey to see what options people were migrating to:

If you are moving off of @mandrillapp, what are you moving to?

— Cal Evans (@CalEvans) March 29, 2016

SparkPost

MailChimp’s announcement notes that SparkPost has agreed to take on existing Mandrill users and honor Mandrill’s pricing for them. Fortunately, SparkPost has PHP users covered: there is an official PHP API library. There is also a Drupal module, but unfortunately it seems to be 7.x only at this writing and is only a sandbox project—you’ll have to install it via git. Drupal 8 users should be able to use the official API library with Composer. WordPress developers are in more luck: there is an official WordPress plugin. SparkPost provides a guide for Magento devs using the SMTP Pro extension. SparkPost also has one of the most generous plans we’ve seend, with 100,000 free emails per month, though you can not exceed that limit without upgrading ahead of time.

SendGrid

A long time option for PHP users has been SendGrid. (Full disclosure: SendGrid has sponsored our php[tek] conference in the past, but is not a current sponsor.) They have an official PHP API, installable via Composer. While there is a 7.x-only Drupal module, SendGrid recommends Drupal users use the SMTP Authentication Support or Swift Mailer modules in its documentation. Both the officially-recommended modules support Drupal 8 at least in the development releases of each module. Magento is also supported through the SMTP Pro extension. WordPress devs can install the official plugin. SendGrid doesn’t list a free tier on their pricing page, their “Essentials” plan start at $9.95 for 40,000 emails per month.

SendinBlue

Many devs I know have spoken highly of SendinBlue. They offer a WordPress plugin, (7.x only) Drupal module, and Magento extension. They also have an official PHP library. Their free tier is limited to 9,000 emails per month with no daily limits, however the messages will include SendinBlue branding.

Amazon SES

Amazon’s transactional email service is affordable but not as easy to install and configure for newbies. They have an official PHP library through the AWS PHP SDK. There is a third-party Drupal module for 7.x users. Similarly there’s an independent WordPress plugin. There is a USD 99 paid extension for Magento.

Mailjet

Mailjet offers a PHP API wrapper, a WordPress plugin, a 7.x-only Drupal plugin, a Joomla! extension, and a Magento plugin. The free tier is capped at 6,000 emails per month and 200 email per day. The first 30 days include a premium trial which allows users to explore segmentation, testing, and compare campaign performance.

Mailgun

Mailgun has a PHP SDK installable via Composer. There is also a WordPress plugin, a 7.x-only Drupal module,  and a Magento extension. The first 10,000 emails each month are free, after which you pay a tiered price based on monthly volume.

Postmark

Postmark offers a PHP API library, installable via Composer and available on Packagist. There is also an official WordPress plugin. There is a community-supported Drupal module (you guessed it, 7.x only) and Magento extension. There are also many other community modules for PHP frameworks. If you sign up to try it, the first 25,000 emails are free. After that, you can buy credits to send emails starting at $1.50 per thousand emails.

Conclusion

Which of these services you use depends on your needs, price sensitivity, and how much specific support you want for your platform. If I’ve missed any services with good PHP support, please let us know in the comments!

Image Credit: RaHuL Rodriguez on Flickr

Apr 05 2016
Apr 05

We’re going to be in New Orleans next month for DrupalCon, will you be? Heather White, Sandy Smith, and I will all be flying down the week of May 9th. Heather helped organize the PHP track for this year’s event and will be helping to make sure everything runs smoothly for the speakers. Sandy will be at our sponsor booth to chat with all of you and show off our magazine and some sample books. I’ll be at our booth with Sandy and also presenting Navigating the PHP Community.

DrupalCon New Orleans Logo

Want to join us? We’re giving away a free ticket to DrupalCon at random. We’ll draw names from all entries on Wednesday, April 13th.

Our Contest is closed.

Can’t make it to Drupalcon? Come meet and hang out with us at php[tek] in May or on php[cruise] this summer. Also, follow us on twitter, @phparch, or subscribe to our mailing list to stay updated.

Oscar still remembers downloading an early version of the Apache HTTP server at the end of 1995, and promptly asking "Ok, what's this good for?" He started learning PHP in 2000 and hasn't stopped since. He's worked with Drupal, WordPress, Zend Framework, and bespoke PHP, to name a few. Follow him on Google+.
Apr 01 2016
Apr 01

The April 2016 issue of php[architect] magazine is out! This issue we take a look at how Drupal is using tools and techniques from the PHP community.

This issue also includes articles on how to easily generate documentation, advice on learning new frameworks, what it means to be a leader in the PHP community, and how to use PHPStorm to improve your code.

Download a FREE article and get your issue today.

Oscar still remembers downloading an early version of the Apache HTTP server at the end of 1995, and promptly asking "Ok, what's this good for?" He started learning PHP in 2000 and hasn't stopped since. He's worked with Drupal, WordPress, Zend Framework, and bespoke PHP, to name a few. Follow him on Google+.
Feb 26 2016
Feb 26

We’re excited to announce that we’ve partnered with the Drupal Association to help plan and organize the dedicated PHP track at this year’s DrupalCon in New Orleans. Our own Heather White is working with Larry Garfield (aka @crell) to identify PHP topics relevant to Drupal developers, review sessions, and select speakers. Having a robust PHP track will help Drupalers “get off the island”, a call-to-action started by Larry that has seen the Drupal project embrace solutions and practices from the greater PHP community. At the same time, it’s an opportunity for PHP developers to see how Drupal 8 embraces modern PHP including Object-Oriented development, Composer integration, and code re-use to provide a world class CMS. This collaboration continues the work we began when we launched php[world], a conference meant to bring together PHP’s disparate communities.

If you’re a speaker, the call for sessions is still open (closes on Feb 29th, see link for exact time). Look for the php[architect] team at this year’s DrupalCon. We look forward to meeting you there.

Oscar still remembers downloading an early version of the Apache HTTP server at the end of 1995, and promptly asking "Ok, what's this good for?" He started learning PHP in 2000 and hasn't stopped since. He's worked with Drupal, WordPress, Zend Framework, and bespoke PHP, to name a few. Follow him on Google+.
Oct 07 2015
Oct 07

This morning, during my usual scan of Feedly/Twitter/Reddit I read Secure the data of visitors on your Drupal website better. The post shows you how to use the Field encryption module.

The Field encryption module ensures that the values stored in the Drupal database are encrypted. When the database ends up in the wrong hands, then nobody can read the data since this module has encrypted it. This way, you are prepared for a worse case scenario.

It all seems straight forward enough, but I suspected it wouldn’t be so simple and in fact doesn’t look as secure as purported. My main concern was with the 3 options presented for storing the private key used to encrypt data. So I asked on Twitter:

How secure is this if Drupal needs to read the key? http://t.co/q8wzlLy2dM /cc @enygma @Awnage @ircmaxell

— Oscar Merida (@omerida) October 7, 2015

Now, this post isn’t meant to denigrate the work of that project or to completely discount the advice on openlucius.com. Let’s see why some of the ways to store the key are problematic.

@enygma @omerida @Awnage the key is stored in the db? o_O

— Anthony Ferrara (@ircmaxell) October 7, 2015

The first option is to store the key in the database, and at least the article recommends against selecting that. If your key is in the database, and a malicious attacker manages to steal your database or find some way to read it’s contents via SQL Injection, they will have your key. With the key, nothing will stop them from unencrypting your data.

The second option is to specify it as a variable in settings.php. The key is a little harder to get but is only a variable_get('encrypt_drupal_variable_key') call away. Since settings.php is in the public web root, misconfiguring PHP or having PHP files show the source code will leak your key too. Finally, if you’re committing your settings files to git or SVN (hint: you shouldn’t be), anyone with access to your repository will also have your key.

@omerida imho they should only offer the last option. @ircmaxell @Awnage

— Chris Cornutt (@enygma) October 7, 2015

The final option, to use a File should be the recommended way to specify the key. Ideally, the file is somewhere outside of your web root and, again, not in your code repository.

Only in option 1 is your key vulnerable to SQL injection attack. For the other 2 options, an attacker would have to gain access to your code to get your key. Given how Drupal 7 stores routes in the database, all that takes is and SQLi vulnerability in another module or core itself and someone could install a back door or shell on your site.

@omerida @enygma @Awnage depends on a lot of factors. If done correctly (haven't looked yet), could make SQLi virtually useless by itself.

— Anthony Ferrara (@ircmaxell) October 7, 2015

No matter how you store it, if you have the PHP module enabled, anyone who can build a view or execute PHP code from the Drupal UI can retrieve your key. There’s also a temptation to share the key across development, testing, and production environments so that your database snapshots are portable between them all.

Others brought up issues on as well. The original module author added a comment highlighting that the Field Encryption module is still marked as Beta, which was released in 2013.Also, there are better key management solutions for Drupal.

@enygma @ircmaxell @omerida @Awnage the default options are bad, bad, and bad. Modules like townsec_key & key attempt to provide real KMS

— Cash Williams (@cashwilliams) October 7, 2015

Also, there are better algorithms for encryption than those in the module.

@ircmaxell @enygma @omerida @Awnage It's worse than that, the suggested plugin Encrypt, uses ECB & mcrypt with no authentication. *shrug*

— Ashley Pinner (@NeoThermic) October 7, 2015

Security is a Continual Process

This illustrates that security is a continual process, with a lot of considerations to take into account. It’s not as easy as installing a single module or ticking a box on a check list. If you’re storing really sensitive user data, ask yourself if you really need it. If this data is credit card information—get to know what it takes to be PCI compliant. Then ask if you aren’t better off using a payment processor instead. But please, don’t be lulled into a false sense of security after adding a single component.

Oct 05 2015
Oct 05

With Drupal, it’s possible to build very intricate solutions by gluing the right combination of contrib modules together. Of course, there is a downside to relying only on contrib modules, particularly for one-off or highly custom tasks. Bringing in a contrib module means you assume responsibility for feeding and caring for it. If it’s a mature module, like Views, that’s one thing. But if you find yourself looking at a little-used module that hasn’t seen a stable release yet—or worse hasn’t been updated in months—you may be better off rolling your own solution.

Drupal 8 development has shown that PHP itself, and the wider PHP community, already provides ways to solve common tasks. In this post, I’ll show you some core PHP functionality that you may not be aware of; pulling in packages and libraries via Composer is a topic for another day.

In this particular case, I need to export a CSV file showing all nodes added to a site after a specific date. This report may get created just a handful of times. True, I could easily build a View and use Views Data Export to download it as CSV but doing it purely in code has these benefits:

  • No module dependencies. It’s at least one less thing to update and maintain, especially if security issues are found. If data exports in multiple formats were a more import feature across this site, the Views Data Export module would definitely make sense.
  • Easy to deploy. If I make it a view, I have to remember to export it and make sure it’s deployed to all my environments. If someone edits the view on one of them and doesn’t export it, I could lose improvements or fixes. Granted Features can really streamline the process, but in this case it’s not critical, and as you’ll see everything we do will be in code anyway.
  • Integration with Drush. I created a Drush command to run this at the command line. This made it quicker for me to develop since it was easy to run without involving a browser. PHPStorm’s built-in terminal was perfect for this task. Drush commands are also useful for automation and scheduling. If I need, this script can be cron’d to run daily and pipe the output somewhere.
  • Efficient resource usage. Depending on how PHP is configured, if you’re running a command line script you may not have to worry about memory_limit or max_execution_time settings. These can cause your script to terminate unexpectedly when you’re processing a lot of data. In this case, we could be exporting hundreds or thousands of nodes depending on how far back in time we go.

A Minimal module.info File

For this example, I created a simple exporters module and prefixed it with my initials to prevent unexpected naming clashes. Below are the contents of my om_exporters.info file, free of any other module dependencies. I also created an om_exporters.module file just in case but it ended up empty.

name = OM Exporters
description = Exports newest content to CSV
core = 7.x
php = 5.5
version = 7.x-1.0

Creating a Drush Command

Creating a custom Drush command is straightforward. Drush will look for new commands in a file called <module>.drush.inc. In that file, you should have a function named <module>_drush_command(), which implements a hook_Drush_command(). When you add or change commands, you’ll need to clear caches for Drush to know about the changes.

In this case, the function is simple:

function om_exporter_drush_command() {
    $items['export-newest'] = array(
        description' => 'Export Newest Content to CSV',
        'aliases' => ['ex-new'],
        'callback' => 'om_export_newest',
        'arguments' => [
            'date' => '',
        ]
    );

    return $items;
}

As you can see, the key to $items becomes our Drush command export-newest. We can give it a friendly description, a shorter alias (ex-new), specify the function to run in callback, and list any arguments we require.

Now, when you run the Drush command as shown below, whatever function listed as the callback will be invoked and passed the arguments needed.

Drush export-newest 2015-08-01

Validating Dates

The first thing we’ll do is validate the date argument using PHP 5’s DateTime class. If you’re not familiar with it, this class makes it easy to work with Dates and Timezones without a lot of fuss in an object-oriented manner. It’s easier to understand than using older functions like time(), date(), and strtotime().

The code below takes the $date_arg passed in from Drush and makes sure its parsable as a date. If validation fails, our function does not continue.

function om_export_newest($date_arg) {
    // get the default timezone
    $tz = variable_get('date_default_timezone', 'UTC');
    $tz = new \DateTimeZone($tz);
    // First validate date, we assume $date_arg is
    // a string that can be parsed by \DateTime so
    // you have the flexibility to pass
    // in '-1 months' or '28 days ago'
    try {
        $since = new \DateTime($date_arg, $tz);
    } catch (\Exception $ex) {
        watchdog('export-newest',
            Could not parse date:' . $ex->getMessage(),
            null,
            WATCHDOG_CRITICAL);
        return;
    }
    // ..

Output CSV with SPL’s File Object

The Standard PHP Library is a collection of useful classes that’s not as well known as it should be. It’s intended to solve common problems. In this task, I used the \SplFileObject class to work with files as objects. I find it a lot easier than remembering and looking up the different file_* functions, since I get autocompletion in my IDE. For this, we create a file object that writes to STDOUT so that our command will output everything to the terminal or screen. First, we create our SPLFileObject:

// we will use SPL to send our data to STDOUT formatted as CSV
$fout = new \SplFileObject("php://stdout");

Scripts write to STDOUT by default anyway, but to use the built-in fputcsv method, we need to specify it explicitly.

Typically the first line of a CSV file is the header describing the columns that follow. Now, here’s where we use fputcsv(). This method takes in an array and then writes it as a CSV file. The method automatically handles using commas to separate fields, enclosing text fields with quotes, and so on. You can even configure how all that is handled; for example, if you need to use ‘;’ as the separator. See the online documentation for fputcsv for details.

// write our headers
$fout->fputcsv([
    'nid', 'type', 'title', 'date_created', 'path_alias'
]);

Finding Nodes with EntityFieldQuery

Drupal’s native EntityFieldQuery API is a powerful alternative to always relying on Views to create and filter some collection of nodes, users, taxonomy terms, etc. It’s also object-oriented (I keep saying that) and provides a very readable interface for querying Drupal’s databases. It abstracts away the underlying data store for you, so you don’t need to know exactly what tables or fields everything is in. For that same reason, it’s much safer to use than doing a direct db_query().

One thing that is tricky at first is wrapping your head around the terms it uses. Entities have properties that are common to all the entities of that kind. For nodes, these are things like the title, created date, the bundle (content type), the status, and more. If it’s fieldable, it can have fields specific to a bundle. If you need to query on property values, you use propertyCondition. For fields, use fieldCondition. The same pattern holds if you need to sort them by one or the other. To dig deeper, see How to Use EntityFieldQuery.

The code below shows how get all the nodes with a created timestamp greater than the one we pass to our Drush script.

// query for nodes newer than the specified date
$query = $query = new EntityFieldQuery();
$query->entityCondition('entity_type', 'node')
            ->addMetaData('account', user_load(1)) // Run the query as user 1
            ->propertyCondition('created', $created->format('U'), '>')
            ->propertyOrderBy('created', 'ASC');

Iterating Entities with Generators

Generators were introduced in PHP 5.5. They’re a special kind of function that uses the yield keyword to return an item that’s part of some collection. In practice, they’re a simple way to build a function that iterates over a collection without having to build the whole collection in memory first.

In the code excerpt below you’ll see how we loop through the nodes returned by our EntityFieldQuery. We do this in a generator—notice the yield keyword.

$result = $query->execute();
if (!empty($result)) {
    // $result is an array with node ids
    foreach ($result['node'] as $nid => $row) {
        $count++;
        
        // TRUE will reset static cache to
        // keep memory usage low
        $node = node_load($row->nid, null, TRUE);
        if ($count < 100000) {
            yield $node;
        }
    }
}

The generator function is called in a foreach loop which terminates once the generator stops yielding values.

    // use a generator to loop through nodes
    foreach (nodes_generator($since) as $node) {
        $fout->fputcsv([
            $node->nid,
            $node->type,
            $node->title,
            $node->created,
            url('node/' . $node->nid)
        ]);
    }

Usage

With the module complete and enabled, we have a new Drush command out our disposal. We can invoke it in a terminal shell with the command below:

drush export-newest 2015-06-01

That command will output our nodes as a stream of CSV lines. To save the output in a file, just redirect it as shown below. Once you download the file, you can send it to your client and/or project manager to peruse in Excel.

drush export-newest 2015-06-01 > newest-nodes.csv

Conclusion

There you have it, a straightforward independent Drush command that uses built-in PHP libraries to export a collection of nodes to CSV. Of course, we could have done it with Views and some other modules, but this module is easy to version and quick to deploy. It only depends on Drupal core, so it’s super low-maintenance.

For the full script, check out the gist on github

Jan 29 2015
Jan 29

Last week, I had the pleasure to present at the Drupal NoVA meetup group about using Vagrant to automate setting up development environments for your projects. Using a VM has been the single biggest change to my workflow in recent years, no matter what CMS or framework I’m using on it.

You can view the slides below.

Afterwards, I received a few questions—which means I need to update the slides—which led to some interesting research for answers.

Can you setup a VM through vagrant which allows GUI-based OS access

Now, Vagrant assumes you’re comfortable at the command line, and if you need to access the guest OS, it’s just a vagrant ssh away. But there are cases where you want more than a terming, maybe for providing a standard desktop environment for a GUI tool. It turns out, of course, that this is possible. Assuming you’re using Virtualbox, add the following line in your Vagrantfile to the block that configures Virtualbox settings.

v.gui = true;

With it, the box will not launch in headless mode. Of course, if using a Linux image your provisioner should install a desktop environment like Gnome or KDE.

For more, see the Vagrant Documentation on Headless Mode and this Question on StackOverflow

Can I install Windows of any flavor?

My initial instinct was that this wouldn’t be possible, because of licensing and activation. However, it turns out that I was wrong. From Windows Boxes for Vagrant Courtesy of Modern.ie:

One of the sites that helped make my environments simple was Modern.ie as they provided a series of Virtual Machine images with multiple versions of Windows with different versions of Internet Explorer installed. These images are available for users on a Mac, Linux or Windows machine by taking advantage of different virtualization technologies including Hyper-V, Parallels, Virtual Box and VMware Player/Fusion.

I’m pleased to be announcing a new way to leverage the Modern.ie VMs for your testing purposes — Vagrant. If you aren’t familiar with Vagrant, Vagrant is a handy tool for your tool belt which is used to create and configure lightweight, reproducible and portable development environments.

Read the post to see the limitations as well as what combinations of of Windows XP through Windows 8.1 and IE 6–11 are available.

Are you using Vagrant in your day-to-day work? What tips would you share with others getting started?

Dec 17 2014
Dec 17

Taming Content coverThe final issues of 2014 is out!  Our theme this month in “Taming Content” with features on WordPress, Drupal, and ProcessWire. Also read about PHP tricks, Queues with Laravel, the SoundCloud API, and Community News!

Check out the full magazine details page for more details, Download the Advanced Custom Fields article for free to sample an article.

Oscar still remembers downloading an early version of the Apache HTTP server at the end of 1995, and promptly asking "Ok, what's this good for?" He started learning PHP in 2000 and hasn't stopped since. He's worked with Drupal, WordPress, Zend Framework, and bespoke PHP, to name a few. Follow him on Google+. Tags: , , , , , ,
Nov 25 2014
Nov 25

At this year’s php[world] hackathon, I spent my time getting a Vagrant machine configured to run Drupal 8. I know there are other options, like Acquia’s own Dev Desktop, or even Zend Server. However, I like using Vagrant to run my LAMP stacks, especially on OS X. I’ve never been able to easily run xAMP on non-Linux machines. Installing MySQL can be a pain, system updates can change the version of PHP you’re running, and some PHP extensions are really difficult to build—even with Homebrew. Vagrant simplifies getting a working development environment running by automating the provision of a virtual machine for you, usually with a tool like Chef, Puppet, or Ansible. I used the hackathon as an opportunity to check out the shell script provisioner. If you know you’re way around the shell, this is a very straight-forward method since it uses the same commands you’d type in yourself at the terminal. There are a number of other benefits to using Vagrant:

  • Match your development environment exactly to your production server, so there’s no more “works on my machine”.
  • No need to install stuff you don’t need on your main operating system just for one client site.
  • Each site you work on gets its own machine, that you can destroy when the project is done.
  • Save your provisioning scripts in Version Control, to track how they change.
  • Share your Vagrantfile and scripts with colleagues, so everyone works in an identical environment.
  • Easily test code in new environments. How will your codebase run in PHP 5.6? Fire up a new machine and test it.

In this post, I’ll walk through setting up a Vagrantfile and shell script to install Apache, MySQL, PHP on a basic Debian machine; automatically download and extract Drupal 8, and create a database for the site. At the end, we’ll just have to walk through the installation steps in a browser.

Configuring the Virtual Machine

The Vagrantfile describes the machine for a project and how to configure and provision it. It controls things like how to setup networking, map files between the host and guest OS, and run the provisioner we chose. Let’s take a look at some key configuration settings. First, we have to specify the box to build on. These are box images, many provided by the community, that have the base OS and some tools. There are boxes for CentOS, Redhat, and more. The line below tells vagrant to use a Debian 7.4 box that has chef installed (even though we won’t be using chef).

config.vm.box = "chef/debian-7.4"

Next, we configure networking so that our box is accessible from the host OS. Here, I’m using the private_network option, so the box and specifying an internal IP address. If you need your virtual machine to be accessible from other devices on your local network, look into using a public_network.

config.vm.network "private_network", ip: "192.168.33.10"

For this config, I’m just using the default shared folders setting. This maps your project directory to /vagrant/ on the guest OS. If you haven’t used Vagrant before, shared folders map one or more directories from your host machine to paths on the virtual machine. In effect, this lets you work and edit files in your favorite IDE on your machine while the guest OS sees and uses the same files. So, for example, you change sites/default/default.settings.php in PHPStorm in your home OS, and Drupal in the VM will process the changes. If you need to map more directories, see the comments in the default Vagrantfile. For example, to map the web directory to /var/www/drupal8, you’d do something like the following:

config.vm.synced_folder "web", "/var/www/drupal8"

Finally, we have to tell vagrant what do once the machine is booted up in order to configure it. This is done with a provisioner, and there are many to choose from. As I mentioned earlier, I’m using a simple shell script for this machine; specified with the config.vm.provision setting.

config.vm.provision "shell", path: "provision/setup.sh"

Setting Up Additional Components

When you start your box for the first time with vagrant up, the provisioner will take care of installing additional components and configuring them. My first pass at this was a bit naive, though it worked. I later came back and augmented it to check if something was already available (you can run vagrant up --provision to re-provision an existing machine). For example, the following part of the script will setup Apache. First, we test if the Apache configuration is present. If it is, we assume it’s already configured and continue. If it’s not present:

  1. It’s installed from the apt repositories,
  2. The Rewrite module is enabled,
  3. We copy some custom environment settings and change directory ownership so that Apache runs as the vagrant user. This is necessary to allow the web server to copy uploaded files into a folder at sites/default/files.
if [ ! -e "/etc/apache2" ]
then
    echo "Installing Apache"
    apt-get install -y apache2
    a2enmod rewrite
    cp /vagrant/provision/apache2-envvars /etc/apache2/envvars
    sudo chown vagrant /var/lock/apache2
    usermod -a -G adm vagrant
fi

Similarly, later in the script we use wget to download and extract the Drupal 8 source into a web directory. $DRUPAL_SRC is a variable configured at the beginning of the script, for when it changes.

# download drupal
if [ ! -e "/vagrant/web/" ]
then
    echo "Downloading Drupal 8"
    mkdir /vagrant/web/
    cd /vagrant/web/
    wget --quiet $DRUPAL_SRC
    tar --strip-components=1 -xzf `basename $DRUPAL_SRC`
    rm `basename $DRUPAL_SRC`
    rm /vagrant/web/sites/default/default.settings.php
fi

Take a look at the complete script to familiarize yourself with what it does.

Provisioning with Ansible

At the same hackathon, Sandy Smith worked on setting up a similar machine with Ansible. We had a friendly competition going over who’s method would work first, and we both hit a few snags. Learn more about provisioning with Ansible in the September 2014 issue In the end, there wasn’t much of a difference. However, the Ansible provisioner reuses existing “roles” coupled with variables you specify. This leads to much smaller “playbooks” to configure a new machine. It also takes care of tracking what changes have been made if you re-provision a box.

---
- hosts: all
  sudo: true
  vars:
    web_server: apachephp
    servername: drupal8.local www.drupal8.local 192.168.33.99
    timezone: America/New_York
  vars_files:
    - vars/mysql.yml
    - vars/common.yml
    - [ "vars/apachephp.yml", "vars/ws_defaults.yml" ]
  roles:
    - init
    - php5-cli
    - apache
    - php5
    - mysql
    - composer
    - phpcommon
    - app

Using the Box

Before using the box, you have to install Vagrant and Virtualbox on your machine. Then clone or download the files from from github: https://github.com/omerida/drupal8-vm. In the directory where the files are use vagrant up to start the machine. The default URL is http://drupal8.dev/ To access it, add the following line to your hosts file:

192.168.33.10   drupal8.dev

Once the box is booted, open a browser and go to “http://drupal8.dev” and you should see the Drupal 8 installation wizard. d8-install

What’s next?

This gives you a very basic machine to work on. From here, you could do a number of things:

  • Add the dotdeb.org repository to get newer versions of PHP and MySQL.
  • Figure out how to add drush to the guest system
  • Further automate the basic Drupal installation
  • See how to install contrib modules to the site.

If you can script it, you can automate it.

Oct 16 2014
Oct 16

Are you done updating your nginx and apache servers to no longer support SSLv3 and prevent the POODLE attack? Well, now it’s time to upgrade your Drupal 7 sites to version 7.32, as a significant SQL injection vulnerability has been fixed in that update. Exploits are sure to follow, if they aren’t already in the wild.

SA-CORE-2014-0044

The technical writeup of the exploit is, in my opinion, actually very light in providing technical details. Helpfully, there’s a simple patch to prevent the attack. If you can’t do a full upgrade right now, go apply the patch. The exploit can be used by anonymous attackers, so an ounce of prevention here will pay off. Let’s take a look at the patch:

diff --git a/includes/database/database.inc b/includes/database/database.inc
index f78098b..01b6385 100644
--- a/includes/database/database.inc
+++ b/includes/database/database.inc
@@ -736,7 +736,7 @@ abstract class DatabaseConnection extends PDO {
// to expand it out into a comma-delimited set of placeholders.
foreach (array_filter($args, 'is_array') as $key => $data) {
$new_keys = array();
- foreach ($data as $i => $value) {
+ foreach (array_values($data) as $i => $value) {
// This assumes that there are no other placeholders that use the same
// name. For example, if the array placeholder is defined as :example
// and there is already an :example_2 placeholder, this will generate

The fix is to change the foreach loop to ensure it loops through a numerically indexed array of values. Without the call to array_values, malicious attackers could inject SQL conditions via the array’s keys, which are used to name the expanded placeholders. The post on sucuri.net about the exploit shows the manipulated SQL statement. A good discussion of the attack can also be found on the PHP subreddit.

But…PDO?

I was a bit stumped at first. Drupal 7 is using PDO and prepared statements, so it should be safe from SQL injection. Right? Diving into the affected file, this foreach loop is in a function, expandArguments that “supports an alternate syntax for doing arrays of values”. Looking at the example from the advisory:

The function assumes that it is called with an array
which has no keys. Example:

  db_query("SELECT * FROM {users} where name 
    IN (:name)", array(':name'=>array('user1','user2')));

Which results in this SQL Statement

  SELECT * from users where name IN (:name_0, :name_1)

with the parameters name_0 = user1 and name_1 = user2.

The Problem occurs, if the array has keys, which are 
no integers. Example:

  db_query("SELECT * FROM {users} where name IN (:name)", 
     array(':name'=>array(
       'test -- ' => 'user1',
       'test' => 'user2')
     )
  );

this results in an exploitable SQL query:

  SELECT * FROM users WHERE name = :name_test -- 
    , :name_test AND status = 1

with parameters :name_test = user2.

Since Drupal uses PDO, multi-queries are allowed. So this 
SQL Injection can be used to insert arbitrary data in the 
database, dump or modify existing data or drop the whole 
database.

So, because the array keys were not filtered nor sanitized, attackers can change the resulting SQL. Coupled with the fact that PDO allows multi-queries by default, a single call could execute an insert, update, delete, drop statement along with the original select statement.

Disabling Multipe Queries

Don’t use Drupal? Because PDO uses emulated prepared statements, If you’re using PDO to interact with MySQL, you may want to disable multiple queries in your PDO statements as a safeguard. Though you’ll also lose the ability to “use a named parameter marker of the same name more than once in a prepared statement”. Read the PHP documentation for PDO::prepare, first. To disable it:

$pdo->setAttribute(PDO::ATTR_EMULATE_PREPARES, false);

Security is Ongoing

This attack reinforces that security is hard and ongoing. You can’t trust user input, so remember to always Filter Input, Escape Output (FIEO). Kudos to the Drupal security team for addressing and publicizing the vulnerability. While it’s unfortunate that an exploit was found, it’s comforting to know that the project has a team dedicated to security.

Aug 20 2014
Aug 20

We are excited to announce today the amazing keynote speakers that we have lined up for our php[world] conference this November. We’ve worked hard to find the best speakers and talks that cover the breadth of the PHP experience. We want php[world] to be a conference that pulls together all the different fragmented communities of PHP into one place to share ideas, and our keynotes reflect that mission.

We will have Luke Stokes, Co-Founder and CTO of FoxyCart, speaking on his experience of forming his own company. Angela Byron, a core committer to the Drupal Project and Director of Community Development at Acquia, is going to talk to us about the efforts Drupal has been making to break out of its own community and embrace libraries from other projects. Andrew Nacin, a WordPress Lead Developer, is going to share how WordPress built their automatic security updates and convinced their community of its benefits. Also, Jeffrey “Jam” McQuire, Open Source Evangelist at Acquia, will present how the Open Source Software revolution, with PHP leading the way, is making for better business, better government, and, he hopes, a better world!

Finally we are going to wrap up the conference with “The Greatest Panel on Earth.” We will have key people representing seven of the biggest PHP frameworks and applications: WordPress, Drupal, Magento, Joomla!, Symfony, Laravel, and Zend Framework all together in one place to answer all your most difficult questions!

Read on for full descriptions of all the keynotes, or you can visit our php[world] schedule or speaker list online. Register soon and book your hotel before our block sells out! We look forward to seeing you in D.C. this fall!

Turning Your Code Into a Company: The Parts They Don’t Tell You.

Somewhere around 2005 and 2006 my friend and I started tinkering around with building a better shopping cart experience because all the others sucked. Since 2007, we’ve processed over half a billion dollars worth of transactions and enabled thousands of online stores. It was really, really hard. This talk will tell the story of taking some code and persevering it into a company called FoxyCart. If you’ve ever wanted the liberty of being your own boss, hopefully you’ll find yourself in this story and determine if you have what it takes to succeed.

BIO: Luke Stokes is the Co-founder and CTO of FoxyCart.com. Enjoying Nashville, TN with his beautiful wife and three children, he’s passionate about living life on purpose. He’s pragmatic enough to get things done but idealistic enough to still believe we can change the world and make it better. He built his first websites in 1996 (yes, AOL and Geocities) and has been hacking at computers ever since. Always opinionated, he loves a good debate on liberty, Bitcoin, programming or anything interesting. He’s also a generally outgoing guy (for a programmer) and loves connecting with people.

Drupal 8: A Story of Growing Up and Getting Off the Island

The Drupal project has traditionally held a strong internal value for doing things “The Drupal Way.” As a result, Drupal developers have historically needed to build up reams and reams of tricks and workarounds that were specific to Drupal itself, and Drupal was inaccessible to people with a more traditional programming background.

Starting in Drupal 8, however, we’ve effectively done a ground-up rewrite of the underlying code and in the process made major inroads to getting more inline with the rest of the PHP world. Procedural code is out, OO code is in. “Creative” hacks have been replaced with FIG standards. “Not invented here” is now “Proudly found elsewhere.”

This story will talk about the journey that Drupal 8 and the Drupal core development team has taken during this transition over the past 3+ years, including some of the pros and cons of this approach and how we dealt (and are dealing) with some of the community management challenges that resulted.

BIO: Angela Byron is Drupal core committer and Director of Community Development at Acquia. She got her start as a Google Summer of Code student in 2005 and since then has completely immersed herself in the Drupal community. Her work includes reviewing and committing Drupal core patches, supporting community contributors, coordinating with the Drupal.org infrastructure team, and evangelizing Drupal. Angela is the lead author of O’Reilly’s first Drupal book, entitled Using Drupal. She is on the Board of Directors for the Drupal Association. Angie is known as “webchick” on drupal.org.

Idealism as code: From philosophy to empowerment

As part of the LAMP stack, PHP is a dominant web technology and it is getting more powerful all the time: Convergence through things like Composer and the PSR standards is bringing once disparate communities together. Multiple “meta projects” like Drupal are adopting code from around the PHP and FOSS spheres. Contribution to one has become contribution to whole ecosystems.

Many of us are idealists. Powering 80% of the web, we have the chance – and perhaps the responsibility – to make a difference through PHP. Paraphrasing Angie “Webchick” Byron, Drupal core committer, “We make really abstract complicated programming concepts accessible to non-developers, available to them by clicking a few buttons, without having to understand all the code that comes underneath it. What I get really excited about is the idea that we create really easily accessible things to help those people who are on the front lines trying to make the world a better place. We can build technology to enable that.”

I will talk about how the thinking of RSM and other pioneers became code and how that code is empowering people and organisations. I want to draw a few lines from the very definition of free and open source software, through its practical application and native advantages, to how it helps people do better business, better government … and I’m hoping … make a better world.

BIO: Jeffrey A. “jam” McGuire, Open Source Evangelist at Acquia, is involved at the intersection of open source software, business, and culture. A memorable and charismatic communicator, he receives enthusiastic responses from audiences at events around the world, where he talks about open source technology and community, digital disruption, Drupal and more. This helps satisfy his inner diva, which he also feeds with performances as a storyteller and musician.

Trust, Community, and Automatic Updates

In October 2013, WordPress shipped what is perhaps its most polarizing feature ever — automatic updates in the background of self-hosted web software, on by default and no easy way to turn it off. In most open source communities, this would be cause for open revolt. Learn how through trust, communication, and a steadfast commitment to its philosophies, the WordPress core team convinced a skeptical community to go along, even if it meant users giving up some control.

BIO: Andrew Nacin is a lead developer of WordPress, wrangling contributions, spearheading initiatives, advising new development, and squashing bugs. He feels strongly about the core philosophies of WordPress, among them “decisions, not options” — software should be opinionated in lieu of burdening the user with too many options. He works for WordPress founder Matt Mullenweg at Audrey Capital, where he is primarily tasked with working on WordPress core and keeping the lights on at WordPress.org. He resides in downtown Washington, D.C., with his wife.

The Greatest Panel on Earth

Join us for our closing keynote! Have you ever wanted to ask the various framework and application developers questions? Want to see each of their different points of view (and maybe get them to debate a few hot topics)? This is your chance. We are gathering a panel of core developers from WordPress, Drupal, Magento, Joomla!, Symfony, Laravel, and Zend Framework. They’ll be ready to have a discussion and answer your questions.

About the author—Eli has been a PHP coder since the day PHP 4 was released. He's worked for numerous companies in the past, such as Digg.com, Zend Technologies, TripAdvisor, mojoLive, and Goodsie. Though found himself in love with the PHP community so deeply that he ended up here at php[architect], and loves what he does. Conferences, magazine, books, training - Teaching people the love for the language that he himself has.

Jul 18 2014
Jul 18

By default, Drupal is configured to send out plain text emails. For many developers, plain text email is sufficient and preferable to HTML email. HTML email is still, in this day and age, not guaranteed to render the same across email clients, more likely to be labeled as spam, and requires a significant amount of testing to make sure it works. Still, a minimally styled HTML message can be easier for recipients to read and help reinforce your brand/design (if you don’t depend on images to do so). In this article, we’ll look at the modules to install and configure to enable HTML emails and, specifically, how to change the default Webform email template to send submissions as HTML.

1. Set up your site to send email

In the hopefully distant past, your server would have a Mail Transfer Agent (MTA) installed in order to send email messages to other MTAs. On Linux systems, this was usually handled by Sendmail, Postfix, or Exim. Configuring these packages, maintaining them, and ensuring they aren’t exploitable by spammers. Luckily this is a time drain we no longer have to deal with.

Instead, transactional email providers can handle outgoing email, and the headaches involved, for us. Depending on your hosting provider, you may have one already available. If not, I like to recommend Mandrill, which “runs on the delivery infrastructure that powers MailChimp.” Besides having a top-of-the-line service behind it, it has a very generous free tier that allows sending 12,000 emails at no cost each month.

Once you’ve signed up for the service, you need to create an API key so that your Drupal site can use the service. From the Mandrill app dashboard, click on Settings and in the bottom half of the screen, click on + New API Key. From there, enter a good description for the key. You’ll see that you can also restrict what IPs can use the key as well as what API Calls each key can use (You’ll want to give a key at least the Send privileges).

Create a Mandrill API Key

Once you’ve created your key, it’s time to setup Drupal to connect to Mandrill and use it for outgoing email. The quickest way to do this is to use the SMTP Authentication Support

This module allows Drupal to bypass the PHP mail() function and send email directly to an SMTP server. The module supports SMTP authentication and can even connect to servers using SSL if supported by PHP.

Install it using drush with the commands below, or download and enable it via the Modules page.

drush dl smtp
drush en smtp

Once it’s enabled, navigate to Admin > Configuration > SMTPAuthentication Support . The path will be admin/config/system/smtp. Once there, under SMTP Server Settings set smtp.mandrillapp.com as the SMTP Server, with the default port of 587. In the SMTP Authentication section, enter your Mandrill login as the Username and the API Key you created earlier as the Password. To ensure your settings are working, tick the Enable debugging checkbox before you click the Submit configuration button. If you don’t receive a test email, check your settings and API key restrictions before proceeding.

2. Allow outgoing email to use HTML

This is the crucial part where we configure Drupal to send HTML emails instead of plain text ones. We need two modules for this, MIME Mail which in turn depends on Mail System. Note also that MIME Mail depends on Drupal core > 7.23, so make sure you’re running at least 7.24. Install both modules with drush as follows and answer yes when asked to download the mailsystem module:

drush dl mimemail
drush en mimemail

Next, go to to Admin > Configuration > Mime Mail to configure the MIME mail module settings. You can change the From: name and email address here, and in the select menu labelled E-mail format choose a text format that allows some HTML formatting. You could even create one that is tailored for outgoing email, which we’ll see later. Optionally you can choose to include your site’s style sheets in the emails, but I recommend creating a mail.css file in your theme instead and leaving this unmarked. Save your settings and proceed.

Finally, and this was the most difficult part to figure out, we need to configure the Mail System module. Go to to Admin > Configuration > Mail System From this form, we’ll create a new class for sending email and tell drupal to use it. First, expand the New Class field set. Here we’ll pick the classes that handle formatting and sending email and the module will generate a new class based on the ones we select. Select MimeMailSystem in the Class to use for the format() method and Select SmtpMailSystem in the Class to use for the mail() method, as shown in the figure below and then save the settings.

Generating our mail handling class

When the page reloads, you’ll see a new option in the class select menus in the Mail System Settings field set. The new class will be named MimeMailSystem_SmtpMailSystem, indicating the format() and mail() selections. Choose the new class in the Site-wide default and Mime Mail module class select menus then save the settings.

Generating our mail handling class

Finally, we have to tell the SMTP module to allow HTML emails. A new checkbox will be shown on the SMTP Authentication Support settings form under E-Mail Options. Make sure it’s checked, then save the settings.

SMTP HTML Email

At this point, your Drupal site is configured to format outgoing emails as HTML. But the emails sent my modules, such as the User module’s email when a new password is requested, will need a template or formatting to send legible emails.

4. Formatting Outgoing Email

One way to do this, as mentioned earlier, is to create an HTML Email text format that automatically adds paragraphs based on new lines and turns URLs and email addresses into clickable links. A sample one I created recently is shown in the figure below. Note that if you limit the HTML tags allowed, you have to use only those tags in custom templates. Once your text format is created, go to the MIME mail settings screen an select it as the E-mail format.

Email Text filter

A text filter like the one above will ensure that the default emails look nice, as in the image below. If you want to include headers, bold tags, or even images, you’ll have to add that to the message template. For the User module, you can edit the template at Admin > Configuration > People > Account Settings. Scroll to the bottom of the page, below the E-mails heading are vertical tabs, one for each kind of email (password reset, new account welcome, etc).

Password reset email with a basic text filter

4. Send Webform Submission as HTML Emails

In this section, we’ll see how to override emails that use templates files in your theme. The Webform module is my go to module for creating forms that send emails to site admins and visitors. It is lightweight, scalable, and comes with a lot of functionality prebuilt along with companion modules to augment its capabilities.

Of note, there is also the Entityform module which meets the same basic need. Which one you choose is up to you and the requirements for your project, see When to Use Entityform for a comparison of the two.

First, we need to tell the Mail System to use our SMTP and MimeMail Class for outgoing webform messages. Go to admin/config/system/mailsystem, expand the last section New Setting, and select “Webform >> Webform Module” in the Module select. You can leave the key field below empty, then Save Settings.

Mail System settings for Webform Module

When the page refreshes, you’ll see a new select dropdown for Webform module class. Select our old friend, MimeMailSystem_SmtpMailSystem and save the settings again.

Mail System settings for Webform Module

Webform’s emails can be overridden by custom templates in your theme folder, for all emails or even for specific webforms. You’ll find the instructions for doing so in the module’s themeing instructions webform/THEMEING.txt, the relevant section is shown below.

Theme submission e-mails
-----------------------
The default e-mails sent by webform are fairly basic. If you like, you may
customize the display of e-mails sent by each individual webform.

- Open the Webform module directory.

- Copy (do not move!) the "webform-mail.tpl.php" file to your theme directory.

- Open up the new file and edit it to your liking. The webform-mail.tpl.php file
  contains further instructions on how to get started with theming the e-mail.

- If you want to edit the e-mail sent by only one particular webform, rename the
  file "webform-mail-[node id here].tpl.php", replacing [node id here] with the
  node ID of the webform.

The base email template file, webform-mail.tpl.php, renders the submission data using newlines to separate each field of data. If you want to add headings and other HTML formatting to the message, you can do so in the file. But it’d be a pain to have to customize every webform’s email template individually, particularly if you’ll have a lot of webforms or your site’s content editors will be creating them independently. I was puzzled by this at first, until the thought struck me that the module already builds an HTML representation of the submission when it displays that to user’s who can view a submission. There had to be a way to reuse that function, which turned out to be webform_submission_render(). The template code below shows how to do just this, while also respecting the configuration settings for which components to include and exclude in the message.

<?php

/**
 * @file
 * Customize the e-mails sent by Webform after successful submission.
 *
 * This file may be renamed "webform-mail-[nid].tpl.php" to target a
 * specific webform e-mail on your site. Or you can leave it
 * "webform-mail.tpl.php" to affect all webform e-mails on your site.
 *
 * Available variables:
 * - $node: The node object for this webform.
 * - $submission: The webform submission.
 * - $email: The entire e-mail configuration settings.
 * - $user: The current user submitting the form.
 * - $ip_address: The IP address of the user submitting the form.
 *
 * The $email['email'] variable can be used to send different e-mails to different users
 * when using the "default" e-mail template.
 */
?>
<h1><?= check_plain($node->title) ?></h1>

<?php
echo webform_submission_render($node, $submission, $email, 'html');
?>

<p><a href="https://www.phparch.com/2014/07/sending-html-emails-with-drupal-7-webform-and-mandrill//%submission_url%">View this submission online</a></p>

That’s all there is to it! Remember to create a mail.css file in your theme folder so that you can have some control over the output. After that, its just a matter of testing the emails in as many possible email clients as you can (especially the ones your clients use). Your best bet, still to this day, is to keep it simple and not try to do very fancy layouts. Also, since a lot of email is consumed on mobile and tablet device, don’t bloat them with a lot of CSS or images (which may not be rendered anyway).

Conclusion

Drupal can send nicely formatted emails, if you install and configure the correct recipe of modules. There are a lot of settings to wade through, and potentially some trial-and-error to tweak them and getting working exactly as you need. But you are now familiar with a set of modules to make this work, and hopefully I’ve shown you the basics so that you can better spend your time on crafting beautiful and effective email messages.

Related Links

Nov 01 2013
Nov 01

I was working on a page that had a sidebar block showing a list of content with the same topic as the main page. In Drupal terms, the sidebar block shared the taxonomy term. It’s pretty easy to create such a block using Views by adding a contextual filter that gets its value from the page path. Contextual filters are very powerful. You can learn more about them in the Drupal documentation here.

Of course on some pages, if Views finds no matches, the block will not display. Our client came back and asked if it could show the full list on pages where no matches were found with the same topic. After pondering it a bit, I realized that this is possible using one of the hooks Views makes available. As you can see from the full list of hooks, you can affect how a view is built at many points along the way. You can accomplish this through the Views UI, by embedding a view in the “No Results” behavior. This example will show you how to do the same in code, but could also be extended to do more complicated replacements, like render one or more blocks programatically.

Figuring out which hook to use can be challenging, especially if you’re unfamiliar with the build pipeline and its phases. In this case, we’ll use the post_render hook, but first, let’s look at our block view which has the identifier “block_1”. I had added two contextual filters that get their values based on the current path of the page. A sample path to the page could be /lists/12/4, where 12 is a topic term id and 4 is an audience term id. Note that you can use term names as the identifier when you configure a contextual filter, but support for this is buggy, especially if your terms include ampersands or other punctuation (see this issue).

views-hook-context

The first thing to do is to clone our filtered display and remove the contextual filters for the cloned block. The new block will have an identifier like “block_2”. You’ll also need to know the machine name of the view we are targeting. Once the blocks are set up in Views, we need to create our view hook in a custom module. The hook code looks like the following:

/**
 * Implements hook_views_post_render(&$view, &$output, &$cache)
 *
 * @param $view
 * @param $output
 * @param $cache
 */
function mymodule_views_post_render(&$view, &$output, &$cache) {
  // test for the view we want to change
  if ('sidebar_lists' == $view->name) {
    switch ($view->current_display) {
      case 'block_1': // our filtered list      
        if (empty($view->result)) {
          // show unfiltered results
          $output = views_embed_view('sidebar_lists', 'block_2');

          // fake a non-empty result for views to render the block
          $view->result = array(1 => true);
        }
        break;
    }
  }
}

That’s all we need. The post_render hook allows us to check if our first block found any matches. The views_embed_view() function is used to programmatically get the output of our fall back view and set that as our output. When I first tried this, nothing displayed. It turns out that you need $view->result to have a non-empty value for Views to render the block.

Of course, I’ve introduced a bit of a performance hit to our page loads by executing another query if the filtered view query is empty. If you’re not caching the whole page, you’d want to cache the output of the block.

The Views UI let’s you build some very complicated filtered lists. Still, in some cases you will need to write custom code. I hope this example shows you how the View module’s hooks can be used to get it to do what you want.

About Drupal Sun

Drupal Sun is an Evolving Web project. It allows you to:

  • Do full-text search on all the articles in Drupal Planet (thanks to Apache Solr)
  • Facet based on tags, author, or feed
  • Flip through articles quickly (with j/k or arrow keys) to find what you're interested in
  • View the entire article text inline, or in the context of the site where it was created

See the blog post at Evolving Web

Evolving Web