wake-up-neo.net

Wie verbinde ich Dateisystempfad-Zeichenfolgen in PHP?

Gibt es eine eingebaute Funktion in PHP, um Pfadzeichenfolgen intelligent zu verknüpfen? Die Funktion, die als Argumente "abc/de /" und "/fg/x.php" enthält, sollte "abc/de/fg/x.php" zurückgeben. Das gleiche Ergebnis sollte mit "abc/de" und "fg/x.php" als Argumente für diese Funktion angegeben werden.

Wenn nicht, gibt es eine verfügbare Klasse? Es kann auch nützlich sein, um Pfade zu teilen oder Teile davon zu entfernen. Wenn Sie etwas geschrieben haben, können Sie Ihren Code hier veröffentlichen?

Es ist in Ordnung, immer "/" zu verwenden, ich codiere nur für Linux.

In Python gibt es os.path.join(), was großartig ist.

62
user89021

Da dies eine beliebte Frage zu sein scheint und die Kommentare sich mit "Feature-Vorschlägen" oder "Fehlerberichten" füllen, müssen Sie nur zwei Strings mit einem Schrägstrich verknüpfen, ohne dass dabei Schrägstriche zwischen den beiden Strings eingefügt werden. Das ist alles. Nicht mehr und nicht weniger. Es wertet weder die tatsächlichen Pfade auf der Festplatte aus, noch behält es den anfänglichen Schrägstrich bei (fügen Sie den Pfad bei Bedarf wieder hinzu, zumindest können Sie sicher sein, dass dieser Code immer einen String ohne - Slash zurückgibt).

join('/', array(trim("abc/de/", '/'), trim("/fg/x.php", '/')));

Das Endergebnis ist immer ein Pfad ohne Schrägstriche am Anfang oder Ende und ohne doppelte Schrägstriche. Fühlen Sie sich frei, daraus eine Funktion zu machen.

BEARBEITEN: Hier ist ein Nice-Funktions-Wrapper für das obige Snippet. Sie können beliebig viele Pfadausschnitte übergeben, entweder als Array oder als separate Argumente:

function joinPaths() {
    $args = func_get_args();
    $paths = array();
    foreach ($args as $arg) {
        $paths = array_merge($paths, (array)$arg);
    }

    $paths = array_map(create_function('$p', 'return trim($p, "/");'), $paths);
    $paths = array_filter($paths);
    return join('/', $paths);
}

echo joinPaths(array('my/path', 'is', '/an/array'));
//or
echo joinPaths('my/paths/', '/are/', 'a/r/g/u/m/e/n/t/s/');

:O)

46
deceze
function join_paths() {
    $paths = array();

    foreach (func_get_args() as $arg) {
        if ($arg !== '') { $paths[] = $arg; }
    }

    return preg_replace('#/+#','/',join('/', $paths));
}

Meine Lösung ist einfacher und ähnelt der Funktionsweise von Python os.path.join

Betrachten Sie diese Testfälle

array               my version    @deceze      @david_miller    @mark

['','']             ''            ''           '/'              '/'
['','/']            '/'           ''           '/'              '/'
['/','a']           '/a'          'a'          '//a'            '/a'
['/','/a']          '/a'          'a'          '//a'            '//a'
['abc','def']       'abc/def'     'abc/def'    'abc/def'        'abc/def'
['abc','/def']      'abc/def'     'abc/def'    'abc/def'        'abc//def'
['/abc','def']      '/abc/def'    'abc/def'    '/abc/def'       '/abc/def'
['','foo.jpg']      'foo.jpg'     'foo.jpg'    '/foo.jpg'       '/foo.jpg'
['dir','0','a.jpg'] 'dir/0/a.jpg' 'dir/a.jpg'  'dir/0/a.jpg'    'dir/0/a.txt'
106
Riccardo Galli

Die Funktion von @ deceze behält den führenden Pfad/nicht bei, wenn versucht wird, einen Pfad zu verbinden, der mit einem absoluten Unix-Pfad beginnt, z. joinPaths('/var/www', '/vhosts/site');.

function unix_path() {
  $args = func_get_args();
  $paths = array();

  foreach($args as $arg) {
    $paths = array_merge($paths, (array)$arg);
  }

  foreach($paths as &$path) {
    $path = trim($path, '/');
  }

  if (substr($args[0], 0, 1) == '/') {
    $paths[0] = '/' . $paths[0];
  }

  return join('/', $paths);
}
17
David Miller

Meine nehmen:

function trimds($s) {
    return rtrim($s,DIRECTORY_SEPARATOR);
}

function joinpaths() {
    return implode(DIRECTORY_SEPARATOR, array_map('trimds', func_get_args()));
}

Ich hätte eine anonyme Funktion für trimds verwendet, aber ältere Versionen von PHP unterstützen sie nicht.

Beispiel:

join_paths('a','\\b','/c','d/','/e/','f.jpg'); // a\b\c\d\e\f.jpg (on Windows)

Aktualisierte April 2013Marz 2014 Mai 2018 :

function join_paths(...$paths) {
    return preg_replace('~[/\\\\]+~', DIRECTORY_SEPARATOR, implode(DIRECTORY_SEPARATOR, $paths));
}

Dieser korrigiert alle Schrägstriche entsprechend Ihrem Betriebssystem, entfernt keinen führenden Schrägstrich und bereinigt mehrere Schrägstriche hintereinander.

14
mpen

Wenn Sie wissen, dass die Datei/das Verzeichnis vorhanden ist , können Sie zusätzliche Schrägstriche hinzufügen (die möglicherweise nicht erforderlich sind). Rufen Sie dann realpath auf. dh.

realpath(join('/', $parts));

Dies ist natürlich nicht ganz das Gleiche wie die Python -Version, kann aber in vielen Fällen gut genug sein.

6
George Lund

Eine Alternative ist die Verwendung von implode() und explode().

$a = '/a/bc/def/';
$b = '/q/rs/tuv/path.xml';

$path = implode('/',array_filter(explode('/', $a . $b)));

echo $path;  // -> a/bc/def/q/rs/tuv/path.xml
4
Chris J

um Teile von Pfaden zu erhalten, können Sie pathinfo http://nz2.php.net/manual/de/function.pathinfo.php verwenden.

für den Beitritt sieht die Antwort von @deceze gut aus

2
bumperbox

Eine andere Art, diesen Angriff anzugreifen:

function joinPaths() {
  $paths = array_filter(func_get_args());
  return preg_replace('#/{2,}#', '/', implode('/', $paths));
}
2
stompydan

Beste Lösung gefunden:

function joinPaths($leftHandSide, $rightHandSide) { 
    return rtrim($leftHandSide, '/') .'/'. ltrim($rightHandSide, '/'); 
}

HINWEIS: Aus dem Kommentar von user89021 kopiert

1
Basil Musa

Die folgende Lösung verwendet die von @RiccardoGalli vorgeschlagene Logik, wird jedoch verbessert, um die DIRECTORY_SEPARATOR-Konstante zu verwenden, wie von @Qix und @ FélixSaparelli vorgeschlagen, und, wichtiger noch, mit jedes angegebene Element zu trimmen, um nur den reinen Platz zu vermeiden Namen, die im letzten Pfad erscheinen (dies war in meinem Fall eine Voraussetzung).

In Bezug auf die Flucht des Verzeichnisseparators innerhalb des preg_replace()-Musters habe ich, wie Sie sehen können, die preg_quote()-Funktion verwendet, die den Job gut erledigt.
Außerdem würde ich nur mutiple-Trennzeichen (RegExp-Quantifizierer {2,}) ersetzen.

// PHP 7.+
function paths_join(string ...$parts): string {
    $parts = array_map('trim', $parts);
    $path = [];

    foreach ($parts as $part) {
        if ($part !== '') {
            $path[] = $part;
        }
    }

    $path = implode(DIRECTORY_SEPARATOR, $path);

    return preg_replace(
        '#' . preg_quote(DIRECTORY_SEPARATOR) . '{2,}#',
        DIRECTORY_SEPARATOR,
        $path
    );
}
1

Das scheint ganz gut zu funktionieren und sieht für mich recht ordentlich aus.

private function JoinPaths() {
  $slash = DIRECTORY_SEPARATOR;
  $sections = preg_split(
          "@[/\\\\]@",
          implode('/', func_get_args()),
          null,
          PREG_SPLIT_NO_EMPTY);
  return implode($slash, $sections);
}
1
Kenny Hung

Dies ist eine korrigierte Version der von deceze geposteten Funktion. Ohne diese Änderung wird joinPaths ('', 'foo.jpg') zu '/foo.jpg'.

function joinPaths() {
    $args = func_get_args();
    $paths = array();
    foreach ($args as $arg)
        $paths = array_merge($paths, (array)$arg);

    $paths2 = array();
    foreach ($paths as $i=>$path)
    {   $path = trim($path, '/');
        if (strlen($path))
            $paths2[]= $path;
    }
    $result = join('/', $paths2); // If first element of old path was absolute, make this one absolute also
    if (strlen($paths[0]) && substr($paths[0], 0, 1) == '/')
        return '/'.$result;
    return $result;
}
1
Dwayne

Die folgende Funktion verhält sich wie Node's path.resolve :

function resolve_path() {
    $working_dir = getcwd();
    foreach(func_get_args() as $p) {
        if($p === null || $p === '') continue;
        elseif($p[0] === '/') $working_dir = $p;
        else $working_dir .= "/$p";
    }
    $working_dir = preg_replace('~/{2,}~','/', $working_dir);
    if($working_dir === '/') return '/';
    $out = [];
    foreach(explode('/',rtrim($working_dir,'/')) as $p) {
        if($p === '.') continue;
        if($p === '..') array_pop($out);
        else $out[] = $p;
    }
    return implode('/',$out);
}

Testfälle:

resolve_path('/foo/bar','./baz')         # /foo/bar/baz
resolve_path('/foo/bar','/tmp/file/')    # /tmp/file
resolve_path('/foo/bar','/tmp','file')   # /tmp/file
resolve_path('/foo//bar/../baz')         # /foo/baz
resolve_path('/','foo')                  # /foo
resolve_path('/','foo','/')              # /
resolve_path('wwwroot', 'static_files/png/', '../gif/image.gif') 
                                  # __DIR__.'/wwwroot/static_files/gif/image.gif'
0
mpen

Von der großartigen Antwort von Ricardo Galli, ein bisschen Verbesserung, um das Protokoll-Präfix nicht zu töten.

Die Idee ist, das Vorhandensein eines Protokolls in einem Argument zu testen und in das Ergebnis einzufügen. ACHTUNG: Dies ist eine naive Implementierung!

Zum Beispiel:

array("http://domain.de","/a","/b/")

ergebnisse zum (Protokoll halten)

"http://domain.de/a/b/"

statt (Tötungsprotokoll)

"http:/domain.de/a/b/"

http://codepad.org/hzpWmpzk benötigt jedoch eine bessere Code-Schreibfähigkeit.

0
nicolallias
function path_combine($paths) {
  for ($i = 0; $i < count($paths); ++$i) {
    $paths[$i] = trim($paths[$i]);
  }

  $dirty_paths = explode(DIRECTORY_SEPARATOR, join(DIRECTORY_SEPARATOR, $paths));
  for ($i = 0; $i < count($dirty_paths); ++$i) {
    $dirty_paths[$i] = trim($dirty_paths[$i]);
  }

  $unslashed_paths = array();

  for ($i = 0; $i < count($dirty_paths); ++$i) {
    $path = $dirty_paths[$i];
    if (strlen($path) == 0) continue;
    array_Push($unslashed_paths, $path);
  }

  $first_not_empty_index = 0;
  while(strlen($paths[$first_not_empty_index]) == 0) {
    ++$first_not_empty_index;
  }
  $starts_with_slash = $paths[$first_not_empty_index][0] == DIRECTORY_SEPARATOR;

  return $starts_with_slash
    ? DIRECTORY_SEPARATOR . join(DIRECTORY_SEPARATOR, $unslashed_paths)
    : join(DIRECTORY_SEPARATOR, $unslashed_paths);
}

Beispielverwendung:

$test = path_combine([' ', '/cosecheamo', 'pizze', '///// 4formaggi', 'GORGONZOLA']);
echo $test;

Wird ausgeben:

/cosecheamo/pizze/4formaggi/GORGONZOLA
0
user6307854

Eleganter Python-inspirierter PHP Einzeiler für den Pfad.

Dieser Code verwendet kein unnötiges Array.

Multi-Plattform

function os_path_join(...$parts) {
  return preg_replace('#'.DIRECTORY_SEPARATOR.'+#', DIRECTORY_SEPARATOR, implode(DIRECTORY_SEPARATOR, array_filter($parts)));
}

Unix-basierte Systeme

function os_path_join(...$parts) {
  return preg_replace('#/+#', '/', implode('/', array_filter($parts)));
}

Unix-basiertes System ohne REST -Parameter (explizite PEP8-Philosophie nicht beachten):

function os_path_join() {
  return preg_replace('#/+#', '/', implode('/', array_filter(func_get_args())));
}

Verwendungszweck

$path = os_path_join("", "/", "mydir/", "/here/");

Bonus: Wenn Sie wirklich Python folgen möchten, folgen Sie os.path.join (). Erstes Argument ist erforderlich:

function os_path_join($path=null, ...$paths) {
  if (!is_null($path)) {
    throw new Exception("TypeError: join() missing 1 required positional argument: 'path'", 1);
  }
  $path = rtrim($path, DIRECTORY_SEPARATOR);
  foreach ($paths as $key => $current_path) {
    $paths[$key] = $paths[$key] = trim($current_path, DIRECTORY_SEPARATOR);
  }
  return implode(DIRECTORY_SEPARATOR, array_merge([$path], array_filter($paths)));
}

Überprüfen Sie die Quelle von os.path.join (), wenn Sie möchten: https://github.com/python/cpython/blob/master/Lib/ntpath.py

0
jedema

Ich liebe Riccardos Antwort und ich denke, es ist die beste Antwort.

Ich verwende es, um Pfade in url building zu verbinden, aber mit einer kleinen Änderung, um den doppelten Schrägstrich von Protokollen zu handhaben:

function joinPath () {
    $paths = array();

    foreach (func_get_args() as $arg) {
        if ($arg !== '') { $paths[] = $arg; }
    }

    // Replace the slash with DIRECTORY_SEPARATOR
    $paths = preg_replace('#/+#', '/', join('/', $paths));
    return preg_replace('#:/#', '://', $paths);
}
0
Smily

Betriebssystemunabhängige Version basierend auf die Antwort von mpen , jedoch in einer einzelnen Funktion gekapselt und mit der Option, einen nachgestellten Pfadtrenner hinzuzufügen.

function joinPathParts($parts, $trailingSeparator = false){
    return implode(
        DIRECTORY_SEPARATOR, 
        array_map(
            function($s){
                return rtrim($s,DIRECTORY_SEPARATOR);
            }, 
            $parts)
        )
        .($trailingSeparator ? DIRECTORY_SEPARATOR : '');
}

Oder für Sie Einzeilerliebhaber:

function joinPathParts($parts, $trailingSeparator = false){
    return implode(DIRECTORY_SEPARATOR, array_map(function($s){return rtrim($s,DIRECTORY_SEPARATOR);}, $parts)).($trailingSeparator ? DIRECTORY_SEPARATOR : '');
}

Nennen Sie es einfach mit einer Reihe von Pfadteilen:

// No trailing separator - ex. C:\www\logs\myscript.txt
$logFile = joinPathParts([getcwd(), 'logs', 'myscript.txt']);

// Trailing separator - ex. C:\www\download\images\user1234\
$dir = joinPathParts([getcwd(), 'download', 'images', 'user1234'], true);
0
Magnus W