Wednesday, December 18, 2013

Putting content on a specific part of a Drupal page

I wanted to add some buttons to my page. The best place looked like it was on the right hand side of the menu bar. That way I wouldn't waste any vertical space and the buttons only needed to be small and inconspicuous (they were for adding and deleting annotations). The problem was how to do it. You couldn't do that by just assigning the text to an existing region so I defined a new one. I called it "Annotations". In my theme's .info file I added the line:

regions[annotator] = Annotations

But you could call it anything you like. The next step was to create a module that could generate the content. I created a trivial "annotator" module that had a hook_block_view function. This generated some content when the module was being rendered by the template.

So to get the module called I had to install and enable it. Then in the Structure section of admin I told Drupal to assign the annotator module's output to the "Annotations" region.

Finally, I edited the template (as it turned out the specific template for that page, but it could be the general one) in my theme so that just after it has rendered the menu it then tests for the existence of the "annotator" module and renders the content:

<?php if ($page['annotator']) : ?>
    if (module_exists('annotator'))
        print drupal_render($page['annotator']);
<?php endif; ?>

All that remains to be done is to style the module output so that it floats to the right and Bob's your uncle. The next step will be to hide them from casual browsers since only logged-in users are supposed to be able to annotate.

Thursday, December 12, 2013

Login/logout to Drupal remotely in PHP

Previously I explained how to login/logout to Drupal using Java. It's far easier in PHP because of the curl module, which can easily be added to any php installation. Most the http header fields are handled for you so the code is pretty simple. A couple of tricks though: you must set CURLOPT_FOLLOWLOCATION on the connection when reading the logout response or you'll just get a redirect. When logging in that doesn't matter as the cookie is returned immediately. And if you want to store the cookie you can use get_variable, set_variable to store it in the Drupal database. There probably isn't much need for the logout function but I included it anyway for completeness:

Then there is the little question of when the cookie crumbles. Since the above code reads the "expires" string from the initial cookie response it is easy to store the expiration string along with the cookie (so I return an array from remote_login), and then compare the current time with this value whenever you retrieve it. If it has expired it needs to be renewed:

Monday, December 9, 2013

Splitting and joining compressed folders in Linux

Github has a file limit of 50MB, and I had a repository with an archive of compressed files that exceeded that. So I thought it might be nice if I could split the archive up into segments and then rejoin and decompress them when they were needed. But how do to this efficiently?

There is plenty of advice available on the Web, and initially I was attracted to tar, which has a means of creating archive sections, originally used to create files for separate tapes. But it doesn't compress and split at the same time, and you need to write a clumsy script to rename each of the sections. So I went back to the method everyone said was bad: split. All you have to do is create a tar archive in the usual way:

tar czf archive.tar.gz myfolder

Now split it into numbered sections:

split -a 1 -n 5 -d archive.tar.gz archive.tar.gz.

And what you end up with is a set of 5 more or less equal-sized files numbered archive.tar.gz.0, archive.tar.gz.1, etc. (StackOverflow suggests using a pipe, but then the segments have to be of a fixed size, since the stream length can't be measured.) If you need more than 10 segments (-n option) increase the -a option, which specifies the length of the suffix. To sew them back up again all you need is:

cat archive.tar.gz.* > archive.tar.gz

The reason this works is that the wildcard orders the files via the suffix, so they will be joined up in the correct order. Otherwise you'd have to specify each file. Now to decompress:

tar xzf archive.tar.gz

The only drawback with this method is that you need to know the number of segments in advance. This is not a problem for me, as I can put it into a script and adjust it when needed, which will be rarely, if ever.