Php 将url字符串(路径和参数)解析为数组

Php 将url字符串(路径和参数)解析为数组,php,optimization,Php,Optimization,只是在这里写一个小函数,需要一些优化帮助 所有请求都重定向到索引页 我有一个将url解析为数组的函数 url的类型描述为: http://localhost/{user}/{page}/?sub_page={sub_page}&action={action} 例如: http://localhost/admin/stock/?sub_page=products&action=add 请求uri时,域被排除,因此my函数接受如下字符串: /admin/stock/?sub_pa

只是在这里写一个小函数,需要一些优化帮助

所有请求都重定向到索引页

我有一个将url解析为数组的函数

url的类型描述为:

http://localhost/{user}/{page}/?sub_page={sub_page}&action={action}
例如:

http://localhost/admin/stock/?sub_page=products&action=add
请求uri时,域被排除,因此my函数接受如下字符串:

/admin/stock/?sub_page=products&action=add
我的功能如下,警告这是非常程序化的

对于那些不屑于阅读和理解的人,我在底部添加了一个解释;)

基本上有一个主if语句,一个路径是如果没有定义查询字符串(没有“?”),另一个路径是如果“?”确实存在

我只是想让这个功能更好

值得让它成为一门课吗

本质上,我需要一个函数,它将
/{user}/{page}/?sub_page={sub_page}&action={action}
作为参数并返回

array(
    "user" => {user},
    "page" => {page},
    "sub_page" => {sub_page},
    "action" => {action}
)

干杯,Alex

一些建议可以让这个功能更好

首先,使用而不是分解来分隔主机名、路径和查询字符串

第二,在决定是否有查询字符串之前,先编写解析路径的代码,因为您可以任意解析路径

第三,不要使用
foreach
循环来复制参数,而是像这样使用:

// put $return_uri_array last so $parameter_array can't override values
$return_uri_array = array_merge($parameter_array, $return_uri_array); 
这是否应该是一个类取决于您的编程风格。一般来说,我总是使用类,因为在单元测试中模拟类更容易

最简洁的方法是这样一个正则表达式(没有完全测试,只是为了说明原理)

if(preg_匹配(')!http://localhost/(?P\w+(:/(?P\w+)/(?:\?子页面=(?P\w+)&操作=(?P\w+)!',$uri,$matches)){
返回$matches;
}
生成的数组也将具有匹配项的数字索引,但您可以忽略它们,或使用
数组\u intersect\u keys
筛选所需的关键字。
\w+
模式匹配所有“word”字符,您可以将其替换为类似于
[-a-zA-Z0-9\]
或类似的字符类

function uri_to_array($uri){
  $result = array();

  parse_str(substr($uri, strpos($uri, '?') + 1), $result);
  list($result['user'], $result['page']) = explode('/', trim($uri, '/'));

  return $result;
}

print_r(
  uri_to_array('/admin/stock/?sub_page=products&action=add')
);

/*
Array
(
    [sub_page] => products
    [action] => add
    [page] => stock
    [user] => admin
)
*/
演示:

如果您愿意

  • 做得好
  • 使用正则表达式
  • 使用相同的方法解析所有URL:s(
    parse_URL()
    不支持相对路径,下面称为
    only_path
这可能符合你的口味:

$url = 'http://localhost/admin/stock/?sub_page=products&action=add';
preg_match ("!^((?P<scheme>[a-zA-Z][a-zA-Z\d+-.]*):)?(((//(((?P<credentials>([a-zA-Z\d\-._~\!$&'()*+,;=%]*)(:([a-zA-Z\d\-._~\!$&'()*+,;=:%]*))?)@)?(?P<host>([\w\d-.%]+)|(\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3})|(\[([a-fA-F\d.:]+)\]))?(:(?P<port>\d*))?))(?<path>(/[a-zA-Z\d\-._~\!$&'()*+,;=:@%]*)*))|(?P<only_path>(/(([a-zA-Z\d\-._~\!$&'()*+,;=:@%]+(/[a-zA-Z\d\-._~\!$&'()*+,;=:@%]*)*))?)|([a-zA-Z\d\-._~\!$&'()*+,;=:@%]+(/[a-zA-Z\d\-._~\!$&'()*+,;=:@%]*)*)))?(?P<query>\?([a-zA-Z\d\-._~\!$&'()*+,;=:@%/?]*))?(?P<fragment>#([a-zA-Z\d\-._~\!$&'()*+,;=:@%/?]*))?$!u", $url, $matches);
$parts = array_intersect_key ($matches, array ('scheme' => '', 'credentials' => '', 'host' => '', 'port' => '', 'path' => '', 'query' => '', 'fragment' => '', 'only_path' => '', ));
var_dump ($parts);
参考资料

为了澄清,以下是用于制定正则表达式的相关文档:

  • RFC3986方案/协议
  • RFC3986用户和密码
  • RFC1035主机名
    • 或RFC3986 IPv4
    • 或RFC2732 IPv6
  • RFC3986查询
  • RFC3986片段

  • 看一下简化一些任务的方法。这看起来太复杂了。对于您想要的模式,一个简单的
    preg\u match()
    不是也有同样的作用吗?好吧,但是preg\u match不会返回关联数组??:你可以在结果中使用关联数组,如果你使用命名子模式谢谢,我现在就开始,发布我的结果。PCRE的东西太容易出错,并且是作为parse_url()的替代品出现的。parse_url()应该是起点。他问如何使他的函数“更好”。如果“更好”意味着代码更少,那么PCRE解决方案是最好的。如果“更好”意味着更少的代码加上对函数功能的清晰理解,那么正则表达式就不是最好的选择,我同意;-)
    function uri_to_array($uri){
      $result = array();
    
      parse_str(substr($uri, strpos($uri, '?') + 1), $result);
      list($result['user'], $result['page']) = explode('/', trim($uri, '/'));
    
      return $result;
    }
    
    print_r(
      uri_to_array('/admin/stock/?sub_page=products&action=add')
    );
    
    /*
    Array
    (
        [sub_page] => products
        [action] => add
        [page] => stock
        [user] => admin
    )
    */
    
    $url = 'http://localhost/admin/stock/?sub_page=products&action=add';
    preg_match ("!^((?P<scheme>[a-zA-Z][a-zA-Z\d+-.]*):)?(((//(((?P<credentials>([a-zA-Z\d\-._~\!$&'()*+,;=%]*)(:([a-zA-Z\d\-._~\!$&'()*+,;=:%]*))?)@)?(?P<host>([\w\d-.%]+)|(\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3})|(\[([a-fA-F\d.:]+)\]))?(:(?P<port>\d*))?))(?<path>(/[a-zA-Z\d\-._~\!$&'()*+,;=:@%]*)*))|(?P<only_path>(/(([a-zA-Z\d\-._~\!$&'()*+,;=:@%]+(/[a-zA-Z\d\-._~\!$&'()*+,;=:@%]*)*))?)|([a-zA-Z\d\-._~\!$&'()*+,;=:@%]+(/[a-zA-Z\d\-._~\!$&'()*+,;=:@%]*)*)))?(?P<query>\?([a-zA-Z\d\-._~\!$&'()*+,;=:@%/?]*))?(?P<fragment>#([a-zA-Z\d\-._~\!$&'()*+,;=:@%/?]*))?$!u", $url, $matches);
    $parts = array_intersect_key ($matches, array ('scheme' => '', 'credentials' => '', 'host' => '', 'port' => '', 'path' => '', 'query' => '', 'fragment' => '', 'only_path' => '', ));
    var_dump ($parts);
    
    // split the URL
    preg_match ('!^((?P<scheme>[a-zA-Z][a-zA-Z\d+-.]*):)?(((//(((?P<credentials>([a-zA-Z\d\-._~\!$&'()*+,;=%]*)(:([a-zA-Z\d\-._~\!$&'()*+,;=:%]*))?)@)?(?P<host>([\w\d-.%]+)|(\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3})|(\[([a-fA-F\d.:]+)\]))?(:(?P<port>\d*))?))(?<path>(/[a-zA-Z\d\-._~\!$&'()*+,;=:@%]*)*))|(?P<only_path>(/(([a-zA-Z\d\-._~\!$&'()*+,;=:@%]+(/[a-zA-Z\d\-._~\!$&'()*+,;=:@%]*)*))?)|([a-zA-Z\d\-._~\!$&'()*+,;=:@%]+(/[a-zA-Z\d\-._~\!$&'()*+,;=:@%]*)*)))?(\?(?P<query>([a-zA-Z\d\-._~\!$&'()*+,;=:@%/?]*)))?(#(?P<fragment>([a-zA-Z\d\-._~\!$&'()*+,;=:@%/?]*)))?$!u', $url, $matches);
    $parts = array_intersect_key ($matches, array ('scheme' => '', 'credentials' => '', 'host' => '', 'port' => '', 'path' => '', 'query' => '', 'fragment' => '', 'only_path' => '', ));
    
    // extract the user and page
    preg_match ('!/*(?P<user>.*)/(?P<page>.*)/!u', $parts['path'], $matches);
    $user_and_page = array_intersect_key ($matches, array ('user' => '', 'page' => '', ));
    
    // the query string stuff
    $query = array ();
    parse_str ($parts['query'], $query);