PHP Query String Manipulation

2020-04-01 07:32发布

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 all.

Some example cases:

It should ideally be something like:

function add_get_param($uri, $name, $value = null) { ... }
function remove_get_param($uri, $name) { ... }

Some example tests:

$var = add_get_param('http://mysite.com?param1=1&param2=2', 'param3', 3);
// http://mysite.com?param1=1&param2=2&param3=3

and:

$var = add_get_param('/dir/page.html?param1=1&param2=2#jump_to_bottom', 'param3');
// /dir/page.html?param1=1&param2=2&param3#jump_to_bottom

etc...

Alright, I wrote my own functions:

PHP: http://pastebin.org/170157 jQuery: http://pastebin.org/169981

4条回答
戒情不戒烟
2楼-- · 2020-04-01 08:00

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.

查看更多
女痞
3楼-- · 2020-04-01 08:01

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()

查看更多
Emotional °昔
4楼-- · 2020-04-01 08:04

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');
查看更多
疯言疯语
5楼-- · 2020-04-01 08:20

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...

查看更多
登录 后发表回答