PHP Query String Manipulation

前端 未结 4 1745
我寻月下人不归
我寻月下人不归 2021-01-17 06:16

Any one have the ultimate PHP function(s) to add/remove parameters from a query string? It needs to handle all possible cases, Ive seen ones that handle some cases, but not

相关标签:
4条回答
  • 2021-01-17 06:46

    Alright I wrote my own, based on zerkms's sketch

    class URL {
        public static function each_get($url, $each_callback = null, $last_callback = null) {
            $url = parse_url($url);
            $result = '';
            if (isset($url['scheme'])) $result .= $url['scheme'].'://';
            if (isset($url['user'])) {
                $result .= $url['user'];
                if (isset($url['pass'])) $result .= ':'.$url['pass'];
                $result .= '@';
            }
            if (isset($url['host'])) $result .= $url['host'];
            if (isset($url['path'])) $result .= $url['path'];
            if (!isset($url['query'])) $url['query'] = '';
            $query = array();
            $callable = is_callable($each_callback);
            foreach (explode('&', $url['query']) as $param) {
                if ($param == '') {
                    continue;
                }
                if (!$callable) {
                    $query[] = $param;
                    continue;
                }
                $callback_result = $each_callback($param);
                if ($callback_result === true) {
                    $query[] = $param;
                } elseif ($callback_result !== false) {
                    $query[] = $callback_result;
                }
            }
            if (is_callable($last_callback)) {
                $query = $last_callback($query);
            }
            $query = implode('&', $query);
            $result .= strlen($query) ? '?'.$query : '';
            if (isset($url['fragment'])) $result .= '#'.$url['fragment'];
            return $result;
        }
    
        public static function add_get($url, $new_param, $new_value = null) {
            return
                static::each_get($url, function($param) {
                    $param = explode('=', $param);
                    if (isset($param[1])) {
                        return $param[0].'='.$param[1];
                    }
                    return $param[0];
                }, function($query) use($new_param, $new_value) {
                    if ($new_value === null) {
                        $query[] = $new_param;
                    } else {
                        $query[] = $new_param.'='.$new_value;
                    }
                    return $query;
                });
        }
    
        public static function remove_get($url, $remove_param) {
            return 
                static::each_get($url, function($param) use($remove_param) {
                    $param = explode('=', $param);
                    return $param[0] != $remove_param;
                });
        }
    
        public static function replace_get($url, $name, $value = null) {
            return static::add_get(static::remove_get($url, $name), $name, $value);
        }
    }
    

    And here is my limited test cases:

    function test($test, $result) {
        static $i;
        $i++;
        if ($test !== $result) {
            echo $i.' Fail: got '.$test.' should be '.PHP_EOL.'            '.$result.'<br>'.PHP_EOL;
        } else {
            echo $i.' Pass: '.$test.'<br>'.PHP_EOL;
        }
    }
    
    $urls = array(
        0 => 'http://user:pass@www.site.com?a=1',
        1 => 'http://www.site.com?a=1',
        2 => '/dir/page.php?a=1',
        3 => '/dir/?a=1',
        4 => '/dir?a=1',
        5 => '/?a=1',
        6 => '?a=1',
        7 => 'http://user:pass@www.site.com?a=1#hash',
        8 => 'http://www.site.com?a=1#hash',
        9 => '/dir/page.php?a=1#hash',
        10 => '/dir/?a=1#hash',
        11 => '/dir?a=1#hash',
        12 => '/?a=1#hash',
        13 => '?a=1#hash',
        14 => 'http://www.site.com/?a=1',
        15 => 'http://www.site.com/?a=1#hash',
        16 => '/dir/page.php?a=1&b=2&c=3',
    );
    
    test(URL::add_get($urls[0], 'b', 2), 'http://user:pass@www.site.com?a=1&b=2');
    test(URL::add_get($urls[1], 'b', 2), 'http://www.site.com?a=1&b=2');
    test(URL::add_get($urls[2], 'b', 2), '/dir/page.php?a=1&b=2');
    test(URL::add_get($urls[3], 'b', 2), '/dir/?a=1&b=2');
    test(URL::add_get($urls[4], 'b', 2), '/dir?a=1&b=2');
    test(URL::add_get($urls[5], 'b', 2), '/?a=1&b=2');
    test(URL::add_get($urls[6], 'b', 2), '?a=1&b=2');
    test(URL::add_get($urls[7], 'b', 2), 'http://user:pass@www.site.com?a=1&b=2#hash');
    test(URL::add_get($urls[8], 'b', 2), 'http://www.site.com?a=1&b=2#hash');
    test(URL::add_get($urls[9], 'b', 2), '/dir/page.php?a=1&b=2#hash');
    test(URL::add_get($urls[10], 'b'), '/dir/?a=1&b#hash');
    test(URL::add_get($urls[11], 'berLongBla 1235_+'), '/dir?a=1&berLongBla 1235_+#hash');
    test(URL::add_get($urls[12], 'a', 2), '/?a=1&a=2#hash');
    test(URL::add_get($urls[13], 'a[]', 2), '?a=1&a[]=2#hash');
    test(URL::add_get($urls[14], 'b', 2), 'http://www.site.com/?a=1&b=2');
    test(URL::add_get($urls[15], 'b', 2), 'http://www.site.com/?a=1&b=2#hash');
    
    test(URL::remove_get($urls[0], 'a'), 'http://user:pass@www.site.com');
    test(URL::remove_get($urls[1], 'a'), 'http://www.site.com');
    test(URL::remove_get($urls[2], 'a'), '/dir/page.php');
    test(URL::remove_get($urls[3], 'a'), '/dir/');
    test(URL::remove_get($urls[4], 'a'), '/dir');
    test(URL::remove_get($urls[5], 'a'), '/');
    test(URL::remove_get($urls[6], 'a'), '');
    test(URL::remove_get($urls[16], 'b'), '/dir/page.php?a=1&c=3');
    

    I also converted it to JavaScript/jQuery

    URL = {};
    URL.parse_url = function(str, component) {
        var o = {
            strictMode: false,
            key: ["source","protocol","authority","userInfo","user","password","host","port","relative","path","directory","file","query","anchor"],
            q:   {
                name:   "queryKey",
                parser: /(?:^|&)([^&=]*)=?([^&]*)/g
            },
            parser: {
                strict: /^(?:([^:\/?#]+):)?(?:\/\/((?:(([^:@]*):?([^:@]*))?@)?([^:\/?#]*)(?::(\d*))?))?((((?:[^?#\/]*\/)*)([^?#]*))(?:\?([^#]*))?(?:#(.*))?)/,
                loose:  /^(?:(?![^:@]+:[^:@\/]*@)([^:\/?#.]+):)?(?:\/\/\/?)?((?:(([^:@]*):?([^:@]*))?@)?([^:\/?#]*)(?::(\d*))?)(((\/(?:[^?#](?![^?#\/]*\.[^?#\/.]+(?:[?#]|$)))*\/?)?([^?#\/]*))(?:\?([^#]*))?(?:#(.*))?)/ // Added one optional slash to post-protocol to catch file:/// (should restrict this)
            }
        };
    
        var m = o.parser[o.strictMode ? "strict" : "loose"].exec(str),
        uri = {},
        i   = 14;
        while (i--) {uri[o.key[i]] = m[i] || "";}
    
        switch (component) {
            case 'PHP_URL_SCHEME':
                return uri.protocol;
            case 'PHP_URL_HOST':
                return uri.host;
            case 'PHP_URL_PORT':
                return uri.port;
            case 'PHP_URL_USER':
                return uri.user;
            case 'PHP_URL_PASS':
                return uri.password;
            case 'PHP_URL_PATH':
                return uri.path;
            case 'PHP_URL_QUERY':
                return uri.query;
            case 'PHP_URL_FRAGMENT':
                return uri.anchor;
            default:
                var retArr = {};
                if (uri.protocol !== '') {retArr.scheme=uri.protocol;}
                if (uri.host !== '') {retArr.host=uri.host;}
                if (uri.port !== '') {retArr.port=uri.port;}
                if (uri.user !== '') {retArr.user=uri.user;}
                if (uri.password !== '') {retArr.pass=uri.password;}
                if (uri.path !== '') {retArr.path=uri.path;}
                if (uri.query !== '') {retArr.query=uri.query;}
                if (uri.anchor !== '') {retArr.fragment=uri.anchor;}
                return retArr;
        }
    }
    
    URL.each_get = function(url, each_callback, last_callback) {
        url = URL.parse_url(url);
        var result = '';
        if (url.scheme) result += url.scheme+'://';
        if (url.user) {
            result += url.user;
            if (url.pass) result += ':'+url.pass;
            result += '@';
        }
        if (url.host) result += url.host;
        if (url.path) result += url.path;
        if (!url.query) url.query = '';
        var query = [];
        $.each(url.query.split('&'), function(key, param) {
            if (param == '') {
                return;
            }
            if (!each_callback) {
                query.push(param);
                return;
            }
            var callback_result = each_callback(param);
            if (callback_result === true) {
                query.push(param);
            } else if (callback_result !== false) {
                query.push(callback_result);
            }
        });
        if (last_callback) {
            query = last_callback(query);
        }
        query = query.join('&');
        result += query.length ? '?'+query : '';
        if (url.fragment) result += '#'+url.fragment;
        return result;
    }
    
    
    URL.add_get = function(url, new_param, new_value) {
        return URL.each_get(url, function(param) {
                param = param.split('=');
                if (typeof param[1] != 'undefined') {
                    return param[0]+'='+param[1];
                }
                return param[0];
            }, function(query) {
                if (typeof new_value == 'undefined') {
                    query.push(new_param);
                } else {
                    query.push(new_param+'='+new_value);
                }
                return query;
            });
    }
    
    URL.remove_get = function(url, remove_param) {
        return URL.each_get(url, function(param) {
                param = param.split('=');
                return param[0] != remove_param;
            });
    }
    
    URL.replace_get = function(url, name, value) {
        return URL.add_get(URL.remove_get(url, name), name, value);
    }
    
    var i = 0;
    function test(test, result) {
        i++;
        if (test !== result) {
            console.debug(i+' Fail: got '+test+' should be '+result);
        } else {
            console.debug(i+' Pass: '+test);
        }
    }
    

    And the limited text cases:

    var urls = {
        0 : 'http://user:pass@www.site.com?a=1',
        1 : 'http://www.site.com?a=1',
        2 : '/dir/page.php?a=1',
        3 : '/dir/?a=1',
        4 : '/dir?a=1',
        5 : '/?a=1',
        6 : '?a=1',
        7 : 'http://user:pass@www.site.com?a=1#hash',
        8 : 'http://www.site.com?a=1#hash',
        9 : '/dir/page.php?a=1#hash',
        10 : '/dir/?a=1#hash',
        11 : '/dir?a=1#hash',
        12 : '/?a=1#hash',
        13 : '?a=1#hash',
        14 : 'http://www.site.com/?a=1',
        15 : 'http://www.site.com/?a=1#hash',
        16 : '/dir/page.php?a=1&b=2&c=3'
    };
    
    test(URL.add_get(urls[0], 'b', 2), 'http://user:pass@www.site.com?a=1&b=2');
    test(URL.add_get(urls[1], 'b', 2), 'http://www.site.com?a=1&b=2');
    test(URL.add_get(urls[2], 'b', 2), '/dir/page.php?a=1&b=2');
    test(URL.add_get(urls[3], 'b', 2), '/dir/?a=1&b=2');
    test(URL.add_get(urls[4], 'b', 2), '/dir?a=1&b=2');
    test(URL.add_get(urls[5], 'b', 2), '/?a=1&b=2');
    test(URL.add_get(urls[6], 'b', 2), '?a=1&b=2');
    test(URL.add_get(urls[7], 'b', 2), 'http://user:pass@www.site.com?a=1&b=2#hash');
    test(URL.add_get(urls[8], 'b', 2), 'http://www.site.com?a=1&b=2#hash');
    test(URL.add_get(urls[9], 'b', 2), '/dir/page.php?a=1&b=2#hash');
    test(URL.add_get(urls[10], 'b'), '/dir/?a=1&b#hash');
    test(URL.add_get(urls[11], 'berLongBla 1235_+'), '/dir?a=1&berLongBla 1235_+#hash');
    test(URL.add_get(urls[12], 'a', 2), '/?a=1&a=2#hash');
    test(URL.add_get(urls[13], 'a[]', 2), '?a=1&a[]=2#hash');
    test(URL.add_get(urls[14], 'b', 2), 'http://www.site.com/?a=1&b=2');
    test(URL.add_get(urls[15], 'b', 2), 'http://www.site.com/?a=1&b=2#hash');
    
    0 讨论(0)
  • 2021-01-17 06:58

    This is the sketch for the function you can start with:

    function add_get_param($url, $param, $value)
    {
            $parts_url = parse_url($url);
    
            parse_str($parts_url['query'], $parts_query);
    
            $parts_query[$param] = $value;
    
            return $parts_url['scheme'] . '://' . $parts_url['host'] . '/' . $parts_url['path'] . '?' . http_build_query($parts_query);
    }
    
    var_dump(add_get_param('http://mysite.com?param1=1&param2=2', 'param3', 3));
    

    UPD: since parse_str breaks the data (replaces dots with underscores) I don't think this sketch is useful.

    0 讨论(0)
  • 2021-01-17 07:07

    I don't know about the ultimate solution. But PHP has several very helpful native functions that making your own defined function about should be easy.

    Check out: html_build_query(), parse_str(), and parse_url()

    0 讨论(0)
  • 2021-01-17 07:08

    try the built in http_build_query and parse_str functions, they use associative arrays in the same style as $_GET as intermediates, but seem to do what you want...

    0 讨论(0)
提交回复
热议问题