使用PHP解析URL中的相对路径

时间:2013-02-14 20:31:22

标签: php url path relative resolve

示例1:domain.com/dir_1/dir_2/dir_3/./../../../
应在浏览器中自然解析为= domain.com/

示例2:domain.com/dir_1/dir_2/dir_3/./../../../test/././../new_dir/
应解析为domain.com/new_dir/

示例3:domain.com/dir_1/dir_2/dir_3/./../../../test/dir4/../final
应解析为domain.com/test/final

问题是......我怎么能遍历字符串才能做到这一点?我觉得for()循环在这一点上会感到困惑..

Transfrom relative path into absolute URL using PHP

PHP: How to resolve a relative url

在这种情况下,

对我不起作用..我不需要参考点(基础),因为目标是清理我已经拥有的东西..

2 个答案:

答案 0 :(得分:8)

这是一个更简单的问题,然后你正在考虑它。您需要做的只是explode()字符上的/,并使用堆栈解析所有单个段。当您从左到右遍历数组时,如果看到.,则不执行任何操作。如果看到..,则从堆栈中弹出一个元素。否则,将元素推入堆栈。

$str = 'domain.com/dir_1/dir_2/dir_3/./../../../';
$array = explode( '/', $str);
$domain = array_shift( $array);

$parents = array();
foreach( $array as $dir) {
    switch( $dir) {
        case '.':
        // Don't need to do anything here
        break;
        case '..':
            array_pop( $parents);
        break;
        default:
            $parents[] = $dir;
        break;
    }
}

echo $domain . '/' . implode( '/', $parents);

这将正确解析所有测试用例中的网址。

请注意,错误检查会留给用户进行练习(例如,当$parents堆栈为空并且您尝试从其中弹出一些内容时)。

答案 1 :(得分:1)

这里你想要的是“replaceDots”功能。

它通过记住最后一个有效项目的位置来工作,然后如果你得到点,然后删除该项目。完整说明在此处“删除点细分”http://tools.ietf.org/html/rfc3986。在RFC页面上搜索删除点段。

您需要多个循环。内部循环向前扫描并查看下一部分,然后如果它是点,则跳过当前部分等,但它可能比这更棘手。或者考虑将其分解为部分然后遵循算法。

  1. 虽然输入缓冲区不为空,但循环如下:

    一个。如果输入缓冲区以前缀“../”或“./”开头,        然后从输入缓冲区中删除该前缀;否则,

    B中。如果输入缓冲区以前缀“/./”或“/。”开头,        在哪里“。”是一个完整的路径段,然后替换它        输入缓冲区中带有“/”的前缀;否则,

    ℃。如果输入缓冲区以前缀“/../”或“/ ..”开头,        其中“..”是一个完整的路径段,然后替换它        输入缓冲区中带有“/”的前缀,并删除最后一个        段及其前面的“/”(如果有的话)来自输出        缓冲;否则,

    d。如果输入缓冲区仅包含“。”或“..”,然后删除        来自输入缓冲区;否则,

    电子。将输入缓冲区中的第一个路径段移动到结尾        输出缓冲区,包括初始“/”字符(如果        任何)和任何后续角色,但不包括,        下一个“/”字符或输入缓冲区的结尾。

    1. 最后,输出缓冲区作为结果返回 remove_dot_segments。功能
  2. 它通过记住最后一个有效项目的位置来工作,然后如果你得到点,然后删除该项目。完整描述在这里

    这是我在C ++中的一个版本......

    ortl_funcimp(len_t) _str_remove_dots(char_t* s, len_t len) {
      len_t x,yy;
      /*
        Modifies the string in place by copying parts back. Not
        sure if this is the best way to do it since it involves
        many copies for deep relatives like ../../../../../myFile.cpp
    
        For each ../ it does one copy back. If the loop was implemented
        using writing into a buffer, you would have to do both, so this
        seems to be the best technique.
      */
      __checklenx(s,len);
      x = 0;
      while (x < len) {
        if (s[x] == _c('.')) {
          x++;
          if (x < len) {
            if (s[x] == _c('.')) {
              x++;
              if (x < len) {
                if (s[x] == _c('/')) { // ../
                  mem_move(&s[x],&s[x-2],(len-x)*sizeof(char_t));
                  len -= 2;
                  x -= 2;
                }
                else x++;
              }
              else len -= 2;// .. only
            }
            else if (s[x] == _c('/')){ // ./
              mem_move(&s[x],&s[x-1],(len-x)*sizeof(char_t));
              len--;
              x--;
            }
          }
          else --len;// terminating '.', remove
        }
        else if (s[x] == _c('/')) {
          x++;
          if (x < len) {
            if (s[x] == _c('.')) {
              x++;
              if (x < len) {
                if (s[x] == _c('/')) { // /./
                  mem_move(&s[x],&s[x-2],(len-x)*sizeof(char_t));
                  len -= 2;
                  x -= 2;
                }
                else if (s[x] == _c('.')) { // /..
                  x++;
                  if (x < len) { //
                    if (s[x] == _c('/')) {// /../
                      yy = x;
                      x -= 3;
                      if (x > 0) x--;
                      while ((x > 0) && (s[x] != _c('/'))) x--;
                      mem_move(&s[yy],&s[x],(len-yy) * sizeof(char_t));
                      len -= (yy - x);
                    }
                    else {
                      x++;
                    }
                  }
                  else {// ends with /..
                    x -= 3;
                    if (x > 0) x--;
                    while (x > 0 && s[x] != _c('/')) x--;
                    s[x] = _c('/');
                    x++;
                    len = x;
                  }
                }
                else x++;
              }
              else len--;// ends with /.
            }
            else x++;
          }
        }
        else x++;
      }
      return len;
    }