Perl 5.21 cpanm fails to install DBIx::Connector

As you may find if you use a very recent environment with perlbrew, The latest Perls do not contain CGI.pm, so when you attempt to use cpanm (CPAN minus) to install a module like DBIx::Connector,  it will fail and you will see in the created log file a line that contains:

Can't locate CGI.pm in @INC (you may need to install the CGI module)

This turns out to be, if you trace it,  because the test module Test::MockModule still has a CGI based test.  You can make the desired module install by forcing the Test component to install anyway:

$ cpanm Test::MockModule --force
(succeeds)
$ cpanm DBIx::Connector
(succeeds)

That’s really all there is to it.

WPJax September 2014

My notes from this month’s “WordPress Sampler” meeting of WPJax at Modis. Folks in our group range from business owners and students to advanced developers. Here are some of their recommendations and insights, primarily from Elizabeth, Clint, and Jonathan.

Themes and Development

  • What WP Theme is That? is especially useful when dissecting what other webmasters have done in building their themes.
  • BluChic has WordPress themes for sites, intended for a more feminine look.
  • Creative Market is WordPress themes: Hundreds, nay thousands! At reasonable prices.
  • The Avada multi-purpose, responsive theme. Comes highly recommended as being one of the most easily customizable and dependable. This is Theme Forest’s best-selling theme.
  • Canvas, WooTheme’s “flagship” theme. Somewhat pricier than the other themes we discussed, this one is just as easy, but a little better for folks who aren’t afraid to write just a handful of PHP statements to tweak the perfect theme’s functionality.
  • Cobalt Apps promises to break down some of the barriers that normally require a bit of coding. It builds child themes for the Genesis theme without having to dig too deeply into PHP or HTML / CSS.

Stock Photos and Shopping

  • Death to the Stock Photo sends you free, royalty-free photos. you receive an monthly email. Or subscribe to their entire library for a small fee.
  • The Dollar Photo Club has High-resolution and vector images, royalty-free, always $1.00 USD each.
  • Embed items in your marketplace from “Square” (using an <iframe>) for easy shopping carts right in your site

Sites:

  • Cafe bon Appetit is a site partly coded by Jonathan, showing how something built for large institutions like a university can still be attractive and appealing. The main page operates several sites inside, each catered to a college or corporation cafeteria. This ties together databases, design, and working through procedural and regulatory challenges.
  • Jonathan also showed us the behind-the-scenes operation of a new site for a major office furniture designer/manufacturer. The site’s theme and plugins enable functions in the WordPress admin screens that permit building nested database-driven detail boxes in the post/page composition process without any coding whatsoever.

Jonathan also shared his experience finding, tracking, and repairing a bug in the WordPress Core that has existed for years.

I encourage you to contact Clint, Jonathan, or Elizabeth for your WordPress design needs.  And thanks again to Modis and to Tim and Rebecca for the venue and the refreshments!

Good questions and a bunch of tips from everyone else attending rounded out this excellent session. We’ve got a great group going, and much talent on the move here in the “Bold New City of the South!”

SSH login without a password

If you are using Linux and OpenSSH to automate your tasks, you will almost always find it easier to have an automatic login that does not require a password. This is especially true if you are using something like rcp for easy file transfers.

Let’s configure SSH (version 2) with a secure key to bypass password login from host A / user a to Host B / user b.

Step by step

First login on system A as user a and generate a pair of authentication keys. Do not enter a passphrase:

a@A:~> ssh-keygen -t rsa
Generating public/private rsa key pair.
Enter file in which to save the key (/home/a/.ssh/id_rsa): 
Created directory '/home/a/.ssh'.
Enter passphrase (empty for no passphrase): 
Enter same passphrase again: 
Your identification has been saved in /home/a/.ssh/id_rsa.
Your public key has been saved in /home/a/.ssh/id_rsa.pub.
The key fingerprint is:
3e:4f:05:79:3a:9f:96:7c:3b:ad:e9:58:37:bc:37:e4 a@A

Now use ssh to create a directory ~/.ssh as user b on B. (The directory may already exist, which is fine, although in that case you may have to manually reset the mode with chmod 700 ~/.ssh ):

a@A:~> ssh b@B mkdir -p .ssh -m 700
b@B's password: 

Finally append a’s new public key to b@B:.ssh/authorized_keys and enter b’s password one last time:

a@A:~> cat .ssh/id_rsa.pub | ssh b@B 'cat >> .ssh/authorized_keys2'
b@B's password: 

From now on you can log into B as b from A as a without password:

a@A:~> ssh b@B

If that does not work, from system A do:

a@A:~gt; ssh b@B 'chmod 640 ~/.ssh/authorized_keys2'

and you should be good to go.

Mojolicious and DBI handles

From http://toroid.org/ams/etc/mojolicious-db-handles we find this bit of code:

sub startup {
  my $app = shift;

  my ($user, $pass);
  # read $user and $pass from config file
  (ref $app)->attr(db => sub {
    DBI->connect("dbi:Mysql:database=$db",
                 $user, $pass)
    }
  );
}

The concept is that Morbo, or Starman, or whatever PSGI server is running your program, can use any kind of forking, but each instance of your program will execute the startup code and create its own database handle.

Some of the code is not too obvious:

  • ref $app returns the class name of the main object. In my tests, replacing this line with the more obvious: $app->attr(db =>… worked just fine. EDIT: Apparently the ref business is because he wanted the class method, although because there isn’t an instance method by the same name of attr, it doesn’t matter.
  • The attr(...) call is a Mojolicious method (see here) that is described as, “Create attribute accessor for hash-based objects.” What that means is, the call actually creates a function definition as a string, and then does an eval of the string, thereby creating the named function (db in this case) in the given namespace (ref $app) in this case.

And here’s how you get the data back out:

  $app->get('/test')->to(cb =>
               sub{ 
               my $self = shift;
               $Data::Dumper::Indent = 1;
               $self->render( 'text' => "TEST: ATTR of foo" . $self->app->foo .
                    "\n<pre>\n" . Dumper($self) . "</pre>" );
               });

It’s really a better idea to use DBIx::Connector anyway, but the startup attribute trick might come in handy elsewhere.  One note on DBIX::Connector − Under the heading, Execution Methods we see the code:

  $conn->run(sub { $_->do($query) });

It is not documented, but by reading the source (let’s hear it for free software!) what happens is that $_ is set, via the «local» keyword, to temporarily be the database handle (dbh) of the connection within execution of the code reference.

Thanks to mst and others on #perl for the assistance.

Postfix on bare CentOS install

Starting from scratch with a new CentOS 7 Linode, I found that iptables is set by default to block (although not reject) packets to the IMAP and POP3 services.

Rackspace has a good primer on setting up Dovecot that includes these instructions, but here’s the short answer:

sudo iptables -I INPUT 2 -p tcp --dport 587 -j ACCEPT
sudo iptables -I INPUT 3 -p tcp --dport 110 -j ACCEPT
sudo iptables -I INPUT 4 -p tcp --dport 143 -j ACCEPT
sudo iptables -I INPUT 5 -p tcp --dport 993 -j ACCEPT
sudo iptables -I INPUT 6 -p tcp --dport 995 -j ACCEPT
sudo /etc/init.d/iptables save
sudo /etc/init.d/iptables restart

That adds a rule to accept the IMAP and POP ports, both the regular and SSL versions. Then we save the chain table and restart iptables. Now you should be able to get in:
$ telnet myhost.wlindley.com imap
Trying myhost.wlindley.com... Connected to myhost.wlindley.com. Escape character is '^]'. * OK [CAPABILITY IMAP4rev1 LITERAL+ SASL-IR LOGIN-REFERRALS ID ENABLE IDLE STARTTLS LOGINDISABLED] Dovecot ready.

Perlbrew a 64-bit Perl on Linode

For some reason, even the 64-bit kernel on my Linode wasn’t sufficient for perlbrew to generate a 64-bit Perl. I was able to get one by doing:

perlbrew install 5.20.0 --64int

which resolved the problem I was having trying to install Minion with cpanm, namely the error “Perl with support for quads is required!” (from this bit of code, thanks mst on undernet #perl)

Moose data types

A quick reference to the built-in data types you can use in Moose. Use these when declaring a class, as with ‘isa':

 Data Type Possible Values
Any Note: [`a] is an optional extension
which means any Type 
Item
Bool undef, 0, empty string, or 1
Maybe[`a] undef or [`a]. e.g.: Maybe[Str]
Undef must be undef
Defined must not be undef
Value
Str string
Num looks like a number
Int integer
ClassName string that is name of a class
RoleName …of a role
Ref
ScalarRef[`a] e.g., ScalarRef[Value]
ArrayRef[`a]
HashRef[`a]
CodeRef
RegexpRef
GlobRef
FileHandle IO::Handle or Perl filehandle
Object any blessed reference
any Class e.g., MyClass or SQL::Abstract
assuming your program uses them

Full details, examples, and advanced capabilites are explained at https://metacpan.org/pod/Moose::Manual::Types

Cleanly create SQL with SQL::Abstract::More

Some years ago now, I had written my own wrapper around DBI to make common SQL statements easier to write. Awhile back I found SQL::Abstract and recently revisited some old code to bring it up to the modern era. I found that the related SQL::Abstract::More was almost a direct replacement for what I had written − except with more features and better debugged. Here’s an example:

#!/usr/env/perl

use strict;
use warnings;

use SQL::Abstract::More;

my $sqla = SQL::Abstract::More->new;

# More maintainable with named parameters.
($stmt, @bind) = $sqla->select(
    -columns => [qw(listname id description from_email),
         'mailing_list.active|active',
         "COUNT(subscriber.person_id)|subcribercount",
    ],
    -from => [qw(mailing_list subscriber)],
    -where => {'subscriber.list_id' => {'=', \ 'mailing_list.id'},
           'subscriber.active' => {'<>', \ 0}
    },
    -group_by => "list_id",
    );

print "$stmt\n" . join(',',@bind) . "\n";

The Above example produces the code ready to pass to SQL:

    SELECT listname, id, description, from_email, 
      mailing_list.active AS active, 
      COUNT(subscriber.person_id) AS subcribercount
    FROM mailing_list, subscriber
    WHERE ( ( subscriber.active <> 0 AND 
      subscriber.list_id = mailing_list.id ) ) 
    GROUP BY list_id

After that, it’s just a matter of execution:

my $sth = $dbh->prepare($stmt);
$sqla->bind_params($sth, @bind);
$sth->execute;

You could do the same thing with SQL::Abstract itself, but you have to use somewhat-undocumented features for the “as” and “group by” pieces. Specifically, you can use a scalar reference for a literal field name in the columns part, and shove the “group by” clause into the order field; but you’ll have to build the group clause yourself:

use SQL::Abstract;

my $sql = SQL::Abstract->new;

my ($stmt, @bind) =
    $sql->select([qw(mailing_list subscriber)], 
		 [qw(listname id description from_email),
		  \ "mailing_list.active AS active",
		  \ "COUNT(subscriber.person_id) AS subcribercount"
		 ],
		 {'subscriber.list_id' => \ '= mailing_list.id',
		  'subscriber.active' => \ '<> 0'},
		 "asc GROUP by list_id"
    );
print "$stmt\n" . join(',',@bind) . "\n";

Altogether, SQL::Abstract::More is superior.

Thoroughly Modern Perl

 

An overview of:

  • A bit of Perl history
  • Perl 5 −vs− 6
  • Perlbrew: Running modern and bleeding-edge programs on the same system as legacy
  • Unicode and UTF-8 in the Web world, and how to sort and capitalize names that are more than just English.
  • Perl 5’s heritage Object system −vs− the “new” Moose
  • Databases: Old-school SQL with injection vulnerabilities, SQL::Abstract, and DBIx
  • Tying it all together: Mojolicious

Download/view:

Finding shortest time or distance with Graph::Undirected

The Graph module on CPAN is mostly well documented. One place it falls short is explaining that not only can you create weighted edges, you can also use various edge attributes to calculate different minimum spanning trees (via Dijkstra’s algorithm) based on any given attribute.

Here we create a small network of railway lines between cities, from the example on page 9 in John Armstrong’s “Track Planning for Realistic Operation” (Kalmbach Books, 1986):

    • There are two routes from A to D: A-B-D, and A-C-D.
    • Here we assume that the route via B is longer but faster, and via C shorter but slower.
    • The line continues from D through E and G to H.
    • There is a branch line from E to F.

We calculate the shortest route by distance, and then by time.

Note the undocumented attribute parameter to SPT_Dijkstra().

#!/usr/bin/env perl
use strict;
use warnings;

use Graph::Undirected;

my $station_graph = Graph::Undirected->new();

# Add a few cities

$station_graph->add_path(qw(A B D E G H)); # first route via B
$station_graph->add_path(qw(A C D));	   # second via C
$station_graph->add_path(qw(E F));	   # branch route

# Define characteristics of the alternate routes

# Longer but faster
$station_graph->set_edge_attribute(qw(A B distance), 150);
$station_graph->set_edge_attribute(qw(A B time), 3.1);

# Shorter yet slower
$station_graph->set_edge_attribute(qw(A C distance), 120);
$station_graph->set_edge_attribute(qw(A C time), 3.3);

# Find spanning tree in distance
my $sptg1 = $station_graph->SPT_Dijkstra(attribute => 'distance');

print "Shortest Distance: ". join('|',$sptg1->SP_Dijkstra('A','H'));
print "\n";

# Clear cache (required for recalculation)
$station_graph->SPT_Dijkstra_clear_cache();

# Find spanning tree in time
my $sptg2 = $station_graph->SPT_Dijkstra(attribute => 'time');

print "Shortest Time:     ". join('|',$sptg2->SP_Dijkstra('A','H'));
print "\n";

1;

When run, this shows as follows:

$ perl Graph.pl 
Shortest Distance: A|C|D|E|G|H
Shortest Time:     A|B|D|E|G|H

If you want to use a directed graph, create the graph by replacing that line with:

my $station_graph = Graph::Directed->new();

and be sure to specify the starting node for the spanning trees:

my $sptg1 = $station_graph->SPT_Dijkstra(attribute => 'distance', first_root => 'A');
…
my $sptg2 = $station_graph->SPT_Dijkstra(attribute => 'time', first_root => 'A');

"Si datur citrea, sucus faciunt" (When life gives you lemons, make lemonade)