Drupal and Taxonomy Weights

I recently worked on a project in Drupal that called for a large number of taxonomy terms. I needed to put the terms in a specific order, but unfortunately, I had more terms than Drupal's weight field supports, which is a range from -10 to +10.

I did a quick search on Drupal, and was horrified to see how many people are hacking core to add a greater range. This is pretty easy to do without hacking core. All you need to do is create your own module that implements hook_form_alter().

my_module.module

<?php

function my_module_form_alter($form_id, &$form) {
  switch(
$form_id) {
    case 
'taxonomy_form_term':
    
$form['weight']['#delta'] = 100;
    break;
  }
}
?>

And that's it!

[tags]alter, drupal, form, hook, module, taxonomy, term, weight[/tags]

Get Firefox Ad

This is a pretty cool ad for Firefox that just makes me laugh...

Firefox, IE, Opera, Netscape, browsers, funny, ad

Tradition vs. Technology

I've lived in New England my entire life, and if there's one thing that Yankees treasure, it's tradition. I'm no different, and yet today, I grudgingly decided that one tradition is not worth keeping.

Ever since I was a child, my family engaged in one of the most time-honored New England traditions of the autumn: raking leaves. Raking leaves is a noble chore. You get exercise and fresh air, your lawn benefits from being dethatched by the tines of the rake, and it instills a solid work ethic in the young.

It's a chore that I have always cherished. This year, however, I was rather dreading it. I just purchased a new home in September, and it has a substantially larger yard than my previous home. I knew that it would take me weeks to rake the entire property, and with a full time job, young kids, a wife, and everything else that keeps a family busy, I was trying to figure out how I could squeeze an extra 12 hours into each day.

Mostly out of curiosity, I decided to try a leaf blower. I'll categorically state that I find this to be cheating, but in the face of weeks of raking, I saw little reason to not give it a try. I'll have to admit, I was highly skeptical of the tool. As I mentioned before, one of the benefits of raking by hand is that the lawn gets a good dethatching; that is, all the dead grass and other material that forms a carpet right at the level of the soil and blocks nutrients from reaching the roots of the grass gets pulled up by the tines of the rake. I didn't see how a leaf blower would help with this.

At this point, I have to concede that the idea for the leaf blower was not mine. The leaf blower was a gift to me from my father, who is much wiser than I am. When he first gave it to me, I had no intention of using the thing for the reasons I had mentioned above. I have the unfortunate tendency to forget about things that I dismiss as useless, even if my determination regarding the usefulness of a thing is based on little or no prior experience. I don't know what it was about today that made me rethink my position on the leaf blower, but I was pleasantly surprised by its effectiveness.

As I mentioned, I have a large yard. Nearly two acres of level lawn, ringed by a thick woods of maple, oak, birch, and sumac. I was able to completely clear my backyard of fallen leaves in under an hour, a chore that would have easily taken me six hours had I resorted to my traditional techniques. The leaf blower was powerful enough to scrub the lawn and underlying soil clean. However excited I was about my progress and the ease of clearing the leaves, I could not help but feel sadness.

You see, I'm addicted to technology. I work with it every day, and run my life with it. The use of technology, even simple technology like a leaf blower, has implications. Using a leaf blower is a one-man job, and the tool is so loud, there's no chance for discussion and conversation while working. Furthermore, when you use a tool that cuts your work time down to next to nothing, the issue of work ethic is not even worth mentioning.

I was left wondering how I will teach all of these things to my sons. How will I teach them the value of sweat equity, the importance of physical labor and the satisfaction of putting your body to work with fantastic results? How can they learn the fine art of Yankee conversation, which occurs in short bursts, layered on top of physical work? The great New Hampshire author Noel Perrin described this very thing in one of his essays.

Sure, I can choose to abandon the leaf blower and go back to traditional methods. But as much as I have this choice, my Yankee sense of frugality forbids me from doing something that takes so much time when I have at my disposal the tools to get the job done faster leaving room for other things. Would I rather rake or spend the extra time with my sons?

As my father always reminds me, there's no such thing as setting aside quality time with your kids. He points out that any time you spend with your kids is quality. Perhaps I'll take this to heart and take my kids for a walk in the woods instead of raking up the woods.

[tags]autumn, chores, leaf+blower, leaves, new+england, new+hampshire, raking, work, yankee[/tags]

Flex and Drupal Paths

At CommonPlaces, each developer has his or her own sandbox to code in. Each sandbox can run n instances of a Drupal application, which all run out of subdirectories from the developer's web root. So, for example I have a structure like this:

  • /public_html
    • /drupal_site1
    • /drupal_site2

We have a similar staging environment for all of our QA, and then of course, we have the production servers.

When I develop Flex applications that need to connect to one of these instances, I run into fun with dynamic urls to the /services/amfphp gateway. Because Flex can interact with Javascript, it's trivial to build dynamic urls to whatever environment the Flex app is running in.

Step 1: Download and enable the JSTools module for Drupal. This module extends the Drupal javascript object and gives it extra properties.

Step 2: Construct your urls dynamically in Flex by utilizing the ExternalInterface object.

var protocol:String = ExternalInterface.call('location.protocol.toString');
var domain:String = ExternalInterface.call('location.hostname.toString');
var urlPath:String = ExternalInterface.call('eval', 'window.Drupal.settings.jstools.basePath');
var gatewayUrl:String = protocol + "//" + domain + urlPath + "services/amfphp";

Note that the protocol and domain strings are set via ExternalInterface calls to a javascript function. The urlPath string is set via a call to the eval() function, and I'm passing in an argument of the Drupal basepath property set by jstools.

Debugging this is also easy, if you use Firefox and the Firebug plugin. All you have to do is pass debug strings to the console:

ExternalInterface.call('console.info', 'protocol = ' + protocol);
ExternalInterface.call('console.info', 'domain = ' + domain);
ExternalInterface.call('console.info', 'path = ' + urlPath);
ExternalInterface.call('console.info', 'gateway url = ' + gatewayUrl);

With the dynamic url to your amfphp gateway set, you can be assured that your Flex client will be able to consume data from Drupal services, no matter where the Flex app is run.

[tags]actionscript, Adobe, AMFPHP, CommonPlaces, Drupal, Flex, javascript, jstools, module, Services, urls[/tags]

Hack-proof Your Drupal App - the Video

I had the pleasure of presenting at DrupalCon in Szeged Hungary, and the topic of my presentation was Drupal security from the perspective of the application. I am pleased to be able to share the video of my presentation. Drupal, DrupalCon, CommonPlaces, Szeged, security, hacking, filters, output

DrupalCon Experiences in Szeged, Hungary

I have been attending DrupalCon this week, hosted in the beautiful Hungarian town of Szeged.

I was fortunate in that my company, CommonPlaces, was generous enough to become a silver sponsor for the conference. This gave me the opportunity to present a session on Drupal security, and a BoF session on cross-site request forgeries and mitigation strategies. The session on hack-proofing Drupal applications seems to have been well received; there was a mix of people in the audience in terms of skill levels and knowledge on the topic.

While the information I presented was well documented in various parts of drupal.org and other blogs, I think the practical demonstrations of attack strategies was eye-opening for many in the audience. There is a big difference, in my opinion, between knowing how to prevent a vulnerability and knowing the mechanics and practical application of a vulnerability. The practical demonstrations were handled by Arian Evans from WhiteHat Security, as my co-presenter.

There was a wide variety of sessions offered at DrupalCon, and one of my favorites by far was on the topic of attracting and retaining Drupal talent. This was a very candor look at how some of the larger Drupal shops (RainCity, Palantir, and Development Seed) run their businesses and profit from working with Drupal.

The huge presence of Acquia here at DrupalCon is very exciting, and I'm very excited to see what they are up to.

If you haven't gotten the chance to attend a DrupalCon before, I hope that you find a way to beg, borrow, or hitchhike your way to the next one.

DrupalCon, CommonPlaces, Drupal, security, sessions

Drupal and Sane Flash Remoting

On my latest project, I was faced with a challenge: build Flash widgets that displayed dynamic data and could be embedded on any web page. Phase two of the widgets called for user interaction with the widget, as opposed to simply displaying content. It seemed that Flex would be the most logical technology to use for this project.

I used the Services and AMFPHP modules for Drupal to expose content via web services for my Flex widget to consume. However, I ran into a problem with the critical piece that Flex needs in order to get remote data. As a workaround to the browser security settings that prevent cross-site scripting, Adobe chose to implement an opt-in solution in the form of a file called crossdomain.xml. With crossdomain.xml, a site owner may allow a list of domains to read its data and the client, Flash in this case, is responsible for enforcement. As the business case for the project called for the widget to be embedded on any domain, I needed to use a promiscuous crossdomain policy, allowing access from all domains:

[xml]

[/xml]

Because of this policy, the widget was allowed to read all data on the site that the user has access to, including any (authenticated) content and (session) cookies. This could easily lead to privacy violations, account takeovers, theft of sensitive data, and bypassing of CSRF protections.

Other domains in a similar predicament have simply hosted their APIs on a different domain, thus preventing access to user data on the root domain. Unfortunately, the nature of Drupal doesn't allow for splitting the Services functionality out from the rest of the platform.

My solution was to write a forwarder, which is just a really simple PHP script, that is hosted on a subdomain. This subdomain hosts the promiscuous crossdomain policy, and the policy file on the root domain is configured to only accept requests from the subdomain. The forwarder does two things: it first makes sure that only requests to /services/amfphp are allowed; if allowed, the $HTTP_RAW_POST_DATA is sent to the root domain via cURL.


<?php
// Configuration variables
$server 'http://mydomain.com/services/amfphp';

$request_uri trim($_SERVER['REQUEST_URI']);
if (
$request_uri[0] === '/'){
  
$request_uri substr($request_uri1);
}

// Split the uri into components
list($handler$protocol) = split('/'$request_uri);

// Filter out unwanted requests
if(($handler != 'services') && ($protocol != 'amfphp')){
  exit();
}

// Handle the post from the flash/flex client
$xml $HTTP_RAW_POST_DATA;
if(
strlen($xml) == 0){
  exit();
}

// Set the headers
$header[] = "Content-type: text/xml";
$header[] = "Content-length: ".strlen($xml);

$ch curl_init($server);
curl_setopt($chCURLOPT_RETURNTRANSFER1);
curl_setopt($chCURLOPT_TIMEOUT30);
curl_setopt($chCURLOPT_HTTPHEADER$header);
curl_setopt($chCURLOPT_POSTFIELDS$xml);

$response curl_exec($ch);

if (
curl_errno($ch)) {
  exit(); 

else {
  
curl_close($ch);
  if(
strlen($response) == 0){
    exit();
  }
  print 
$response;
}

exit();

?>

Because the subdomain doesn't host any data at all, the security risk has been removed. If you are working with Drupal and Flash remoting, you'll need to consider the risks associated with promiscuous crossdomain policy files. While my solution certainly isn't the only solution, it is pretty effective and simple.

[tags]Adobe, crossdomain.xml, curl, Drupal, Flash, Flex, forwarder, policy, security, vulnerability, widget, xml[/tags]

Introduction to Young Talent

My niece, Brynn Doughty, played a wonderful piano piece for a recital on June 12, 2008.

Drupal: Cross-domain Widgets

Drupal is incredibly flexible, but in current versions, lacks the ability to export content easily in the form of widgets. However, the Services module gives you that flexibility in a very easy to use manner.

Services allows you to expose pieces of your Drupal site, such as user, node, and views methods. Combine this with the integration of AMFPHP, you can build some extremely fast Flash and Flex widgets that display dynamic data and can be embedded on any website.

However, there is a catch.

I was working with another developer on a Facebook application that displayed my Flex widget, and it seems that in Facebook, you have to provide a static image for the user to click on in order to active the flash. This is clunky, and not the ideal solution for me.

Another option was to attempt to create cross-domain javascript widgets. I looked at JSON Server, which is a Services wrapper that returns data in JSON. This module worked great on the same domain, but failed on cross-domain calls. The reason why is that the module only accepts POST requests.

I ended up patching the module to accept GET requests structured in the following manner:

[js]
function get(){
headElement = document.getElementsByTagName("head").item(0);
var script = document.createElement("script");
script.setAttribute("type", "text/javascript");
// The callback parameter is needed so that the JSON gets returned correctly in order to be handled by the output function
script.setAttribute("src","http://server.com/services/json?method=views.getView&view_name=some_view&callback=display");
headElement.appendChild(script);
}

function display(obj){
var theDiv = document.createElement("div");
theDiv.innerHTML = obj.data;
document.body.appendChild(theDiv);
}
[/js]

You'll note that I am doing script tag inserts into the head of the calling website. The script source is set to the path of my JSON server, with the services method as a parameter. The services method takes arguments, which differ depending on the service you are calling. In the case of the Views.getView service, you have to supply the name of the view to call.

The last parameter specifies the name of your output function. My patch takes this callback and wraps the JSON-formatted data returned by the service with the name of the callback. The callback is extremely important, as the JSON sent back by the server acts as a call to your defined callback function. From there, your callback function can display the data however it chooses.

Implementation of this method on a remote site is very easy:

[js]

get();
[/js]

For my widget, I created a custom service that returned the output of a theme() function to render the widget template. This html output was then displayed by my JSON callback function.

Using the Services and (patched) JSON Server modules for Drupal, you can quite easily set up cross-domain javascript/html widgets that can be embedded anywhere.

[tags]callback, cross-domain, Drupal, flash, flex, javascript, JSON, scripting, Services, widgets[/tags]

PHP Debugging Goodness

I have found PHP nirvana in a box.

I was trying to debug the lastest dev version of the userpoints module for Drupal, and was getting nowhere. The process of debugging PHP is tedious to begin with, but the practice of putting print statements into your code in places you think are likely the problem is a nightmare, and a huge black hole for productivity. Understanding what hooks are getting called and when they execute via print statements is a good way to waste an entire afternoon.

Enter Zend Studio. Their newest version is based on Eclipse, the open-source IDE that ties development in many languages into a single common UI. Zend Studio supports interactive debugging sessions with the server version of its debugger, and the client-server communication allows you to step into, over, and return from bits of code. It tells you what variables are currently in the stack, what the chain of functions is that is being called, and many other useful things.

I have to admit, I didn't come to this point of nirvana without trial. In trying to configure the Eclipse PDT to communicate effectively with the server debugger running on a remote server, I failed spectacularly. I tried a few other IDEs, and found them all to be unacceptable. I even tried Zend Studio 5.5. I was at the end of my patience when I found the newest version of Zend Studio, which. just. worked. Yes, I said it. It just worked, with the exception of changing the default port setting for the remote debugger.

My frustration is gone, I am at one with the code, and I can finally explain exactly what is going on in Drupal - how things get called, where and when they get called, and what the results of each call are.

And that bug with the userpoints module? The problem existed between keyboard and chair.

[tags]client, code, debugger, Drupal, Eclipse, IDE, module, PHP, server, userpoints, Zend[/tags]

About Erich

Erich is a web developer and a native New Englander who is passionate about life, the universe, and everything.

He is currently a senior Drupal developer at Harvard University, working on the IQSS OpenScholar project.  Prior to joining the team at Harvard, he was the engineering manager at CommonPlaces e-Solutions, in Hampstead, NH, contributing as the lead engineer on the Greenopolis.com and Twolia.com.

Erich is active in the Drupal community, having contributed modules and patches to the community. He presented at DrupalCon in Szeged Hungary, and co-presented at DrupalCon 2009 in Washington, DC.

Erich lives in New Hampshire with his wife, two sons, and two weimaraners.  When not writing code, Erich enjoys landscaping and woodworking.

Faceted search

Categories

Content type

Project types

Artwork Type

Artwork Tags

Recent comments

Activity Stream

August 28, 2010

August 5, 2010

August 4, 2010

  • Twitter ebeyrent tweeted "@cpliakas Absolutely spectacular!!!" 8:54pm #
  • Twitter ebeyrent tweeted "Looks like I picked the wrong day to quit smoking. #failday" 10:08am #

August 3, 2010