php.de

Zurück   php.de > php.de Intern > Wiki Diskussionsforum > Tutorials

Tutorials Hier findest Du Tutorials, welche nach und nach ein fertiges Script ergeben. Sehen, lernen & verstehen!

Antwort
 
LinkBack (6) Themen-Optionen Thema bewerten
Alt 17.05.2008, 08:43  
Erfahrener Benutzer
 
Registriert seit: 21.05.2008
Beiträge: 9.937
Zergling-new wird schon bald berühmt werden
Standard PHP: Falsche Pfade bei include/require ohne include_path

Hallo,


einiges kann schiefgehen, wenn man versucht relative Pfade beim include/require zu verwenden. Es ist dabei zu beachten, dass ein include ohne vollstaendige Pfadangabe:
PHP-Code:
<?php
include "classes/MyClass.class.php"
?>
seinen korrekten Pfad ueber den Pfadnamen des ausfuehrenden Skriptes aufloest.


Zitat:
Das Verzeichnis des ausfuehrenden Skriptes
PHP-Code:
<?php
dirname
($_SERVER["SCRIPT_FILENAME"])
?>
und nicht die Datei, die die include/require Anweisung ausfuehrt, wird als Basis-Verzeichnis fuer relative include/require Anweisungen verwendet.

Der PHP-Interpreter verwendet also den Ordner des Skriptes als Basis, mit dem er aufgerufen wird. Dabei ist es voellig egal, welche weiteren Skripte im Verlauf mit include/require eingebunden werden. Sich den Unterschied klar zu machen, ist wichtig.


Auch kann dies etwas verwirrend sein und mag unlogisch erscheinen, z.B. bei folgendem Dateisystem-Szenario:
Code:
global.inc.php
wwwroot/index.php
classes/MyClass.class.php
global.inc.php
PHP-Code:
<?php
include "classes/MyClass.class.php";
?>
wwwroot/index.php
PHP-Code:
<?php
include "../global.inc.php";
$objMyClass = new MyClass();
?>
classes/MyClass.class.php:
PHP-Code:
<?php
class MyClass { }
?>
Die Pfade scheinen einzeln und fuer sich genommen korrekt gesetzt zu sein, aber wenn man "index.php" nun aufruft, wird das Skript "global.inc.php" - das noch erfolgreich von "index.php" eingebunden wurde - mit einem include-Fehler abbrechen, da "classes/MyClass.class.php" nicht gefunden wurde.


Beziehen wir nun ein, dass dirname($_SERVER["SCRIPT_FILENAME"]) als Basispfad verwendet wird, macht das ganze Sinn, denn der PHP-Interpreter wurde mit "index.php" aufgerufen und verwendet nun dessen Ordner als Basis-Verzeichnis, und "wwwroot/" . "classes/MyClass.class.php" existiert nunmal nicht.


Wie loesen wir also das Problem? Nun es gibt viele Loesungen, wobei ich persoenlich in letzter Zeit zur am Ende beschriebenen Loesung tendiere, alle Loesungen sind allerdings akzeptabel. Wenn man PHP allerdings beruflich verwendet, sollte man sich schon ueberlegen, ob nicht ein professionelleres Handling Sinn macht.



1.) Wenn man weiss, dass "global.inc.php" immer aus "wwwroot" aufgerufen wird, kann man dieses Vorwissen nutzen und einsetzen, in dem man "global.inc.php" einfach dahingehend manipuliert, dass man den relativen Pfad so anpasst, dass er aus "wwwroot" loslaufend, korrekt ist:

global.inc.php:
PHP-Code:
<?php
include "../classes/MyClass.php";
?>
Der Nachteil ist, wird nun ein Skript aus einem Unterordner von "wwwroot" aufgerufen, also z.B. "wwwroot/news/index.php" funktioniert das ganze nicht mehr.



2.) Feste, absolute Pfade:

Der Nachteil von relativen Pfaden ist ganz offensichtlich, dass man vom Basis-Pfad abhaengig ist. Umgehen kann man das, in dem man absolute Pfade verwendet:

global.inc.php:
PHP-Code:
<?php
include "/path/to/my/project/classes/MyClass.class.php";
?>

Dies wird uebrigens von Windows und Linux verstanden, obwohl der DIRECTORY_SEPARATOR von Windows der Backslash (\) ist.


Der Nachteil ist aber offensichtlich, das Projekt muss wissen wo es sich befindet, die Pfade stehen fest und sie muessen bei einem Server-Umzug (und sei es nur von der Entwicklungs- in die Produktiv-Umgebung) muehsam angepasst werden. Search&Replace ist eine feine Sache, Komfort sieht aber anders aus.



3.) Dynamische, absolute Pfade:

Man kann sich natuerlich auch absolute Pfade selber zusammen bauen, in dem man die magische Konstante __FILE__ und wieder die Funktion dirname() verwendet. __FILE__ ist laut Beschreibung des Manual lediglich dies:

Zitat:
Der vollständige Pfad- und Dateiname einer Datei. Wird diese Konstante innerhalb einer nachgeladenen Datei verwendet, wird der Name dieser eingebundenen Datei zurückgegeben.
http://us2.php.net/manual/de/languag...predefined.php


Ruft man nun dirname(__FILE__) auf, hat man sich so seinen eigenen absoluten Basispfad erstellt:

global.inc.php
PHP-Code:
<?php
include dirname(__FILE__) . "/classes/MyClass.class.php";
?>

Diese Intelligenz kann man natuerlich in eine Pfad-Konfigurationsdatei (belassen wir sie der Einfachheit halber in "global.inc.php") auslagern:
PHP-Code:
<?php
define
("PATH_CLASSES"dirname(__FILE__) . "/classes");
?>

Nun kann jede Datei, die "global.inc.php" einbindet, diese Konstante verwenden, egal aus welcher Pfad-Ebene sie aufgerufen wird, immer absolut und damit korrekt:

wwwroot/news/index.php:
PHP-Code:
<?php
include "../../global.inc.php";
include 
PATH_CLASSES "/MyClass.class.php";
?>

Aber auch diese Loesung hat den Nachteil, dass die Anwendung ihren relativen Ort zur "global.inc.php" kennen muss (und wenn dies jede Datei muss, ist die Struktur de-facto star) und die Verwendung einer Konstanten (und die Kenntnis ihres Namens) fuer jeden include/require Befehl benoetigt wird. Eine zwar kleine Abhaengigkeit, aber auch eine kleine Abhaengigkeit ist eine Abhaengigkeit, die man natuerlich vermeiden moechte.


4.) __autoload

Wenn es nur darum geht PHP-Klassen einzubinden, kann man die Funktion __autoload() verwenden:
http://us.php.net/__autoload

Die funktioniert allerdings nur fuer Klassen, nicht fuer andere Inline-Skripte oder Funktionen.


5.) PHP-Einstellung "include_path":

Der "include_path" wird viel zu selten verwendet, was eigentlich verwundert. Schlaegt ein include fehl, weil die Datei nicht gefunden wird, werden die im "php_flag" "include_path" aufgefuehrten und mit PATH_SEPARATOR getrennten Pfade als Basis zur include-Anweisung verwendet und nacheinander bis zum Erfolg oder endgueltigen Misserfolg ausprobiert. Was nach einem endgueltigen Misserfolg passiert, entscheiden die Konstrukte include/require selbst und ist hier nachzulesen:
http://us3.php.net/include/
http://us3.php.net/require/


Der Pfad laesst sich durch die Datei "php.ini", Flag "include_path" entweder hart per Server-Einstellung setzen, oder aber nachtraeglich ueber ".htaccess" oder dynamisch mit set_include_path(). Auslesen ist ueber get_include_path() moeglich.


Wie erwaehnt werden hier die Pfade als String aufgelistet und sind nur mit dem in der PHP-Konstanten PATH_SEPARATOR festgelegten Zeichen getrennt. Es ist ein abhaengig vom Betriebssystem festgelegtes Zeichen, dass in seinen Pfaden nicht vorkommen darf, in Linux ueblicherweise der Doppelpunkt (:), unter Windows das Semikolon (;).


Eine Funktion add_include_path($strIncludePath) koennte also so aussehen:
PHP-Code:
<?php
function add_include_path($strIncludePath) {
    
$strIncludePath realpath($strIncludePath);
    if (empty(
$strIncludePath)) {
        return 
false;
    }
    
$arrIncludePaths explode(PATH_SEPARATORget_include_path());
    
$arrIncludePaths[] = $strIncludePath;
    
$arrIncludePaths array_unique($arrIncludePaths);
    
set_include_path(implode(PATH_SEPARATOR$arrIncludePaths));
    return 
true;
}
?>

Nun koennten wir statt unserer Pfad-Konstante PATH_CLASSES einfach alle wichtigen Verzeichnisse zu unserem "include_path" hinzufuegen. Wildes includen funktioniert dann natuerlich immer noch nicht, denn wir muessen ja vorher bereits eine Vorauswahl getroffen haben, welche Pfade "wuerdig" sind, als Basisverzeichnis in den "include_path" aufgenommen zu werden. Dies gewaehrleistet ein systematisches aber flexibles Schema (was include ich grundsaetzlich bzw. konkret) und bleibt bei den ueblichen Anwendungen auch meistens ueberschaubar: Klassen, Funktionen, externe Bibliotheken (PEAR, Zend, phpMailer, ..) oder Models/Views/Controllers. Externe Bibliotheken verlangen ohnehin dass sie in den "include_path" aufgenommen werden (und PEAR ist es unter XAMPP auch schon automatisch), wie sollten sie auch sonst ohne die Verwendung von absoluten Pfad-Konstrukten wissen, wo und wie sie ihre eigenen Unterbibliotheken nachladen koennen.


Da die genannten externen Bibliotheken PEAR, Zend und phpMailer eigentlich nur Klassen-Sammlungen sind koennen wir die Bibliotheken auch nur bei Bedarf verfuegbar machen:

PEAR.inc.php:
PHP-Code:
<?php
add_include_path
(dirname(__FILE__));
?>
Code:
PEAR.inc.php
PEAR/PEAR.php
PEAR/PEAR/..
..

Ein
PHP-Code:
<?php
include_once "PEAR.inc.php"
?>
genuegt (sofern sich der Pfad von "PEAR.inc.php" bereits im "include_path" befindet).


Das ganze automatisieren bzw. auf ein Minimum an Anweisungen runterbrechen kann man nun mit dem PHP-Flag "auto_prepend_file". Eingestellt, wird das darueber angegebene Skript vor jeder Ausfuehrung eines PHP-Skriptes ausgefuehrt:

wwwroot/.htaccess:
Code:
php_flag auto_prepend_file "C:/path/to/my/project/includes/prepend.inc.php"

Nun wird, bevor ein Skript ueber den Webserver ausgefuehrt wird (denn nur auf den hat ".htaccess" Einfluss), die Datei "global.inc.php" im leider absolut angegebenen Verzeichnis ausgefuehrt. Wenn wir nicht sowieso schon eine Bootstrap-Datei verwenden, bei der dieses Verfahren (fast) unnuetz ist, haben wir es jetzt geschafft und koennen in "prepend.inc.php" unseren "include_path" setzen:

prepend.inc.php:
PHP-Code:
<?php
$arrIncludePaths 
explode(PATH_SEPARATORget_include_path());
$arrIncludePaths[] = realpath("/path/to/my/project/classes");
$arrIncludePaths[] = realpath("/path/to/my/project/functions");
$arrIncludePaths array_unique($arrIncludePaths);
set_include_path(implode(PATH_SEPARATOR$arrIncludePaths));
?>

Es ist anzuraten, dass in dieser Datei so wenig Intelligenz wie moeglich verwendet wird, nach Moeglichkeit sollte sie nur den "include_path" setzen, fertig. Denn auch das Debuggen in dieser Datei ist schwierig und da diese Datei vor jedem Skript ausgefuehrt wird, sollte es keinen irgendwie gearteten Bug produzieren. Bugs entstehen in komplexen Systemen, also versuchen wir dem mit Einfachheit entgegenzuwirken.


Der Nachteil wurde bereits genannt: Wir muessen einmalig unseren absoluten Pfad fuer das Projekt kennen und ihn in der ".htaccess" Datei setzen. Das ist schlecht, laesst sich aber meines Wissens nicht vermeiden (wenn diese Information falsch ist, lasst es mich wissen). Einmalig heisst aber wirklich einmalig, pro Entwicklungsumgebung.


Der Vorteil ist nun, dass unsere komplexe Anwendung nun rein garnichts ueber sich wissen muss, weder wie die Pfadkonstante heissen, ob es welche gibt und schon garnicht muss die Anwendung wissen, wo sich welche Dateien befinden. All dies uebernimmt nun PHP aus dem Wissen der fuer "include_path" gelieferten Pfade. Eine clevere __autoload Funktion erledigt den Rest:

PHP-Code:
<?php
function __autoload($strClass) {
  require 
str_replace("_"DIRECTORY_SEPARATOR$strClass ".class.php");
}
?>

Auch sie kennt nur die Details, die sie wissen muss. Alle Bibliotheken funktionieren nun in jeder Umgebung, in der "include_path" korrekt gesetzt ist, eine Voraussetzung die sich notfalls nachtraeglich schaffen laesst.


Die "auto_prepend_file" Direktive laesst sich wie erwaehnt natuerlich bei der Verwendung von "Bootstrapping" vermeiden (womit man auch auf absolute Pfade vermeiden kann), allerdings kommt es in komplexen Anwendungen oft genug vor, dass man [mein Gott der Hund hier furzt wie ein Weltmeister] dann doch das ein oder andere Skript hat, das selbstaendig laeuft, seien es Bild-Generatoren oder Download-Manager, die man vielleicht von der komplexen Controller-Struktur entkoppeln moechte und dann faengt man wieder an, das Wissen ueber den Aufbau der Anwendung zu verteilen.


Soviel dazu.
Zergling-new ist offline   Mit Zitat antworten
Sponsor Mitteilung
PHP Code Flüsterer

Registriert seit: 21.08.2005
Beiträge: 4682
PHP-Kenntnisse:
Fortgeschritten

Alt 17.05.2008, 15:03  
Erfahrener Benutzer
 
Registriert seit: 16.07.2005
Beiträge: 1.007
PHP-Kenntnisse:
Fortgeschritten
brian johnson befindet sich auf einem aufstrebenden Ast
Standard

sorry, war zu faul das alles durchzulesen, nur noch die anmerung:

der apache webserver ändert während des shutdowns eines moduls (cgi weiß ich jetzt nicht) den aktuellen pfad auf den pfad des homedirs des webservers. bedeutend ist dies, wenn man während einer shutdown funktion wie destruct in eine datei schreiben muss. dann MUSS man den absoluten pfad angeben.
__________________
PHP4?!?>>>Aktuelle PHP Version: 5.2.11 || 5.3.0
Suse 11.2 *vorfreude*
brian johnson ist offline   Mit Zitat antworten
Alt 19.05.2008, 15:54  
Moderator
 
Benutzerbild von cycap
 
Registriert seit: 13.02.2008
Beiträge: 6.816
PHP-Kenntnisse:
Fortgeschritten
cycap ist einfach richtig nettcycap ist einfach richtig nettcycap ist einfach richtig nettcycap ist einfach richtig nettcycap ist einfach richtig nett
Standard

Ich hab jetzt auch keine Lust das alles zu lesen, aber ich hab einen Tipp der mich schon eine Menge Zeit gekostet hat! Und zwar hat PHP 5.2.5 einen Bug das set_include_path mal funktioniert und mal nicht, fall einem das mal zustößen sollte...
cycap ist offline   Mit Zitat antworten
Alt 19.05.2008, 19:18  
Erfahrener Benutzer
 
Registriert seit: 21.05.2008
Beiträge: 9.937
Zergling-new wird schon bald berühmt werden
Standard

Ihr seid so hoeflich - die geborenen Informatiker eben
Zergling-new ist offline   Mit Zitat antworten
Alt 20.05.2008, 09:55  
Moderator
 
Benutzerbild von cycap
 
Registriert seit: 13.02.2008
Beiträge: 6.816
PHP-Kenntnisse:
Fortgeschritten
cycap ist einfach richtig nettcycap ist einfach richtig nettcycap ist einfach richtig nettcycap ist einfach richtig nettcycap ist einfach richtig nett
Standard

Zitat:
Zitat von Zergling
Ihr seid so hoeflich - die geborenen Informatiker eben
Man spart mit Arbeit wo man kann
cycap ist offline   Mit Zitat antworten
Antwort


Themen-Optionen
Thema bewerten
Thema bewerten:

Forumregeln
Es ist dir nicht erlaubt, neue Themen zu verfassen.
Es ist dir nicht erlaubt, auf Beiträge zu antworten.
Es ist dir nicht erlaubt, Anhänge hochzuladen.
Es ist dir nicht erlaubt, deine Beiträge zu bearbeiten.

BB-Code ist an.
Smileys sind an.
[IMG] Code ist an.
HTML-Code ist aus.
Trackbacks are an
Pingbacks are an
Refbacks are an
Gehe zu

LinkBacks (?)
LinkBack to this Thread: http://www.php.de/tutorials/45917-php-falsche-pfade-bei-include-require-ohne-include_path.html
Erstellt von For Type Datum
Les einfach den Text, es geht um PHP (include) This thread Refback 06.08.2011 11:49
einseinself | Homepagehilfe | [PHP & MySQL] Include-Problem This thread Refback 27.06.2011 09:25
einseinself | Homepagehilfe | [PHP & MySQL] Include-Problem This thread Refback 26.06.2011 18:12
[PHP] Include eines PHP Scripts aus anderem Ordner This thread Refback 06.04.2011 00:55
Metacrawler - Die Metasuchmaschine. This thread Refback 27.08.2010 13:28
Google INTERIA.PL - szukaj: Pfad und dateiname korrekt This thread Refback 10.02.2009 09:48

Ähnliche Themen
Thema Autor Forum Antworten Letzter Beitrag
welche pfade denn nun für welche funktion? Promaetheus PHP Tipps 2006 6 08.11.2006 21:33
falsche Eingaben in URL abfangen...id an DB etc... argon PHP Tipps 2007 2 18.11.2005 10:15

Besucher kamen über folgende Suchanfragen bei Google auf diese Seite
include_path, php pfad, php include pfad, php pfade, php include_path, php require path, php include path, pfade php, php require pfad, include_path php, php include_path setzen, php include pfadangabe, include php pfad, pfade in php, php include absoluter pfad, pfad php, php pfad setzen, php include pfade, php include path setzen, include pfad php

Alle Zeitangaben in WEZ +1. Es ist jetzt 19:21 Uhr.




Powered by vBulletin® Version 3.7.2 (Deutsch)
Copyright ©2000 - 2012, Jelsoft Enterprises Ltd.
Search Engine Optimization by vBSEO 3.2.0
Aprilia-Forum, Aquaristik-Forum, Liebeskummer-Forum, Zierfisch-Forum, Geizkragen-Forum

Creative Commons License
Dieser Inhalt ist unter einer Creative Commons-Lizenz lizenziert.