Kategorien
Programmierung

Aktuelles Verzeichnis nicht mehr Teil von @INC

Gerade beim Wechsel zwischen verschiedenen Perl-Versionen über ein Feature (und keinen Bug) gestolpert: seit Version 5.26 ist das aktuelle Verzeichnis nicht mehr im Standard-Include-Pfad @INC enthalten.

Als Grund hierfür gibt perldelta zur Version 5.26 unschöne Begleiterscheinungen der bisherigen Vorgehensweise an:

While convenient, this has security implications: for example, where a script attempts to load an optional module when its current directory is untrusted (such as /tmp), it could load and execute code from under that directory.

Der Beitrag listet auch einige Möglichkeiten auf, wie man das bisherige Verhalten auf sicherem Weg wiederherstellen kann.

Wer es (quick & dirty) genauso unsicher wie vorher haben will, kann auch

use Cwd qw(abs_path);
use File::Basename qw(dirname);
use lib dirname(abs_path(__FILE__));

in seinem Skript verwenden.

Kategorien
Programmierung

Bytefolge mit Perl ersetzen

Die Funktionen, die Perl für das Suchen und Ersetzen innerhalb von Strings bereitstellt, lassen sich auch hervorragend dazu verwenden, Bytefolgen innerhalb von Binärdaten zu bearbeiten.

Mittels der pack-Funktion wird die zu suchende Bytefolge in einer Variable gespeichert

$source = pack("C*", 0x00, 0x40, 0x06, 0x00, 0x00, 0xB0, 0x04, 0x00);

Deren Position innerhalb der zu durchsuchenden Daten kann durch die Funktion index ermittelt

$pos = index($data, $source);

und ggf. auch mit einer Ziel-Bytefolge mit Hilfe der Funktion subst ersetzt werden

substr($data, $pos, length($dest), $dest);
Kategorien
Programmierung

Creating default object from empty value bei der Verwendung von chained Properties

Erstellt man in PHP eine neue Instanz der vordefinierten Klasse StdClass, so können dieser anschließend beliebige Eigenschaften zugewiesen werden:

$test = new StdClass();
$test->property = 1;

Versucht man allerdings mehrere Eigenschaften ohne vorherige (Teil-)Initialisierung zu verketten, wird dies von PHP mit einer entsprechenden Warnung kommentiert:

$test->anotherproperty->propertytoo = 7;

Warning: Creating default object from empty value in ... on line ..

Um diese Warnung zu vermeiden (und richtig zu initialisieren), kann eine kleine Erweiterung der Klasse StdClass vorgenommen werden, welche beim Zugriff auf jede Eigenschaft prüft, ob diese bereits existiert und ggf. das Anlegen der Instanz nachholt:

class myData extends StdClass {

	public function __get($name) {
		if (!isset($this->{$name})) {
			$this->{$name} = new myData();
		}
		return $this->{$name};
	}
}

Anschließend können in Instanzen dieser Klasse beliebige verkettete Eigenschaften definiert werden, ohne daß PHP eine Warnung ausspuckt:

$test = new myData();
$test->property = 5;
$test->anotherproperty->property = 7;

Die neue Klasse hat keine Nachteile bzg. der Verwendung gegenüber der unmodifizierten Klasse „StdClass“, auch Funktionen wie z.B. „json_encode()“ funktionieren weiter problemlos.

Kategorien
Programmierung

Zugriffe auf „%windir%\System32“ und Unterverzeichnisse

Einer der Gründe, warum in der EDV zeitliche Voraussagen so schwer zu treffen sind, ist die Tatsache, daß man immer wieder über Dinge stolpert, mit denen man nicht gerechnet hat.

Beim Versuch, ein Aufräumskript für die Hinterlassenschaften des AMD-Treibers in Perl zu schreiben, wurde eine Datei nicht gefunden, die laut Explorer und Eingabeaufforderung aber sehr wohl vorhanden war:

C:\Windows\System32\drivers>dir ati2erec.dll
...
 Verzeichnis von C:\Windows\System32\drivers

21.11.2014  04:08            43.520 ati2erec.dll
               1 Datei(en),         43.520 Bytes

Die gleiche Aufgabenstellung als Perl-Skript

use strict;
use warnings;
if (-e 'C:\Windows\System32\drivers\ati2erec.dll') { print "found.\n"; }
else { print "not found.\n"; }

führte aber zur überraschenden Ausgabe

not found.

Wie so oft, wenn es um seltsame Dinge in Windows geht, handelt es sich hierbei aber um ein Feature und keinen Bug, wobei das Feature aber erst einmal gefunden werden muß. Im konkreten Fall hört es auf den Namen „File System Redirector“ und sorgt dafür, daß

In most cases, whenever a 32-bit application attempts to access %windir%\System32, the access is redirected to %windir%\SysWOW64.

Dies erklärt das obige Phänomen, da die verwendte Perl-Version eine 32-bit Anwendung ist. Freundlicherweise liefert der MSDN-Artikel auch gleich eine Lösung

32-bit applications can access the native system directory by substituting %windir%\Sysnative for %windir%\System32. WOW64 recognizes Sysnative as a special alias used to indicate that the file system should not redirect the access. This mechanism is flexible and easy to use, therefore, it is the recommended mechanism to bypass file system redirection.

so daß der Zugriff auf ‚C:\Windows\Sysnative\drivers\ati2erec.dll‘ dann tatsächlich ein

found.

als Ergebnis liefert. Das „flexible and easy to use“ möchte ich aber durchaus in Frage stellen, denn

Note that 64-bit applications cannot use the Sysnative alias as it is a virtual directory not a real one.

bedeutet letztendlich eine entsprechende Abfrage im Skript, damit – je nach verwendetem Interpreter – der Pfad entweder auf  „System32“ oder „Sysnative“ gesetzt wird.

Kategorien
Programmierung

Methods with the same name as their class will not be constructors in a future version of PHP

Mit PHP 4 wurden Konstruktoren eingeführt, welche den gleichen Namen haben wie die Klasse, in der sie definiert wurden:

class tolleKlasse {

    function tolleKlasse() {
    
        // ...
    }
}

In PHP 5 wurden diese Konstruktoren beibehalten, gleichzeitig aber mit der Methode

__construct()

eine neue Art der Konstruktor-Definition eingeführt. Seit PHP 7 wird bei der Verwendung von PHP 4 Konstruktoren nun die Warnung „Deprecated: Methods with the same name as their class will not be constructors in a future version of PHP“ ausgegeben, die darauf hinweist, daß ab PHP 8 die gleichnamigen Methoden nur noch als normale Methoden, nicht aber als Konstuktoren behandelt werden.

Um vorhandenen Code fit für die Zukunft zu machen, reicht es, den Namen der Funktion zu ersetzen:

class tolleKlasse {

    function __construct() {
    
        // ...
    }
}

Da hierdurch vorhandener Code, welcher z.B. im Rahmen einer Vererbung auf den Funktionsnamen des Konstuktors zugreift, in einen Fehler läuft, kann nach dem Konstruktor eine zweite Methode mit dem ursprünglichen Funktionsnamen angelegt werden, welche den eigentlichen Konstruktor aufruft.