Benutzer:Kirmse/Anmeldekontrolle

Aus Delixs
Version vom 4. Oktober 2008, 19:19 Uhr von Kirmse (Diskussion | Beiträge) (Quelltext von smbstatus2html)
(Unterschied) ← Nächstältere Version | Aktuelle Version (Unterschied) | Nächstjüngere Version → (Unterschied)
Zur Navigation springen Zur Suche springen

Dieses Script ist eine Neuimplementierung von smbstatus2html.cgi von Rene van Bevern.

<source lang="perl">

  1. !/usr/bin/perl

use warnings; use strict;

use CGI::Carp qw(fatalsToBrowser); use Net::LDAP;

  1. ========================== Konfigurationsbereich ========================

my %config = (

  1. hier wird angegeben, ob fuer Lehrer das Login angezeigt werden soll oder
  2. statt dessen ein Ersatzstring (siehe bei UNVISIBLESTRING). Dabei bedeutet
  3. no: ausblenden, yes: anzeigen des Lehrerlogins

TEACHER => 'yes',

  1. geben Sie hier an, fuer welche Accounts, gegebenenfalls zusaetzlich bzw. auch
  2. alternativ zu 'lehrer', das Login nicht angezeigt werden soll.
  3. Format: UNVISIBLE => [ 'ffeuerstein', 'hkirmse' ];

UNVISIBLE => [ ],

  1. hier wird angegeben, was in das Feld der Tabelle eingetragen wird, wenn das
  2. Login nicht angezeigt werden soll, z.B. fuer den Admin. Es sollte kein leerer
  3. String eingetragen werden, weil manche Browser dann die Tabellen nicht
  4. vollstaendig zeichnen. Dieser String kommt nur im Feld Account zur Wirkung.

UNVISIBLESTRING => 'xxxxx',

  1. hier wird angegeben, ob nur die Rechner angezeigt werden, die gerade genutzt
  2. werden (also die unbenutzten PCs ausgeblendet werden sollen). Dabei bedeutet
  3. no: ausblenden, yes: anzeigen der unbenutzten Rechner

ALL_PC => 'yes',

  1. hier wird angegeben, was in das Feld der Tabelle eingetragen wird, wenn der
  2. Rechner nicht besetzt ist. Dieser Parameter hat keine Wirkung, wenn bei
  3. ALL_PC => 'no'; eingetragen wird. Es sollte kein leerer String eingetragen
  4. werden, weil manche Browser dann die Tabellen nicht vollstaendig zeichnen.
  5. Dieser String kommt im Feld IP-Adresse und im Feld Account zur Wirkung.

ALTERNATE_STRING => ' ',

  1. An Schulen wo der Mailserver zur Weitergabe von Informationen genutzt wird,
  2. kann die Anzeige des Logins als Maillink erfolgen. Dabei bedeutet
  3. no: kein Maillink, yes: mit Maillink

MAIL_URL => 'yes',

  1. hier wird angegeben, ob nach Mehrfachanmeldungen gesucht werden soll.
  2. dabei bedeutet no: nicht suchen, yes: nach Mehrfachanmeldungen suchen

MULTIPLE_LOGIN => 'yes',

  1. hier wird angegeben, mit welcher Hintergrundfarbe die Zelle fuer Arbeitsplatz
  2. bei Mehrfachanmeldungen im Netz erscheinen soll.

IM_NETZ => '#F9DED9',

  1. hier wird angegeben, mit welcher Hintergrundfarbe die Zelle fuer Arbeitsplatz
  2. bei Mehrfachanmeldungen im Raum erscheinen soll. Falls Mehrfachanmeldungen im
  3. Netz und im Raum vorliegen, kommt die Mehrfachanmeldung im Raum zur Wirkung.

IM_ROOM => '#EEA395', );


  1. hier können sie das Format fuer das Datum und die Uhrzeit angeben. Die
  2. Platzhalter %%tag%%, %%monat%%, %%jahr%%, %%stunde%%, %%minute%%, %%sekunden%%
  3. werden durch aktuellen Werte ersetzt, wobei alle Werte der Zeit zweistellig sind
  4. durch das vorgegebene Format entsteht z.B. "1.1.2008 13:41:05"

my $format = '%%tag%%.%%monat%%.%%jahr%% %%stunde%%:%%minute%%:%%sekunden%%';


  1. ========================== Fehlermeldungen in der Tabelle ===============

my $fehler1 = "Es liegen überhaupt keine Anmeldungen am Fileserver vor"; my $fehler2 = "Es liegen in diesem Raum keine Anmeldungen am Fileserver vor";


  1. ========================== HTML-Bereich =================================
  1. Die generierte HTML-Seite wird zusammengesetzt aus dem Kopf, der (eigentlichen)
  2. Tabelle und dem Fuss. Hier wird die Variable $head als HERE-Dokument bereitgestellt.
  3. Ab der 2. Zeile, die mit: "<!doctype html ..." beginnt, ist alles reines HTML.
  4. Sie können damit ohne Perlkenntnisse das Aussehen der Seite beeinflussen.
  5. Beachten Sie, dass %%aufrufer%%, "%%rechner%%", "%%raum%% und %%datum%% durch
  6. das Script durch die aktuellen Werte ersetzt werden

my $head =<<'KOPF'; <!doctype html public "-//W3C//DTD HTML 4.0 //EN"> <html> <head> <title>Anmeldekontrolle</title> <meta name="author" content="Hans-Dietrich Kirmse, Rene van Bevern"> <style type="text/css"> </style> </head> <body background="/online/whttxtr2.jpg" text="#000000" bgcolor="#FFFFFF" link="#0000FF" alink="#0000C0" vlink="#FF0000">

%%aufrufer%% am PC "%%rechner%%" im Raum "%%raum%%" %%datum%%

Folgende Benutzer dieses Raumes sind angemeldet:

KOPF


  1. die Variable $foot sollte normalerweise nicht geändert werden, da nur Copyrightvermerk.
  2. Falls dieser an irgendeiner anderen Stelle erscheint, ist dagegen natürlich nichts einzuwenden.

my $foot =<<'FUSS';

Arbeitsplatz IP-Adresse Account

© <a href="mailto:hd.kirmse@gmx.de">HD. Kirmse</a>, René van Bevern,   ERG Saalfeld/Thüringen, smbstatus2html Version 0.7 - Dezember 2007

</body> </html> FUSS


  1. wenn keine Anmeldungen am Fileserver vorliegen, dann wird folgende Tabelle
  2. zurueckgegeben, der Platzhalter %%fehler%% wird dann ersetzt

my $error =<<'FEHLER';

%%fehler%% FEHLER

  1. ========================== weitere globalen Variablen ===================

my $ldap_base; # wird z.B. zu 'dc=erg,c=de' my $ip; # IP des Lehrer-PCs my $teacher; # Login des aufrufenden Lehrers my @teacher; # die Logins der Lehrer my $room; # der Raum my %pcs; # die PCs in diesem Raum my @output; # die Ausgabe von smbstatus my @daten; # Daten von smbstatus my %net_connection; # Anmeldungen pro User im Netz my %room_connection; # Anmeldungen pro User im Raum my $date; # Datum und Zeit des Aufrufs my $table; # die Tabelle der HTML-Seite my $ref; # temporaere Variable

  1. ========================== Hauptprogramm ================================
  1. wir holen uns das Login des Lehrers, von dem das Script aufgerufen wurde

$teacher = $ENV{REMOTE_USER}; defined($teacher) or die "es liegt keine Anmeldung am Apache vor, $!\n";

  1. wir holen uns die IP des Rechners, von dem das Script aufgerufen wurde

$ip = $ENV{REMOTE_ADDR}; defined($ip) or die "ein unerwarteter Fehler ist aufgetreten, $!\n";

  1. wir holen uns die Lehrer und den Raum und die Rechner fuer diesen Raum

($ref, $room, %pcs) = &get_teachers_and_pcs($ip); # vom LDAP @teacher = @{$ref};

  1. wir rufen 'smbstatus' auf

@output = `smbstatus`; chomp(@output);

  1. jetzt erzeugen wir die Daten zur Bearbeitung von den aktuell angemeldeten PCs.
  2. uns interessieren von @output nur Zeilen, wo am Ende eine Klammer mit der IP ist
  3. Die Daten haben folgende Struktur: $daten[x] = \($ip, $login, $gruppe, $rechner);

@daten = &get_data(@output);

  1. falls ueberhaupt keine Anmeldungen am Fileserver vorliegen, brechen wir hier ab

if (scalar @daten == 0) { $error =~ s/%%fehler%%/$fehler1/; $table = $error; goto AUSGABE; }

  1. wir ermitteln die Anmeldungen pro User im Netz

if ($config{MULTIPLE_LOGIN} eq 'yes') { %net_connection = &get_anz_pro_user(@daten); }

  1. wir reduzieren jetzt (anhand der IP) die Daten auf die Anmeldungen im Raum

@daten = &filtern_nach_raum(\@daten, \%pcs);

  1. falls keine Anmeldungen am Fileserver in diesem Raum vorliegen, brechen wir ab

if (scalar @daten == 0) { $error =~ s/%%fehler%%/$fehler2/; $table = $error; goto AUSGABE; }

  1. wir ermitteln die Anmeldungen pro User im Raum

if ($config{MULTIPLE_LOGIN} eq 'yes') { %room_connection = &get_anz_pro_user(@daten); }

  1. wenn die nichtbenutzten PCs dieses Raumes mit aufgelistet werden sollen,
  2. dann werden für diese PCs "Pseudo-Datensaetze" bereitgestellt

if ($config{ALL_PC} eq 'yes') { @daten = &gen_data_for_all_pcs(\%config, \%pcs, @daten); }

  1. wir sortieren die Datensätze nach den Rechnernamen

@daten = sort { vergleich_rechner($a,$b) } @daten;

  1. falls die Lehrer nicht angezeigt werden sollen
  2. werden jetzt die Logins durch einen Ersatzstring ersetzt

@daten = &substitute_teacherlogins(\%config, \@teacher, @daten);

  1. wir bauen jetzt die eigentliche Tabelle zusammen
  2. es wird hier nur das HTML herumgestrickt (incl. Mehrfachanmeldung, Maillink)

$table = &get_table( \@daten, \%config, \%net_connection, \%room_connection ); AUSGABE:

  1. wir holen uns Datum und Uhrzeit (wird im Kopf der HTML-Seite angezeigt)

$date = &datum($format);

  1. wir bearbeiten den Kopf

$head =~ s/%%aufrufer%%/$teacher/; $head =~ s/%%datum%%/$date/; $head =~ s/%%rechner%%/$pcs{$ip}/; $head =~ s/%%raum%%/$room/;

  1. wir schicken die Seite zum Apache

print "Content-type: text/html\n\n"; print $head; print $table; print $foot;

  1. ========================== Funktionen ===================================
  1. --------------------------------------------------------------------
  2. Funktion: Hilfsfunktion zur Ermittlung der Suchbasis
  3. Aufruf: $ldap_base = &_get_ldapbase;
  4. Input: --
  5. Output: Die Suchbasis des LDAP z.B. 'dc=erg,c=de'
  6. Update: 13.08.2007
  7. --------------------------------------------------------------------

sub _get_ldapbase { my $ldap_base = ; # wir durchsuchen die ldap.conf mit einer Regex open DATEI, '<', '/etc/ldap.conf' or die "konnte ldap.conf nicht oeffnen, $!\n"; while (my $zeile = <DATEI>) { if ($zeile =~ m/^\s*base\s+(\w.*\w)\s*$/) { $ldap_base = $1; last; } } close DATEI; return $ldap_base; }

  1. --------------------------------------------------------------------
  2. Funktion: es werden aus dem LDAP zu einer IP der Raum und die Rechner,
  3. Aufruf: (\@teachers,$raum,\%pc) = &get_teachers_and_pcs($ip);
  4. Input: $ip = die IP-Adresse des Lehrerrechners
  5. Output: \@logins = Referenz auf Liste der Lehrerlogins
  6. $raum = Name des Raumes (Rechnergruppierung)
  7. \%pcs = alle Rechner des Raumes (IP => Name)
  8. Update: 16.12.2007
  9. --------------------------------------------------------------------

sub get_teachers_and_pcs { my $ip = shift; my ($ldap_base, $ldap, $mesg, $entry, $dn, $pc, $suchbasis, %rechner, $tmp, $raum, @teacher); # wir verbinden uns mit den LDAP $ldap = Net::LDAP->new('127.0.0.1',version => 3) or die "$@"; $ldap->bind or die "konnte mich nicht mit dem Server verbinden"; # wir holen uns die Suchbasis $ldap_base = &_get_ldapbase; # wir holen uns die Lehrer $mesg = $ldap->search( base => "ou=LEHRER,o=SCHULE,$ldap_base", filter => "gidNumber=101", attrs => [ 'uid' ], scope => "sub"); mesg->code and die $mesg->error; # wir stecken die Daten aus den Entries in einen "normalen" Hash @teacher = (); foreach my $entry ($mesg->entries) { push @teacher, $entry->get_value('uid'); } # wir holen uns den Raum zu der IP ($ip) $mesg = $ldap->search( base => "cn=DHCP Service Config,o=DHCP,$ldap_base", filter => "dhcpStatements=fixed-address $ip", attrs => [ 'dhcpHost' ], scope => "base"); mesg->code and die $mesg->error; # wir holen uns den DN ($entry) = $mesg->entries or die "konnte keinen dhcpHost finden"; $dn = $entry->dn; # wir spalten vom DN den Rechnernamen ab, den Rest nehmen wir gleich als Suchbasis ($pc, $suchbasis) = $dn =~ /^cn=([^,]*),(.*)$/; # wir holen uns die Rechner (sind im DN) und IPs zu diesen Raum $mesg = $ldap->search( base => $suchbasis, filter => "objectClass=dhcpHost", attrs => [ 'dhcpStatements' ]); $mesg->code and die $mesg->error; # wir stecken die Daten aus den Entries in einen "normalen" Hash %rechner = (); foreach my $entry ($mesg->entries) { $dn = $entry->dn; ($pc) = $dn =~ /^cn=([^,]*),/ ; # die Klammer ist der Rechnername $tmp = $entry->get_value('dhcpStatements'); ($ip) = $tmp =~ /fixed-address (.*)$/; $rechner{$ip} = $pc; } # wir holen uns noch den Raum ($raum) = $suchbasis =~ /^cn=([^,]*),/ ; # die Klammer ist der Raum # wir trennen uns vom LDAP $ldap->unbind; return (\@teacher, $raum, %rechner); }

  1. --------------------------------------------------------------------
  2. Funktion: aus der Ausgabe von smbstatus werden die Daten herausgezogen
  3. Aufruf: @daten = &get_data(@output);
  4. Input: @output = die Ausgabe von smbstatus
  5. Output: $daten[x] = \($ip, $login, $gruppe, $rechner);
  6. Update: 13.08.2007
  7. --------------------------------------------------------------------

sub get_data { my @output = @_; my @daten = (); foreach my $zeile (@output) { if ($zeile =~ /^ \d+\s* # die PID (\w+)\s* # der User (login) = $1 (\w+)\s* # die Gruppe = $2 (\w+)\s* # der Rechnername = $3 \((\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3})\) # die IP = $4 $/x) { my @values = ( $4, $1, $2, $3 ); # wird eine anonyme Liste push @daten, \@values; } } return @daten; }

  1. --------------------------------------------------------------------
  2. Funktion: es werden die Anzahl der Anmeldungen pro User ermittelt
  3. Aufruf: %connection = &get_anz_pro_user(@daten);
  4. Input: $daten[x] = \($ip, $login, $gruppe, $rechner);
  5. Output: $connection{$user} = $anzahl;
  6. Update: 16.12.2007
  7. --------------------------------------------------------------------

sub get_anz_pro_user { my @daten = @_; my %ip2user = (); foreach my $datum (@daten) { $ip2user{${$datum}[0]} = ${$datum}[1]; } my (%anzahl_anmeldungen, $user); foreach my $ip (keys %ip2user) { $user = $ip2user{$ip}; if (defined($anzahl_anmeldungen{$user})) { $anzahl_anmeldungen{$user}++; } else { $anzahl_anmeldungen{$user} = 1; } } return %anzahl_anmeldungen; }

  1. --------------------------------------------------------------------
  2. Funktion: es werden nur die Datensaetze aus diesem Raum zurueckgegeben
  3. Aufruf: @daten = &filtern_nach_raum(\@daten, \%pcs);
  4. Input: $daten[x] = \($ip, $login, $gruppe, $rechner);
  5. $pcs{$ip} = $rechnername;
  6. Output: $daten[x] = \($ip, $login, $gruppe, $rechner);
  7. Update: 16.12.2007
  8. --------------------------------------------------------------------

sub filtern_nach_raum { my $lref_daten = shift; my $href_pcs = shift; my @daten = @{$lref_daten}; my %pcs = %{$href_pcs}; my ($ip, @temp); foreach my $nr (@daten) { my @liste = @{$nr}; # wir holen uns die IP $ip = $liste[0]; # nur wenn diese IP zu den Rechnern des Raumes gehoert if (defined($pcs{$ip})) { # dann wollen wir diesen Datensatz push @temp, \@liste; } } return @temp; }

  1. --------------------------------------------------------------------
  2. Funktion: es werden die Logins durch einen Ersatzstring ersetzt
  3. Aufruf: @daten = &substitute_teacherlogins(\%config, \@teacher, @daten);
  4. Input: %config = die Daten der Konfiguration
  5. $daten[x] = \($ip, $login, $gruppe, $rechner);
  6. Output: $daten[x] = \($ip, $login, $gruppe, $rechner);
  7. Update: 16.12.2007
  8. --------------------------------------------------------------------

sub substitute_teacherlogins { my $href_config = shift; my $lref_teacher = shift; my @daten = @_; my %config = %{$href_config}; my @teacher = @{$lref_teacher}; my ($login, $anz, %teacher, @unvisible, %unvisible); # wir bearbeiten zuerst die Lehrerlogins if ($config{TEACHER} eq 'no') { # um die Lehrerlogins schneller zu finden, erstellen wir einen Hash foreach my $element (@teacher) { $teacher{$element} = 1; } } # wir holen uns noch die Logins, die nicht angezeigt werden sollen @unvisible = @{$config{UNVISIBLE}}; # auch daraus erstellen wir einen Hash foreach my $element (@unvisible) { $unvisible{$element} = 1; } foreach my $datum (@daten) { my @tmp = @{$datum}; # holen wir das Login $login = $tmp[1]; # wir ueberpruefen, ob das Login im Hash %teacher ist if (exists($teacher{$login})) { $tmp[1] = $config{UNVISIBLESTRING}; # Login ersetzen $datum = \@tmp; } else { # wir ueberpruefen, ob es im Hash %unvisible ist if (exists($unvisible{$login})) { $tmp[1] = $config{UNVISIBLESTRING}; # Login ersetzen $datum = \@tmp; } } } return @daten; }

  1. --------------------------------------------------------------------
  2. Funktion: fuer unbesetzte PCs werden Dummy-Datensaetze ergaenzt
  3. Aufruf: @daten = &gen_data_for_all_pcs(\%config, @daten);
  4. Input: %config = die Daten der Konfiguration
  5. $daten[x] = \($ip, $login, $gruppe, $rechner);
  6. Output: $daten[x] = \($ip, $login, $gruppe, $rechner);
  7. Update: 16.12.2007
  8. --------------------------------------------------------------------

sub gen_data_for_all_pcs { my $href_conf = shift; my $href_pcs = shift; my @daten = @_; my %conf = %{$href_conf}; my %pcs = %{$href_pcs}; # wir stecken jetzt die Datensaetze in einen Hash, wobei der Key # der Rechnername und der Value der ganze Datensatz ist my %help = (); my @datensatz = (); foreach my $ds (@daten) { @datensatz = @{$ds}; $help{$datensatz[3]} = $ds; } my @neu = (); my $temp; # fuer jeden PC aus diesem Raum (laut LDAP) foreach my $key (keys %pcs) { my @tmp = ($conf{ALTERNATE_STRING}, $conf{ALTERNATE_STRING}, $conf{ALTERNATE_STRING}, ); $temp = $pcs{$key}; # $temp ist der Rechnername # wenn es diesen Rechnername in den Datensaetzen von smbstatus gibt if (exists( $help{$temp} )) { # dann nehmen wir diesen push @neu, $help{$temp}; } else { # sonst pushen wir einen Dummy-Datensatz $tmp[3] = $temp; push @neu, \@tmp; } } return @neu; }

  1. --------------------------------------------------------------------
  2. Funktion: es wird die eigentliche Tabelle zusammengesetzt
  3. Aufruf: $table = &get_table(\@daten,\%config,\%net_connection,\%room_connection);
  4. Input: @daten = die bearbeiteten Daten aus smbstatus
  5. %config = die Konfiguration
  6. %net_connection - die Anzahl der Anmeldungen im Netz
  7. %room_connection - die Anzahl der Anmeldungen im Raum
  8. Output: $tabelle = die Tabelle als ein großer String
  9. Update: 30.12.2007
  10. --------------------------------------------------------------------

sub get_table { my $lref_daten = shift; my $href_config = shift; my $href_net_connection = shift; my $href_room_connection = shift; my @daten = @{$lref_daten}; my %config = %{$href_config}; my %net_connection = %{$href_net_connection}; my %room_connection = %{$href_room_connection}; my $tabelle = ; my (@temp, $login, $farbe); foreach my $datum (@daten) { @temp = @{$datum}; $tabelle .= ''; # Beginn der HTML-Zeile # ---------- die 1. Spalte: "Arbeitsplatz" ------------ $login = $temp[1]; $farbe = ; # wenn Mehrfachanmeldungen angezeigt werden sollen if ($config{MULTIPLE_LOGIN} eq 'yes') { if (exists($net_connection{$login}) and ($net_connection{$login} > 1)) { $farbe = $config{IM_NETZ}; } if (exists($room_connection{$login}) and ($room_connection{$login} > 1)) { $farbe = $config{IM_ROOM}; } } if ( $farbe ne ) { $tabelle .= ''.$temp[3].'';

   }
   else {

$tabelle .= ''.$temp[3].'';

   }
   # -------- die 2. Spalte: "IP-Adresse" ------------

$tabelle .= ''.$temp[0].''; # IP


   # -------- die 3. Spalte: "Account" ---------------
   # wenn der Maillink angezeigt werden soll
   if ( ($config{MAIL_URL} eq 'yes')
         and ($temp[1] ne $config{UNVISIBLESTRING})
         and ($temp[1] ne $config{ALTERNATE_STRING}) ) {

$tabelle .= '<a href="mailto:'.$temp[1].'@arktur">'.$temp[1].'</a>';

   }
   else {

$tabelle .= ''.$temp[1].'';

   }
   # -------------------------------------------------

$tabelle .= ''."\n"; # Ende der HTML-Zeile } return $tabelle; }

  1. --------------------------------------------------------------------
  2. Funktion: Vergleichsfunktion fuer's Sortieren der Daten nach Rechnernamen
  3. Aufruf: @daten = sort { vergleich_rechner($a,$b) } @daten;
  4. Input: $a, $b = Datensaetze aus der Liste
  5. Output: -1 | 0 | 1 fuer "kleiner" | "gleich" | "groesser"
  6. Update: 30.12.2007
  7. --------------------------------------------------------------------

sub vergleich_rechner { my $lref_a = shift; my $lref_b = shift; my @datensatz1 = @{$lref_a}; my @datensatz2 = @{$lref_b}; return ($datensatz1[3] cmp $datensatz2[3]); }

  1. --------------------------------------------------------------------
  2. Funktion: Hilfsfunktion zur zweistelligen Darstellung der Zeitdaten
  3. Aufruf: $sek = &zweistellig($sek);
  4. Input: $sek oder $min oder $std
  5. Output: diese Werte, aber zweistellig
  6. Update: 1.01.2008
  7. --------------------------------------------------------------------

sub zweistellig { my $datum = shift; if ($datum < 10) { $datum = '0'.$datum } return $datum; }

  1. --------------------------------------------------------------------
  2. Funktion: liefert formatierten Datumsstring
  3. Aufruf: $date = &datum($format);
  4. Input: String fuer das Ausgabeformat
  5. Output: String mit Datum und Uhrzeit
  6. Update: 1.01.2008
  7. --------------------------------------------------------------------

sub datum { my $format = shift; my @date = localtime(); my $sek = $date[0]; my $min = $date[1]; my $std = $date[2]; my $tag = $date[3]; my $monat = $date[4] + 1; my $jahr = $date[5] + 1900; $sek = &zweistellig($sek); $min = &zweistellig($min); $std = &zweistellig($std); my $rueckgabe = $format; $rueckgabe =~ s/%%tag%%/$tag/; $rueckgabe =~ s/%%monat%%/$monat/; $rueckgabe =~ s/%%jahr%%/$jahr/; $rueckgabe =~ s/%%stunde%%/$std/; $rueckgabe =~ s/%%minute%%/$min/; $rueckgabe =~ s/%%sekunden%%/$sek/; return $rueckgabe; } __END__ </source>