12

Okay.. so basically, say we have a link:

$url = "http://www.site.com/index.php?sub=Mawson&state=QLD&cat=4&page=2&sort=z";

Basically, I need to create a function, which replaces each thing in the URL, for example:

<a href="<?=$url;?>?sort=a">Sort by A-Z</a>
<a href="<?=$url;?>?sort=z">Sort by Z-A</a>

Or, for another example:

<a href="<?=$url;?>?cat=1">Category 1</a>
<a href="<?=$url;?>?cat=2">Category 2</a>

Or, another example:

<a href="<?=$url;?>?page=1">1</a>
<a href="<?=$url;?>?page=2">2</a>
<a href="<?=$url;?>?page=3">3</a>
<a href="<?=$url;?>?page=4">4</a>

So basically, we need a function which will replace the specific $_GET from the URL so that we don't get a duplicate, such as: ?page=2&page=3

Having said that, it needs to be smart, so it knows if the beginning of the parameter is a ? or an &

We also need it to be smart so that we can have the URL like so:

<a href="<?=$url;?>page=3">3</a> (without the ? - so it will detect automatically wether to use an `&` or a `?`

I don't mind making different variables for each preg_replace for the certain $_GET parameters, but I am looking for the best way to do this.

Thank you.

ajreal
  • 46,720
  • 11
  • 89
  • 119
Latox
  • 4,655
  • 15
  • 48
  • 74
  • 1
    Do not parse HTML with regex (http://stackoverflow.com/questions/1732348/regex-match-open-tags-except-xhtml-self-contained-tags). Instead, parse the DOM (http://stackoverflow.com/questions/3650125/how-to-parse-html-with-php). –  Sep 09 '11 at 02:58
  • Sorry cannot help, but you can test regexp here: http://regexpal.com/ And for assistance on php preg replace etc: http://www.regular-expressions.info/php.html Sorry couldnt help more – 422 Sep 09 '11 at 02:54
  • I have re-tag and make the title appropriate to the given description and problem. Please revise – ajreal Sep 09 '11 at 04:49

9 Answers9

13

How about something like this?

function merge_querystring($url = null,$query = null,$recursive = false)
{
  // $url = 'http://www.google.com.au?q=apple&type=keyword';
  // $query = '?q=banana';
  // if there's a URL missing or no query string, return
  if($url == null)
    return false;
  if($query == null)
    return $url;
  // split the url into it's components
  $url_components = parse_url($url);
  // if we have the query string but no query on the original url
  // just return the URL + query string
  if(empty($url_components['query']))
    return $url.'?'.ltrim($query,'?');
  // turn the url's query string into an array
  parse_str($url_components['query'],$original_query_string);
  // turn the query string into an array
  parse_str(parse_url($query,PHP_URL_QUERY),$merged_query_string);
  // merge the query string
  if($recursive == true)
    $merged_result = array_merge_recursive($original_query_string,$merged_query_string);
  else
    $merged_result = array_merge($original_query_string,$merged_query_string);
  // Find the original query string in the URL and replace it with the new one
  return str_replace($url_components['query'],http_build_query($merged_result),$url);
}

usage...

<a href="<?=merge_querystring($url,'?page=1');?>">Page 1</a>
<a href="<?=merge_querystring($url,'?page=2');?>">Page 2</a>
Scuzzy
  • 12,186
  • 1
  • 46
  • 46
  • It's pretty straightforward, it turns the query string parameters from the end of the URL into an array, then turns the second parameter into an array, merges the two arrays (thus the second set will overlay the first set) then turns the array back into a query string, then find and replaces the original query string with the new compiled string. What I didn't code for was if there was no query string on the initial URL value, at which point I could make the function just append the new query string. – Scuzzy Sep 09 '11 at 03:23
  • How do we make this work so if there aren't any $_GET parameters, it'll still work? For example: http://www.site.com/index.php and then a link created for http://www.site.com/index.php?sort=a (as when I am doing this currently, if there is no $_GET, then the sort=a is not added. – Latox Sep 09 '11 at 03:54
  • I've accepted your answer but getting this working without any $_GET parameters would be perfect. – Latox Sep 09 '11 at 04:23
  • I'll try to clean up the function a bit and make it a bit more readable. but it should now just do a simple string concat if it doesn't need to merge – Scuzzy Sep 09 '11 at 04:53
  • +1 Works perfectly over here as well. Merges query string values or adds the query string if it's not present. – arviman Jul 12 '12 at 04:03
10

Well, I had same problem, found this question, and, in the end, prefered my own method. Maybe it has flaws, then please tell me what are they. My solution is:

$query=$_GET;
$query['YOUR_NAME']=$YOUR_VAL;
$url=$_SERVER['PHP_SELF']. '?' .  http_build_query($query);

Hope it helps.

Amantel
  • 659
  • 1
  • 8
  • 18
5
<?php
function change_query ( $url , $array ) {
    $url_decomposition = parse_url ($url);
    $cut_url = explode('?', $url);
    $queries = array_key_exists('query',$url_decomposition)?$url_decomposition['query']:false;
    $queries_array = array ();
    if ($queries) {
        $cut_queries   = explode('&', $queries);
        foreach ($cut_queries as $k => $v) {
            if ($v)
            {
                $tmp = explode('=', $v);
                if (sizeof($tmp ) < 2) $tmp[1] = true;
                $queries_array[$tmp[0]] = urldecode($tmp[1]);
            }
        }
    }
    $newQueries = array_merge($queries_array,$array);
    return $cut_url[0].'?'.http_build_query($newQueries);
}
?>

Use like this :

<?php
    echo change_query($myUrl, array('queryKey'=>'queryValue'));
?>

I do that this morning, it seems to work in all case. You can change / add more than one query, with the array ;)

PiTheNumber
  • 22,828
  • 17
  • 107
  • 180
Doubidou
  • 1,573
  • 3
  • 18
  • 35
3
function replaceQueryParams($url, $params)
{
    $query = parse_url($url, PHP_URL_QUERY);
    parse_str($query, $oldParams);

    if (empty($oldParams)) {
        return rtrim($url, '?') . '?' . http_build_query($params);
    }

    $params = array_merge($oldParams, $params);

    return preg_replace('#\?.*#', '?' . http_build_query($params), $url);
}

$url examples:

$params example:

[
   'foo' => 'not-bar',
]

Note: it doesn't understand URLs with anchors (hashes) like http://example.com/page?foo=bar#section1

luchaninov
  • 6,792
  • 6
  • 60
  • 75
1

improve Scuzzy 2013 function last pieces for clean url query string.

// merge the query string
// array_filter removes empty query array
    if ($recursive == true) {
        $merged_result = array_filter(array_merge_recursive($original_query_string, $merged_query_string));
    } else {
        $merged_result = array_filter(array_merge($original_query_string, $merged_query_string));
    }

    // Find the original query string in the URL and replace it with the new one
    $new_url = str_replace($url_components['query'], http_build_query($merged_result), $url);

    // If the last query string removed then remove ? from url 
    if(substr($new_url, -1) == '?') {
       return rtrim($new_url,'?');
    }
    return $new_url;
jlcolon13
  • 11
  • 1
1
<?php
//current url: http://localhost/arters?sub=Mawson&state=QLD&cat=4&page=2&sort=a

/**
* URL Parameters : Replace query string value in a url
*
* @version 2023.02.21 Jwu
*
* @param string $queryKey Variable name 
* @param string|null $queryValue Property value
* 
* @return string
*/
function changeQueryString($queryKey, $queryValue){
    $queryStr = $_SERVER['QUERY_STRING'];
    parse_str($queryStr, $output);
    if($queryValue == null){
        unset($output[$queryKey]);
    }else{
        $output[$queryKey] = $queryValue;
    }
    $actualLink = 'http' . (isset($_SERVER['HTTPS']) ? 's' : '') . '://' . $_SERVER['HTTP_HOST'] . $_SERVER['PHP_SELF'];
    return $actualLink . '?' . http_build_query($output);
}

usage:

<a href="<?php echo changeQueryString("sort",'z');?>">sort by z</a>

http://localhost/arters?sub=Mawson&state=QLD&cat=4&page=2&sort=z

<a href="<?php echo changeQueryString("page",'5');?>">Page 5</a>

http://localhost/arters?sub=Mawson&state=QLD&cat=4&page=5&sort=a

kkasp
  • 113
  • 1
  • 9
1

If I'm reading this correctly, and I may not be. You know which GET you are replacing in a url string? This may be sloppy but...

$url_pieces = explode( '?', $url );
$var_string = $url_pieces[1].'&';
$new_url = $url_pieces[0].preg_replace( '/varName\=value/', 'newVarName=newValue', $var_string );

That's my take, Good luck.

Adam
  • 1,080
  • 1
  • 9
  • 17
1

I don't know if this is what you're trying to accomplish but here it goes anyway:

<?php
    function mergeMe($url, $assign) {
        list($var,$val) = explode("=",$assign);
        //there's no var defined
        if(!strpos($url,"?")) {
            $res = "$url?$assign";
        } else {
            list($base,$vars) = explode("?",$url);
            //if the vars dont include the one given
            if(!strpos($vars,$var)) {
                $res = "$url&$assign";
            } else {
                $res = preg_replace("/$var=[a-zA-Z0-9_]*(&|$)/",$assign."&",$url);
                $res = preg_replace("/&$/","",$res); //remove possible & at the end
            }
        }
        //just to show the difference, should be "return $res;" instead
        return "$url <strong>($assign)</strong><br>$res<hr>";
    }

    //example
    $url1 = "http://example.com";
    $url2 = "http://example.com?sort=a";
    $url3 = "http://example.com?sort=a&page=0";
    $url4 = "http://example.com?sort=a&page=0&more=no";

    echo mergeMe($url1,"page=4");
    echo mergeMe($url2,"page=4");
    echo mergeMe($url3,"page=4");
    echo mergeMe($url4,"page=4");
?>
derp
  • 2,940
  • 17
  • 16
0

My short and readable way:

function replaceGetParameters(string $url, array $newGetParameters): string {
    $url_parts = parse_url($url);
    $query = [];
    if (isset($url_parts['query'])) {
      parse_str($url_parts['query'], $query);
    }
    $query = array_merge($query, $newGetParameters);
    $url_parts['query'] = http_build_query($query);
    return $url_parts['scheme'] . '://' . $url_parts['host'] . $url_parts['path'] . '?' . $url_parts['query'];
  }
Hermann Schwarz
  • 1,495
  • 1
  • 15
  • 30