Pfad fixen

  • PHP

Es gibt 20 Antworten in diesem Thema. Der letzte Beitrag () ist von 3daycliff.

    Hi,

    ich hatte bis eben versucht mir n kleines Skript zu schreiben, welches in etwa folgendes tut:

    Quellcode

    1. Pfad/Zu/Irgendetwas/../Anderes/Was/Nicht/../../Welches/Kartoffel.php


    Wird zu:

    Quellcode

    1. Pfad/Zu/Anderes/Welches/Kartoffel.php


    Ich dachte mir das in etwa so:
    • Speichere jeden Index des Zeichens "/"
    • Gehe jeden Char durch und für jeden Durchlauf merke den aktuellen Char und die 3 nächsten
    • Wenn der aktuelle und die 3 nächsten Chars "/../" ergeben dann
    • Finde den Index vom dem aktuellen Char im IndexArray
    • Nun zerteile den String entsprechend einmal und fange von vorne an
    Aussehen tut das ganze so:

    PHP-Quellcode

    1. $w = "Pfad/Zu/Irgendetwas/../Anderes/Was/Nicht/../../Welches/Kartoffel.php";
    2. $aIndex = array();
    3. $Length = strlen($w);
    4. for($i = 0; $i < $Length; $i++) {
    5. if($w[$i] === "/") {
    6. $aIndex[] = $i;
    7. }
    8. }
    9. $Size = count($aIndex)-1;
    10. for($i = 0; $i < $Length - 4; $i++) {
    11. $aCur = array();
    12. for($j = $i; $j < $i + 4; $j++) {
    13. $aCur[] = $w[$j];
    14. }
    15. if($aCur[0] . $aCur[1] . $aCur[2] . $aCur[3] == "/../") {
    16. $Index = -1;
    17. for($j = 0; $j < $Size; $j++) {
    18. if($aIndex[$j] == $i) {
    19. $Index = $j;
    20. }
    21. }
    22. if(!$Index !== -1) {
    23. $w = Str::Cut($w, $aIndex[$Index-1], $aIndex[$Index+1] - $aIndex[$Index-1]);
    24. $Length = strlen($w);
    25. $i = 0;
    26. }
    27. }
    28. }


    Mein Ergebnis sieht allerdings so aus: puu.sh/cYcrh/9239f6e87a.png

    Wie kann ich das lösen?

    -Tim
    Hab ich doch?

    EDIT:

    Quellcode

    1. Pfad/Zu/Irgendetwas/../Anderes/Was/Nicht/../../Welches/Kartoffel.php
    2. Pfad/Zu/Anderes/Was/Nicht/../../Welches/Kartoffel.php

    Bereits etwas besser.

    Hab hierbei if(!$Index !== -1) { zu if($Index !== -1) { geändert.
    Nun werden halt noch die doppelten "../" ignoriert? :S

    Dieser Beitrag wurde bereits 2 mal editiert, zuletzt von „backtothetoast“ ()

    Das wäre ja zu einfach. Natürlich diese entfernen, dann aber auch den Pfadteil davor.

    Heißt..
    a/b/../b/c
    ..wird zu..
    a/b/c
    ..weil..
    b/../
    ..entfernt wird.

    Verstehst du den Sinn dahinter?:D Wie dem auch sei, habs jetzt hinbekommen:
    Spoiler anzeigen

    PHP-Quellcode

    1. public static function FixPath($sInput, &$sOutput)
    2. {
    3. $Length = strlen($sInput);
    4. $aIndex = array();
    5. for($i = 0; $i < $Length; $i++) {
    6. if($sInput[$i] === "/") {
    7. $aIndex[] = $i;
    8. }
    9. }
    10. $Size = count($aIndex)-1;
    11. for($i = 0; $i < $Length - 4; $i++) {
    12. $aCur = array();
    13. for($j = $i; $j < $i + 4; $j++) {
    14. $aCur[] = $sInput[$j];
    15. }
    16. $sFull = $aCur[0] . $aCur[1] . $aCur[2] . $aCur[3];
    17. if($sFull == "/../") {
    18. $Index = -1;
    19. for($j = 0; $j < $Size; $j++) {
    20. if($aIndex[$j] == $i) {
    21. $Index = $j;
    22. }
    23. }
    24. if($Index !== -1) {
    25. $sInput = self::Cut($sInput, $aIndex[$Index-1], $aIndex[$Index+1] - $aIndex[$Index-1]);
    26. $Length = strlen($sInput);
    27. $aIndex = array();
    28. for($i = 0; $i < $Length; $i++) {
    29. if($sInput[$i] === "/") {
    30. $aIndex[] = $i;
    31. }
    32. }
    33. $Size = count($aIndex)-1;
    34. $i = 0;
    35. }
    36. }
    37. }
    38. $sOutput = $sInput;
    39. }

    Ich hätt's dir wohl nicht gepostet wenn es nicht funktionieren würde -.- Tut genau das was du in Post #5 beschrieben hast. Probier's aus.
    Allerdings ist das in Post #5 beschriebene Beispiel nicht so wie deine Pfade im Eingangspost. Ich mein, wieso soll der Ordner "Irgendwas" verschwinden? Wo macht das Sinn?

    Also
    Pfad/Zu/Irgendetwas/../Anderes/Was/Nicht/../../Welches/Kartoffel.php
    soll zu
    Pfad/Zu/Anderes/Welches/Kartoffel.php
    werden? Wieso? Wo is das Muster? Wie errechnet/ergibt sich der Pfad? Es sieht aus als würdest du einfach nur random Verzeichnisse aus dem Fullpath rausschneiden. Wozu? Du schneidest quasi Irgendetwas/../ und Was/Nicht/../../ aus dem Pfad raus. Was is der Sinn dahinter? Und stehen die ".." Punkte wirklich so im Pfad oder hast du das nur als Beispiel dafür genommen dass dort noch mehr Ordner stehen?


    Link :thumbup:
    Hello World

    Dieser Beitrag wurde bereits 1 mal editiert, zuletzt von „Link“ ()

    Naja, ../ bedeutet so viel wie "gehe einen Ordner zurück" - deswegen entferne ich nicht nur ../ sondern auch den Ordner davor, damit ich im richtigen Ordner bin und der Pfad am Ende stimmt^^

    Probiers mal in cmd.exe und mach folgendes:

    cd ..

    Damit springst du ein Ordner zurück, so auch ../ in einem Pfad ;)
    Hi,

    ok jetz versteh' ich es endlich. Das war ja auch meine Frage weiter oben, ob das Teil des Pfades ist.

    Mach es doch so (Beispielprogramm):

    PHP-Quellcode

    1. <?php
    2. $pfad = "Pfad/Zu/Irgendetwas/../Anderes/Was/Nicht/../../Welches/Kartoffel.php";
    3. while(preg_match('/\.\.\//i', $pfad)){
    4. $pfad = preg_replace('/([^\/]+\/)(\.\.\/)/i', '', $pfad);
    5. }
    6. echo $pfad;
    7. //Ausgabe: Pfad/Zu/Anderes/Welches/Kartoffel.php
    8. //Oder als Funktion zum Sofort-verwenden:
    9. $pfad = resolvePath("Pfad/Zu/Irgendetwas/../Anderes/Was/Nicht/../../Welches/Kartoffel.php");
    10. function resolvePath($path){
    11. while(preg_match('/\.\.\//i', $path)){
    12. $path = preg_replace('/([^\/]+\/)(\.\.\/)/i', '', $path);
    13. }
    14. return $path;
    15. }
    16. ?>


    Getestet und funktioniert.

    Link :thumbup:
    Hello World

    Dieser Beitrag wurde bereits 1 mal editiert, zuletzt von „Link“ ()

    Solche Sachen sollte man nicht unbedingt selber schreiben, wenn man nicht genau weiß, was man tut. Das bringt auch schnell Sicherheitslücken.

    In dem Fall gibt es durch den unbedachten Einsatz von RegEx auch eine Endlosschleife, wenn der Pfad z.B. foo../bar lautet. Daher am besten auf vorgefertigte Funktionen zurückgreifen, in diesem Fall also realpath.
    Och, ich finde es immer gut, wenn man mal eine bestehende Funktion selber versucht zu programmieren. Lernt man halt eine Menge.
    Und die realpath-Funktion von PHP ist im Prinzip auch nicht so toll... aber meist besser, als eine selbstgeschriebene Variante. Z.B. hast du den Fall ./ ja auch nicht beachtet und der oben stehende RegEx behandelt z.B. den Pfad ../foo nicht so, wie es manche erwarten würden.

    Wenn du es noch mal probieren solltest:
    Mein Ansatz (der mir spontan einfällt) wäre den Pfad mit explode zu trennen und dann das Array zu bearbeiten und wieder mit implode zusammen zu fügen. Sollte einfacher als das String- oder RegEx-Gewusel sein.
    @3daycliff Cool, die Funktion kannte ich noch nicht :) Here, have my upvote
    Wohingegen ich dir bei der Theorie mit der Endlosschleife nur bedingt zustimmen kann. Denn bis zu einem gewissen Grad muss man sich beim Schreiben von Funktionen auch ein Stück weit darauf verlassen, dass "gültige" Werte übergeben werden. Davor sind auch vorgefertigte Funktionen nie gefeit.

    Allerdings könnte man -auf meine Funktion hin bezogen- durchaus dafür sorgen dass eine Prüfung erfolgt:

    PHP-Quellcode

    1. <?php
    2. //$pfad = resolvePath("./hurr/durr/../abc/123/../test.php");
    3. $pfad = resolvePath("Pfad/Zu/Irgendetwas/../Anderes../Was/Nicht../../../Welches/Kartoffel.php");
    4. if($pfad !== false){
    5. /* ... */
    6. }
    7. function resolvePath($path){
    8. while(preg_match('/\/\.\.\//i', $path)){
    9. $path = preg_replace('/([^\/]+\/)(\.\.\/)/i', '', $path);
    10. }
    11. return $path;
    12. if(file_exists($path)){
    13. return $path;
    14. }
    15. return false;
    16. }
    17. ?>

    Ich hab dort jetzt noch in der Zeile mit dem while den Pattern geändert und \/ vorn drangestellt. So müsste er auch foo../bar finden, wobei foo.. hierbei als Verzeichnisname behandelt wird.

    Ich weiß ja mittlerweile dass du nicht so der RegEx-Freund bist und wir hatten ja schonmal eine Diskussion darüber, du erinnerst dich vielleicht ;) Aber ich verwende es einfach so gern :D
    Tja und manchmal ist es eben so dass dass weder vorgefertigte noch selbst geschriebene Funktionen 100% optimal sind. Und meist liegt das eben daran dass man versucht, Spezialfälle mit performantem und optimalem Code behandeln zu wollen. Und in seltenen Fällen gibt's nun mal keine allgemeingültige, optimale und 100% zufriedenstellende Lösung.
    Aber jetzt hat der TE ja gleich mehrere Lösungsansätze, ich denk er wird zurechtkommen ;)


    Link :thumbup:
    Hello World

    Link schrieb:

    Wohingegen ich dir bei der Theorie mit der Endlosschleife nur bedingt zustimmen kann. Denn bis zu einem gewissen Grad muss man sich beim Schreiben von Funktionen auch ein Stück weit darauf verlassen, dass "gültige" Werte übergeben werden. Davor sind auch vorgefertigte Funktionen nie gefeit.

    Die Qualität einer Software (bzw. einer Funktion) hängt letztlich auch von der Robustheit ab. Die ist gerade ein Maß dafür, wie sich ein Programm auf nicht gültige Eingaben verhält.

    In diesem Fall ist es aber ein gültiger Pfad (zumindest unter Linux) und damit auch eine gültige Eingabe. Wenn eine Funktion auf manche gültigen Eingaben nicht funktioniert, ist das schlicht ein Fehler; entweder im Programmcode oder in der Dokumentation.

    Alte Diskussion? Stimmt, da war was. Dann muss ich natürlich noch einen Fehler bei dir suchen...
    ... und gefunden ;)
    Zeile 13 war wohl ein Versehen, aber die Eingabe /../ endet wieder in einer Endlosschleife.
    In diesem Fall ist es aber ein gültiger Pfad (zumindest unter Linux)

    Nicht nur das, denn im Windows-Dateisystem kannst du auch mit Linux-Pfaden navigieren. c:/windows/system32 wäre z.B. möglich. Daher empfehle ich generell, auch auf Windows-Webservern mit Linux-Pfaden zu arbeiten. Das einzige was nicht funktioniert ist "/" als Root-path.
    Klar, man könnte hier jetzt auch noch mit Exceptions arbeiten, aber in erster Linie wollte ich ja eine funktionierende RegEx-Möglichkeit zeigen.

    Zeile 13 war wohl ein Versehen, aber die Eingabe /../ endet wieder in einer Endlosschleife

    Meinst du damit /../ als alleinige Pfadangabe? Also ohne was davor oder dahinter, nur /../? Also falls ja macht das keinen Sinn, du kannst schließlich vom Root-pfad (/) nicht noch eine Verzeichnisebene nach oben springen. Somit wäre /../ ohnehin kein gültiger Pfad und wird daher durch meine Funktion ja automatisch als false zurückgegeben.

    PS: was meintest du damit als du sagteste dass die realpath-Funktion "nicht so toll" ist?


    Link :thumbup:
    Hello World
    Mit "zumindest unter Linux" meinte ich, dass Windows das Anlegen eines Verzeichnisses foo.. nicht erlaubt. (Klar kann man das umgehen, aber mit Bordmitteln sollte es AFAIK nicht möglich sein.)

    Doch, /../ ist ein gültiger Pfad. Wenn man im root-Verzeichnis eine Ebene zurück geht, landet man... oh wunder: wieder im root-Verzeichnis. Genau wie cd C:\.. unter Windows auch zu C:\ navigiert.

    zum PS: z.B. weil der Benutzer, unter dem PHP ausgeführt wird, execute-Permission auf jeden Ordner in der Pfadhierarchie benötigt.
    Hi,

    nagut dann müsste man den RegEx Pattern halt verändern sodass er vor dem ersten / keine anderen Zeichen erwartet und schon geht es. So oder so, möglich wäre es ohne weiteres.

    Wieso sollte man kein Verzeichnis "foo.." anlegen können? Versteh ich jetz nich.

    Zu realpath: stimmt das schränkt das ganze bisschen ein :-/ Schade. Aber auch das könnte man entsprechend abfangen mit Ausnahmen oder vorheriger Prüfung des Pfads oder auch mit chmod checken welche permissions man hat.

    Link :thumbup:
    Hello World