Tom2 (der authentifizierte): Mein erstes Skript

Beitrag lesen

Hi Leute

Nach meinen ersten paar Perl-Basteleien habe ich nun ein Skript geschrieben, welches mir wirklich sehr gefällt! Es handelt sich dabei um einen CGI-LibXSLT-Adapter. Keine Frage, es ist sehr trivial, aber ich habe CPAN sinnvoll genutzt und auch die UTF-8-Codierung funktioniert. Nun habe ich aber noch ein paar Fragen an erfahrene Perl-Programmierer.

Das Skript nimmt die Parameter p (Pfad der XML-Datei) und s (Pfad des XSL-Stylesheets) entgegen und gibt das transformierte Resultat zurück. Falls p keine XML-Datei, sondern nur eine Textdatei ist, dann wird ein  HTML-Dokument daraus gebaut. Das Problem ist nun, dass für p auch absolute Pfade, sowie relative Pfade mit einem '../' erlaubt sind. Das möchte ich verhindern. Wie macht man das Plattformübergreifend und ausreichend sicher? Möglichkeiten, welche mir einfallen sind:

  • Absolute Pfade ($path =~ /^/.+?/) ignorieren
  • Den Pfad immer in einen absoluten transforieren und prüfen, ob er unterhalb eines bestimmten Verzeichnisses liegt.

Der zweite Knackpunkt steht unter dem Kommentar Load Data:
Ist $path eine Textdatei, jedoch keine XML-Datei, dann schlägt der Versuch die Datei zu laden fehl und $xml->toString() ist leer. Es wäre wohl besser, vor dem Laden zu prüfen, ob es sich um XML-Daten handelt.
Aus dem Bauch heraus würde ich die ersten sagen wir mal 100 Zeichen der angeblichen XML-Datei einlesen und dann folgenden Pseudocode anwenden:

Wenn $xml_fragment '<?xml' enthällt
    Datei als XML laden
Andernfalls wenn $xml_fragment '<html' enthällt
    Datei als HTML laden
Sonst
    Textdatei in HTML umwandeln

Verhällt diese Lösung? Oder handle ich mir damit neue Probleme ein?

Natürlich bin ich auch um sonst jeden Tip froh, der meinen Perl-Code verbessert.

Gruss & Dank

Tom2

Hier ist mein Code:

#!/usr/bin/perl -w

This is a CGI-Adaptor for LibXSLT.

To get the required modules, do the following:

tom@mac> sudo perl -MCPAN -e shell

cpan> install XML::LibXSLT

Have fun!

Development only

use strict;
use warnings;
use CGI::Carp qw(fatalsToBrowser);

Character encoding

use utf8;
use encoding 'utf8';

Common Gateway Interface

use CGI;

XML & XSLT

use XML::LibXML;
use XML::LibXSLT;

Now flip the script:

Prepare the output stream

my $cgi = new CGI;
$cgi->charset('utf8');
print $cgi->header(-type=>'text/html');

Get parameters

my $path  = $cgi->param('p');
if (not (-T "$path")) {
 $path = 'index.html';
}
my $style = $cgi->param('s');
if (not -T "$style") {
 $style = 'xsl/div.xsl';
}

Initialize tools

my $parser = XML::LibXML->new();
$parser->load_ext_dtd(0);
$parser->validation(0);
$parser->recover(1);
$parser->keep_blanks(1);
my $xslt = XML::LibXSLT->new();

Load data

my $xml = $parser->parse_file($path);
if ($xml->toString() eq '') {
 $xml = text2html($path);
}
my $xsl = $xslt->parse_stylesheet_file($style);

Return the output

my $results = $xsl->transform($xml);
print $xsl->output_as_chars($results);

This function returns a text file within a HTML DOM document

sub text2html {
 my $source = shift;
 # Read the text file
 my $file = '<html xmlns="http://www.w3.org/1999/xhtml"><body><pre>';
 open(FILE, $source);
 while (my $buffer = <FILE>) {
  if (!utf8::is_utf8($buffer)) {
   utf8::decode($buffer);
  }
  $file .= $buffer;
 }
 close(FILE);
 $file .= '</pre></body></html>';
 # Generate XHTML document
 my $xml = XML::LibXML::Document->new('1.0', 'utf-8');
 $xml->createInternalSubset('html',
  "-//W3C//DTD XHTML 1.0 Strict//EN",
  "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd");
 my $root = $xml->createElement('html');
 $root->appendChild($parser->parse_balanced_chunk($file));
 $xml->setDocumentElement($root);
 return $xml;
}