Problem mit relativen Pfadangaben in PHP
-
Hallo zusammen
Ich habe ein riesen Problem mit relativen Pfadangaben in meinen PHP Scripten. Ich muss teilweise dieselben Scripte in mehreren anderen Scripten includen, welche sich an unterschiedlichen Positionen im Dateisystem befinden. Das währe an sich noch kein Problem, jedoch inlcuden jene includeten Dateien selbst wieder Daten mit include und dann funktionieren die relativen Pfadangaben teilweise nicht mehr. Die einzige Lösung, die ich im Moment sehe währen absolute Pfadangaben, doch dafür müsste ich irgendwie den absoluten Pfad bis hin zum root Directory von meinem Webspace bekommen...Wie macht ihr das?
Gruss Samuel
-
Hallo,
ich verstehe das Problem nicht?
Wenn du z.B. folgende Dateistruktur hast:
folder include -> file core.php -> folder lib -> file functions.php -> file classes.php
Wenn du jetzt in core.php die Dateien "./lib/functions.php" und "./lib/classes.php" inkludierst, funktioniert das, unabhängig davon, von wo die core.php inkludiert wurde!
-
Ja aber sobald nun core.php auch noch was includiert funktionierts nicht mehr, wenn core.php von zwei verschiedenen Verzeichnissen aus includiert wird.
-
Ich weiss, was er meint: Wenn die Datei /var/www/inc/main.php per relativer Pfadangabe die Datei /var/www/inc/special/functions.php einbindet, diese wiederum per relativer Pfadangabe, weil sie selbst in manchen Unterseiten direkt eingebunden wird, wiederum die Datei /var/www/inc/other.php, funktioniert dieses Einbinden nicht ueber di erste Datei.
Das Problem laesst sich nur ueber zwei Wege loesen:
- Absolute Pfadangaben
- Direkt (also jede Pfadangabenvariable beinhaltet den vollstaendigen Pfad)
- Indirekt (es gibt eine globale absolute Pfadangabe, andere Pfadangaben verwenden diese und ergaenzen sie lediglich)
- Vermeidung von vermischten Einbindungen, vor allem ueber unterschiedliche Ordner hinweg
- Alle Dateien, die eingebunden werden, in genau einem Pfad bewahren
- Korrekte Ausfuehrung - in der richtigen Reihenfolge - aller Einbindungen
Um den absoluten Pfad zu erhalten, kannst du z.B. die Umgebungsvariable _SERVER['DOCUMENT_ROOT']:
<a href= schrieb:
php.net">Das Document Root-Verzeichnis, unter dem das aktuelle Skript ausgeführt wird, so wie es in der Konfiguration des Servers festgelegt wurde.
-
@heini
Du hast mein Problem erkannt, danke!
Ich habe mittlerweile über 500 Scriptdateien und die möchte ich nicht alle in ein einziges Verzeichnis werfen, daher bevorzuge ich stattdessen die absolute Pfadangabe. Meine Frage ist nun, gibt es einge Möglichkeit, require und include anzuweisen, ein Prefix zu verwerden?
-
Ah, okay, verstanden.
Das Problem lässt sich sehr einfach und elegant lösen.
Du definierst in jeder Datei der 1. Ausführungsschicht (also jede Datei, die quasi als oberste Instanz vom User aufgerufen werden kann) eine Konstante, die den von dort relativen Pfad zum Hauptverzeichnis enthält.In sämtlichen Include-Anweisungen deiner Bibliotheken verwendest du nun diese Konstante + den vom Hauptverzeichnis aus betrachtet relativen Pfad zur Datei.
Zur Verdeutlichung:
folder htdocs: index.php
define('root', './');
folder htdocs/inc/special: functions.php
include(root.'inc/other.php');
Inkludierst du nun z.B. von der Datei htdocs/asubdir/test.php oder htdocs/inc/whatever.php aus, dann definierst in diesen Dateien einfach root := './../' und alles läuft weiter wie gewohnt. Es sieht auf den ersten Blick recht kompliziert aus, ist aber tatsächlich eine einfache und elegante Möglichkeit, das Problem komplett zu umgehen.
-
Noch eleganter, weil ohne Extra Konfigvariable, ist eine absolute Adressierung von der aktuellen Datei aus:
require_once ( dirname(__FILE__)."/../lib/foo.php" );
-
Naja, ich habe die Erfahrung gemacht, dass man den Pfad zum Hauptverzeichnis immer wieder braucht, und sei es nur im Output irgendwelcher Graphiken, die an einer zentralen Stelle berechnet werden. Daher lässt sich das leicht kombinieren.
An sich aber noch besser, stimmt.
-
Ishildur schrieb:
gibt es einge Möglichkeit, require und include anzuweisen, ein Prefix zu verwerden?
Soweit ich weiss gibt es einen solchen Luxus bisweilen noch nicht. Aber du koenntest - solltest du im Besitz eines Linux-, UNIX- oder BSD-aehnlichen Systems sein - per Anweisung einfach alle 'include('-Textbausteine durch 'include(root.' ersetzen. Genau fuer solche Zwecke wurden sie ja geschrieben. Am einfachsten macht sich das per Shell\1:
#!/bin/bash D=/var/www/inc # Hauptordner nicht vergessen: # Alle PHP-Dateien auflisten FILES=$(find $D -type f -name "*.php") # Jede Datei durchgehen for file in $FILES do # Dateinamen ausgeben echo $file # Text ersetzen cat $D/$file | sed 's/include\(/include\(root\./g' > $D/$file done echo . # Ordner auflisten PATH=$(find $D -type d -name "*") # Jeden Unterordner durchgehen for path in $PATH do # Ordner ausgeben: echo $path echo ---------- # Alle PHP-Dateien auflisten FILES=$(find $D/$path -type f -name "*.php") # Jede Datei durchgehen for file in $FILES do # Dateinamen ausgeben echo $file # Text ersetzen cat $D/$path/$file | sed 's/include\(/include\(root\./g' > $D/$path/$file done echo . done # Programmende exit 0
Hinweis: Das habe ich nicht getestet. Habe mich nur grad kurz belesen, ein paar Zeilen Code kopiert, umgeschrieben und nach Logik weiterentwickelt. Ob das hinhaut, sollte nochmal ueberprueft werden.
EDIT: Vergiss es. Du nutzt vermutlich einen Webhoster, der laesst dich vermutlich auch nicht auf seine Shell... Versuch's alternativ mit einer PHP-Datei:
<?php function conv($f) { // Datei zum Lesen oeffnen if(($h=fopen($f,"r"))!==false) { // und auslesen $tmp=fread($h,sprintf("%u",@filesize($f))); fclose($h); // Datei zum Schreiben oeffnen if(($h=fopen($f,"w"))!==false) { fwrite($h,preg_replace("/([include\(|include_once\(|require\(|require_once\(])/",$1."root.",$tmp)); fclose($h); return true; } } return false; } function start($p) { // Aktuellen Ordner oeffnen if(($h=opendir($p))!==false) { // Alle Dateien und Ordner auflisten while(($f=readdir($h))!==false) { // Dateien "konvertieren" if(!is_dir($p."/".$f)) conv($p."/".$f); // Und Ordner wieder durchsuchen else if($f!="." && $f!="..") start($p."/".$f); } } return true; } start("/var/www/inc"); ?>
Ebenfalls nicht getestet und auf der Schnelle getippt...