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;
}