Tipps und Tricks zu Perl und CPAN-Modulen

Template-im-Template - Teil 2

Beitrag von Uwe am 30.03.2007 um 19:30 Uhr | 0 Kommentare

In Teil 1 habe ich gezeigt, wie man mit dem Template-Toolkit Templates erstellen kann.

Diese Methode war jedoch etwas umständlich. So mußte man entweder mit den Variablen tag_open und tag_close oder dem Konfigurationsparameter TAG_STYLE => 'star' arbeiten.

Beginnt man dagegen die Templates mit:

[% '[' _ '% TAGS star %' _ ']' %]

So kann im Template ganz normal [% und %] für die Template-Erzeugung und später dann [* und *] im erstellten Template verwendet werden. Es entfällt somit der Parameter TAG_STYLE => 'star' bei Template->new.

Das ganze funktioniert eigentlich recht einfach, man darf sich nur nicht von den verschiedenen Tags verwirren lassen. Ich illustriere dies an einem kleinen Beispiel:

[% '[' _ '% TAGS star %' _ ']' %]
[% FOREACH i = [1, 2, 3] %]
[* var_[% i %] *]
[% END %]

Aus diesem Template wird:

[% TAGS star %]
[* var_1 *]
[* var_2 *]
[* var_3 *]

Die erste Anweisung bewirkt das Umschalten auf den neuen Tag-Style (siehe Tabelle Teil 1).

Von den drei vorgestellten Methoden ist dies damit die einfachste und findet ab sofort auch in meinem Perl-Blog Verwendung.


Skalar oder Array-Referenz gleich behandeln

Beitrag von Uwe am 22.03.2007 um 21:50 Uhr | 5 Kommentare

Folgende Situation: Bei der Parameterübergabe erlaubt man sowohl einen Wert (Skalar) als auch mehrere Werte (Array-Referenz). Nun möchte man bei der Auswertung nicht immer zwischen Skalar und Array-Referenz unterscheiden, zumal ja sicherlich der einzelne Wert nur die Sonderform einer einelementigen Liste ist.

Da ich dies heute gleich mehrfach hatte, habe ich mal in Scalar::Util und List::Util bzw. List::MoreUtils nachgeschaut. Dort gibt es viele nützliche Funktionen für Listen (z. B. min, max und shuffle) und Skalare (z. B. blessed und weaken), für mein Problem war aber nichts dabei.

Dabei ist es eigentlich ganz einfach (auch wenn es sich für einen Perl-Anfänger vielleicht nicht so einfach liest): Handelt es sich um einen Skalar, wird eine einelementige Liste erstellt, ansonsten wird die Array-Referenz dereferenziert und der Liste zugewiesen. Das Ergebnis ist also in jedem Fall eine Liste.

Als kleines Modul verpackt sieht das ganze zum Beispiel so aus:

 1  package MyUtil;
 2  $VERSION = 0.001;
 3  
 4  use strict;
 5  use warnings;
 6  
 7  use base 'Exporter';
 8  our @EXPORT_OK = qw(_list);
 9  
10  
11  sub _list {
12      my ($data) = @_;
13      return unless $data;
14  
15      my @data = ($data);
16      @data = @$data if ref $data eq 'ARRAY';
17  
18      return @data if wantarray;
19      return \@data;
20  }
21  
22  
23  1;

Download: MyUtil.pm

In den Zeilen 7 - 8 wird die Subroutine _list als exportierbar gekennzeichnet.

Wird _list nichts oder ein falscher Wert (z. B. leerer String) übergeben, dann wird in Zeile 13 gleich zurückgesprungen. Das Ergebnis ist dann eine leere Liste (Listen-Kontext) oder undef (skalarer Kontext). Wer ein einzelnes leeres Element zulassen möchte, der muß stattdessen "return unless defined $data;" verwenden.

In Zeile 15 erfolgt die Erzeugung einer einelementigen Liste. Ob es sich um eine Array-Referenz handelt, wird in Zeile 16 geprüft. In diesem Fall wird diese dann dereferenziert.

In Zeile 18 wird mit wantarray geprüft, in welchem Kontext (skalar oder Liste) die Funktion _list aufgerufen wurde. Im Listen-Kontext ist wantarray wahr und es wird das Array @data zurückgegeben. Anderenfalls wird eine Array-Referenz zurückgegeben. Wem das zu kompliziert ist, der verwendet einfach "return @data;" - dann wird eben immer eine Liste zurückgegeben.

In Aktion sieht das Ganze dann so aus:

#!/usr/bin/perl

use warnings;
use strict;

use MyUtil qw(_list);


my @list = _list(1);

@list = _list([1, 2, 3]);

Download: use-list.pl


Datenaustauch Perl/PHP mit PHP::Serialization

Beitrag von Uwe am 13.03.2007 um 17:30 Uhr | 0 Kommentare

Möchte man zwischen Perl und PHP Daten austauschen, gibt es verschiedene Wege. YAML und WDDX sind zwei Vertreter eines sprachunabhängigen Datenaustauschformats. Natürlich kann man sich auch ein textbasiertes Format selbst ausdenken oder auf XML zurückgreifen.

Doch das soll alles kein Thema für diesen Beitrag sein: Ich möchte Euch PHP::Serialization vorstellen. Der große Vorteil: Auf PHP-Seite wird eine eingebaute Funktion verwendet (was bei über 3.000 Funktionen ja keine Überraschung ist).

Die beiden Funktionen heißen serialize und unserialize. Nachfolgendes PHP-Programm zeigt diese "in Aktion":

<?php

error_reporting(E_ALL);

$data = $_REQUEST['data'];
$data = stripslashes($data);

$array = unserialize($data);

print serialize($array);

?>

Download: echo.php

Auf der Perl-Seite kommt folgendes Skript zum Einsatz:

#!/usr/bin/perl

use warnings;
use strict;

use Data::Dump qw(dump);

use LWP::UserAgent;
use PHP::Serialization;

my $test = [{lang => 'perl', name => 'uwe'},
            {lang => 'php',  name => 'manu'},
           ];

my $serialize = PHP::Serialization::serialize($test);
#print $serialize;

my $ua   = LWP::UserAgent->new;
$ua->credentials('manu:80', # :443 bei https
                 'My Realm', 'manu', 'manu',
                );

my $res  = $ua->post('http://manu/echo.php', {data => $serialize});
#print $res->as_string;

my $data = PHP::Serialization::unserialize($res->content);

dump($data);

Download: echo.pl

Das Programm ist zugleich ein Beispiel, wie man Basic Authentication mit LWP::UserAgent nutzt. Der erste Parameter von credentials setzt sich aus Host und Port zusammen (dafür habe ich ein paar Versuche gebraucht).

Ansonsten hoffe ich, daß die beiden Programme selbsterklärend sind. Fragen bitte als Kommentar stellen (dann haben auch andere Leser etwas davon).

Und wer sich fragt, warum manu so oft vorkommt - das ist meine Freundin (und sie ist PHP-Programmiererin).


Google Webmaster-Tools: Links zusammenfassen

Beitrag von Uwe am 12.03.2007 um 13:15 Uhr | 0 Kommentare

Web-Crawl-Fehler

Ich habe mein Perl-Blog bei Google Webmaster-Tools angemeldet. Neben Web-Crawl-Fehlern erfahre ich dabei auch, unter welchen Suchbegriffen meine Seite gelistet wird und wer einen Link auf meine Seite gesetzt hat.

Externe Links

Doch gerade diese Übersicht der externen Links enthält viele Duplikate. Bei mir sind dies über 180 Links von der CPAN Autorenliste (es gibt über 200 CPAN-Mirror). Aber auch andere Blogs verlinken mehrfach auf meine Seite, vor allem wenn meine Seite in der Blogroll enthalten ist und der Link damit auf jeder Seite auftaucht.

Google exportiert auf Wunsch alle Links als CSV-Datei. Mit nachfolgendem Programm kann ich die Liste etwas übersichtlicher machen:

#!/usr/bin/perl

use warnings;
use strict;

use Data::Dump qw(dump);
use Text::xSV;


my $file = $ARGV[0] || 'links.csv';

my %rules = (qr/00whois\.(ht|x)ml/ => 'cpan',
            );


my $csv = Text::xSV->new;
$csv->open_file($file);
$csv->read_header;

# alle Zeilen einlesen
my %links = ();
my %tags  = ();
while (my $row = $csv->fetchrow_hash) {
    my $link = $row->{Links};

    # passt eine Regel?
    my $match = 0;
    while (my ($regex, $tag) = each %rules) {
        if ($link =~ $regex) {
            $tags{$tag}++;
            $match++;
        }
    }

    $links{$link}++ unless $match;
}

# verbleibende Links vereinigen
my $last = '';
my @links = sort keys %links;
foreach my $link (@links) {
    if ($last and $link =~ /^\Q$last\E/) {
        # vereinigen
        $links{$last} += delete $links{$link};
    } else {
        $last = $link;
    }
}

print dump(\%tags, \%links);

Download: google-links-summary.pl

Das Skript bekommt als ersten Parameter den Namen der CSV-Datei übergeben (oder Ihr nennt die Datei links.csv). Im %rules-Hash können bestimmte Links über reguläre Ausdrücke getaggt werden. Wer nicht gerade CPAN-Autor ist, kann diese Zeile rauslöschen (es sollte dann my %rules = (); stehenbleiben).

Die Ausgabe ist noch etwas kümmerlich und das Programm unterscheidet auch zwischen http und https sowie Domainnamen mit und ohne www, aber vielleicht kann es Euch als Ausgangsbasis dienen.

Weiterhin ist es ein schönes Beispiel für Text::xSV. Mir gefällt an diesem Modul besonders der Hash-Zugriff auf die einzelnen Datenfelder, auch wenn ich in diesem Fall nur die Links-Spalte nutze.

Ich freue mich über Eure Kommentare und Anregungen.


Standard-Ausgabe aufzeichnen mit IO::Capture::Stdout

Beitrag von Uwe am 12.03.2007 um 08:30 Uhr | 0 Kommentare

Wenn man die Standard-Ausgabe eines externen Programms (oder Perl-Skripts) aufzeichnen möchte, kann man u. a. Backticks (`...`) verwenden. Ich würde in diesem Fall lieber zu IPC::Run3 greifen (aber dazu mehr in einem späteren Beitrag).

Handelt es sich bei dem auszuführenden Programm-Code jedoch um ein Perl-Modul und es kann vielleicht nicht als externer Prozeß gestartet werden (z. B. weil es eine lange Initialisierungsphase hat), dann kommt IO::Capture::Stdout ins Spiel:

#!/usr/bin/perl

use warnings;
use strict;

use Data::Dumper;
use IO::Capture::Stdout;


# Aufzeichnung beginnen
my $capture = IO::Capture::Stdout->new;
$capture->start;

# hier jetzt zu "ueberwachenden" Code ausfuehren
{
    print "Erstelle Datenstruktur\n";
    my $data = {a => 1, b => 2, c => 3};

    print Dumper($data);
}

# Aufzeichnung beenden
$capture->stop;

print "Es wurde aufgezeichnet:\n";
print "=======================\n";
print join('', $capture->read);

Download: capture-stdout.pl

Nachdem ein IO::Capture::Stdout-Objekt angelegt wurde, kann mit start() und stop() die Aufzeichnung begonnen bzw. angehalten werden. Im Anschluß kann mit read() die Standard-Ausgabe gelesen werden.

Mit IO::Capture::Stderr steht ein Modul zum Aufzeichnen der Standard-Fehlerausgabe zur Verfügung. IO::Capture::Extended erweitert die beiden um zusätzliche Funktionalität (Mustererkennung, Anzahl Linien und Ausgaben).


März: Monat der PHP-Bugs

Beitrag von Uwe am 01.03.2007 um 15:30 Uhr | 1 Kommentar

PHP-Sicherheitsspezialist Stefan Esser hat den März zum Monat der PHP-Bugs erkoren. Dabei wird jeden Tag (mindestens) ein Bug in PHP veröffentlicht.

Doch es geht nicht um schlecht programmierte PHP-Anwendungen - Sicherheitslücken in Anwendungen gibt es in jeder Sprache. Nein, Fehler in der Sprache PHP selbst ("core") stehen im Mittelpunkt.

Besonders pikant: Die drei heute veröffentlichten Schwachstellen sind seit Jahren den PHP-Entwicklern bekannt - werden aber nicht gefixt.

Stefan Esser war bis Ende letzten Jahres Mitglied im "PHP Security Response Team". Als Gründe für seinen Rücktritt nannte er die langen Reaktionszeiten der PHP-Entwickler auf Sicherheitslücken. Außerdem war jeder auf seiner Seite, wenn er Sicherheitslücken den Usern (also "normalen" PHP-Entwicklern) zuschrieb. Kritisierte er aber die Sicherheit der Sprache PHP selbst, wurde er sofort ausgegrenzt.

Stefan's Blog ist empfehlenswert für jeden Entwickler von Web-Anwendungen (nicht nur in PHP geschrieben).