DanielM
DanielM

Reputation: 307

Add, change, and remove GET parameters from query string

Let's say the current query string is the following

$_SERVER['QUERY_STRING']:
apple=green&banana=yellow2&navi=blue&clouds=white&car=black

I need a function which can add and remove several parameters from the query string. For example:

echo ChangeQueryString('eyes=2&fingers=10&car=purple', 'clouds&apple');

should give

banana=yellow2&navi=blue&car=purple&eyes=2&fingers=10

So, not only should the function be able to add new parameters (eyes=2&fingers=10), but it should also change the ones which are already present (car=black => car=purple).

All these new and changed parameters could be passed in the first argument of the function. Separated by "&".

The second argument of the function should pass all the keys of the parameters which should be removed from the query string, if present.

I only managed the first part which can add and replace parameters. But maybe somebody has a more efficient way, including the second argument for removing things from the query string.

Actually in the end I need the complete current URL. That's why I added PHP_SELF. Though the removing part is not there yet...

function ChangeQueryString ($add, $remove) {

    if (empty($_SERVER['QUERY_STRING'])){

        $final_url = $_SERVER['PHP_SELF']."?".$add;

    } else {

        $query_string_url_addition = $_SERVER['QUERY_STRING'].'&'.$add;

        parse_str($query_string_url_addition, $query_array);

        $final_url = $_SERVER['PHP_SELF']."?".http_build_query($query_array);

    }

    return $final_url;

}

Upvotes: 0

Views: 1590

Answers (6)

Marco Panichi
Marco Panichi

Reputation: 1185

My function satisfies your request, although it does not using strings, but rather array.

function change_query( $arguments=array(), $url=false )
{
    // url
    if( $url===false ) $url = (isset($_SERVER['HTTPS']) && $_SERVER['HTTPS'] === 'on' ? "https" : "http"). "://$_SERVER[HTTP_HOST]$_SERVER[REQUEST_URI]";
    
    // hash
    $hash = explode( '#', $url );
    $url = $hash[0];
    $hash = ( isset($hash[1]) )? '#'.$hash[1] : '';
    
    // query
    $query = explode( '?', $url );
    $url = $query[0];
    $query = ( isset($query[1]) )? $query[1] : '';
    parse_str( $query, $query );
    
    // remove or replace
    foreach( $arguments as $k=>$v )
    {
        if( $v==null ) unset( $query[$k] );
        else $query[$k] = $v;
    }
    
    // finalize query
    $query = ( !empty( $query ) )? '?'.http_build_query( $query ) : '' ;
    
    // return
    return $url.$query.$hash;
    
}

Please note:

  • The $url variable is built using a snippet taken from (this answer)[https://stackoverflow.com/a/6768831/162049]
  • If you pass an $url to the function, it will use that, otherwise it will use the current url of the page
  • The $arguments array has elements like =>
  • If you set => null, that variable will be removed from the query string

Usage:

echo change_query(
    array(
        'foo' => 'changed',
        'bar' => null,
        'lorem' => "Ipsum"
    ),
    'https://stackoverflow.com/?foo=test&bar=10'
);

// output
// https://stackoverflow.com/?foo=changed&lorem=Ipsum

Upvotes: 0

Don't Panic
Don't Panic

Reputation: 41820

After you've parsed the query strings to arrays, you can merge and diff those to produce the result you want.

function ChangeQueryString($original, $add, $remove) {
    $new = [];
    parse_str($original, $new[0]);
    parse_str($add, $new[1]);
    parse_str($remove, $delete);
    return http_build_query(array_diff_key(array_merge(...$new), $delete));
}

This will only handle simple query strings. If there are any nested elements you'll need a recursive solution. But that's true for any of these answers as well as your original function.

Upvotes: 1

Markus Zeller
Markus Zeller

Reputation: 9145

You should not alter the PHP magic GLOBALS.

Using arrays is more readable than strings. So try this modification which may fit your needs.

$queryString = 'apple=green&banana=yellow2&navi=blue&clouds=white&car=black';

echo changeQueryString($queryString, ['eyes' => 2, 'fingers' => 10], ['clouds', 'apple']);


function changeQueryString(string $queryString, array $add, array $remove): string
{
    $queryValues = [];
    parse_str($queryString ?? '', $queryValues);

    foreach ($remove as $key) {
        if (isset($queryValues[$key])) unset($queryValues[$key]);
    }

    return http_build_query(array_merge($queryValues, $add));
}

Upvotes: 0

user11146000
user11146000

Reputation:

function changeQueryString($queryStr, $updateStr, $removeStr) {
    parse_str($queryStr, $queryArr);
    parse_str($updateStr, $updateArr);
    parse_str($removeStr, $removeArr);
    $changedArr = array_merge($queryArr, $updateArr);
    foreach($removeArr as $k => $v) {
        if(array_key_exists($k, $changedArr)) {
            unset($changedArr[$k]);
        }
    }
    return http_build_query($changedArr);
}

$str = 'apple=green&banana=yellow2&navi=blue&clouds=white&car=black';
$changedQuery = changeQueryString($str, 'eyes=2&fingers=10&car=purple', 'clouds&apple');
var_dump($changedQuery);

This should work for you, utilizing parse_str(), array_merge() and http_build_query()

Upvotes: 3

waterloomatt
waterloomatt

Reputation: 3742

As the first comment pointed out, if you work with the $_GET global array, then you're just working with an array in which you can add, remove and generally manipulate in any fashion.

<?php
// Sample query string: ?apple=green&banana=yellow2&navi=blue&clouds=white&car=black

// You can either copy the query string to a new variable or work with the $_GET array directly. 
// In this case, I am copying it to a new array to preserve the original. 
$queryParams = $_GET;

// Get the value of clouds
$cloudColour = $queryParams ['clouds'];

// Change car from black to purple
$queryParams['car'] = 'purple';

// Change apple to red
$queryParams['apple'] = 'red';

// Remove banana
unset($queryParams['banana']);

// Add person=Mark
$queryParams['person'] = 'Mark';

Finally, as you already know, you can turn the array back into a string with http_build_query($queryParams).

Upvotes: 2

computercarguy
computercarguy

Reputation: 2453

Since there are 2 different separator characters, that makes it a bit simpler. What we can do is first split the string by the "&", then split the parts by the "=" so it's a 2 dimensional array or a 1D array of what are effectively the key/value pairs. (In C#, it could be inserted into a Dictionary, if it helps you to think like that. Otherwise ignore what I just said.)

This would need to be done on both the existing query string and the first param of your ChangeQueryString method. Since you only have a key in the 2nd param, you can just split on the "&".

I would loop through the query array looking for the existence of the keys in the replacement array, and update based on that. Afterwards, I'd loop backwards through the query array looking for the keys in the removal array and delete those instances from the query array.

Because the 2nd one has to be done backwards to prevent issues in indexes, you can't do both loops at the same time. If you try this, or even try to do the 2nd one forwards, you need more code and it becomes convoluted very quickly. I suggest doing the removal last, since you apparently want to keep the order of existing keys, and it's only a minimal decrease in performance to do it last. This performance opinion assumes that you are not doing 10's of thousands (or more) of these params, and are sticking to web standardized allowable amounts of characters in your URL/URI.

If you decide to use the $GET array like rickdenhaan mentioned, you simply don't have to decode the query string. The rest still applies.

Of course, there are many different ways to code this, as well as different methods than I describe to do what you want. I'm simply describing what I'd do. If other people have other opinions, I recommend you post your own answer, instead of down voting or critically commenting on this answer.

As this seems possible it could be a homework question, I'm not going to code this for the OP. If it's not a homework question, I would think they should be able to figure this out on their own from what I've already given.

Hopefully I've been helpful and good luck!

Upvotes: -2

Related Questions