views:

580

answers:

7

One of my sites has some very complicated sorting functions, on top of a pagination, and the various variables add up to a pretty complex URL, which is a huge pain to manage. Is there a way to manage the QUERY_STRING efficiently?

By this I mean... if the url is index.php?catid=3&sort=date&year=2009&page=2 and I wish to have the user jump to page 3, or change the sort method..... how would I preserve the remaining vars without checking for each individual var with an if/else condition and echo them out in the link that would link to page 3 or alternate sort method.

+2  A: 

PHP supplies you a global $_GET which holds your query string all nicely parsed into elements

$_GET['catid'] will be '3'
$_GET['sort'] will be 'date'
$_GET['year'] will be '2009'

etc

You could unset the ones you don't want to pass along and then move to new url via something like:

$get = array_intersect_key($_GET, array_keys($_GET));
unset($get['sort']);
$url = 'target.php?' . http_build_query($get);
Scott Evernden
That's a really cool trick to remove a $_GET variable.
Andrew
-1, that implode will not preserve the keys, it only joins the values together.
sirlancelot
What should $_GET.slice() do? That's not PHP as $_GET is an array and therefore has no methods to call.
Stefan Gehrig
yep / brain fart - too many languages in use in my head these days
Scott Evernden
A: 

If you mean that you would like that the link to page 3 would be only

index.php?page=3

or link to changing the sort method would be only

index.php?sort=date

You would have to store the other variables in session variables (or cookies, if you want them to persist longer).

Something like this:

<?php

  session_start();

  foreach($_GET as $var => $val) {
    // filter any malicious stuff and invalid variables out of $var and $val here
    // like
    if (in_array($var, $array_of_valid_variable_names)) {
      if ($var == 'page') $val = intval($val);

      $_SESSION[$var] = $val;
    }
  }

  // do stuff based on the values stored in $_SESSION

  echo '<a href="index.php?page='.($_SESSION['page'] + 1).'">Next page</a>';
?>
kkyy
A: 

Don't manage the string directly but manage an array ( key => value ) representation of it and only translate it back to string when needed.

One possible way of doing it:

function explodeQueryString( $queryString )
{
    $parts = array();
    if ( strlen( $queryString ) > 1 && substr( $queryString, 0, 1 ) == '?' )
    {
     $q = explode( '&', substr( $queryString, 1 ) );
     foreach( $q as $part )
     {
      list( $key, $value ) = explode( '=', $part );
      $parts[ urldecode( $key ) ] = urldecode( $value );
     }
    }
    return $parts;
}

function implodeQueryString( array $arguments )
{
    $parts = array();
    foreach( $arguments as $key => $value )
    {
     $parts[ ] = sprintf( '%s=%s', urlencode( $key ), urlencode( $value ) );
    }
    return sprintf( '?%s', implode( '&', $parts ) );
}

// $query = $_GET;

$query = '?something=1&somethingelse=2&page=1&yetsomethingelse=3';

$q = explodeQueryString( $query );

print_r( $q );

$q[ 'page' ] += 1;

$query = implodeQueryString( $q );

echo $query;
Kris
i know there is $_GET but that's only for the current request. sometimes you need to parse arbitrary amounts of querystrings.
Kris
This is exactly what parse_str() and http_build_query() do natively.
sirlancelot
A: 

I have had the exact same problem with a general "build me a sortable, pageable Table" class. This is why someone invented subprocedures called "functions" in php.

You have to create a function that handles exactly the link-building process. like so:

/**
* $set: associative array of changing vars
* $unset : normal array of vars to delete
**/
function get_link($set,$unset=array())
{
 $set+=$_GET;
 if ($unset && is_array($unset))
   foreach($unset as $idx) 
      unset($set[$idx]);

 if ($set)
   foreach($set as $name=>$value)
      $pairs[]=$name.'='.urlencode($value);

 return $_SERVER['SCRIPT_NAME']."?".join('&',$pairs);
}

UNTESTED CODE! Use your brains

or you could use $_SESSION-vars for pageing and sorting (an' stuff) and have links only change those (which is what i mostly do nowadays)

+3  A: 

To handle actual query strings (string format), you can use parse_str(). When you want to build a query string, use http_build_query().

There's quite a few examples on those documentation pages.

If for some reason you can't use http_build_query, check out my question about the fastest way to implode an associative array.

<?php
$QueryString = 'catid=3&sort=date&year=2009&page=2'; // sample querystring
parse_str($QueryString, $HttpQuery);

print_r($HttpQuery); // will be an associative array

$HttpQuery['page'] = 3; // change any values

$NewQueryString = http_build_query($HttpQuery); // rebuild the querystring
sirlancelot
A: 

Add the variable name and value at the end of the query string (changing page to 3):

index.php?catid=3&sort=date&year=2009&page=2&x=page&y=3

Then, after extracting $_GET, use a simple function to check if x and y are set.

If they are, set the variable whose name is contained in x to the value y.

You can use the same link everywhere with a simple addition at the end, and the amount of programming is minimal.

Andrew Swift
Interesting solution, but it makes things too complicated and causes duplicate pages to be generated, not good for SEO.
sirlancelot
+1  A: 

Although most of the solutions provided here will work, I think the most simple way to do this will be

// parse query string into an array
$queryData = array();
parse_str($_SERVER['QUERY_STRING'], $queryData);
/*
 * ... manipulate array $queryData
 */
// rebuild query string
$queryString = http_build_query($queryData, null, '&amp;'); // or use & if you don't need XHTML compliance

That's it. Please see documentation on http_build_query() and parse_str() (that's one of those functions whose name was completey messed up - nobody would expect the function to do what it does just by looking at the name).

Stefan Gehrig