Persistent HTTP GET variables in PHP - php

Let's say I have some code like this
if(isset($_GET['foo']))
//do something
if(isset($_GET['bar']))
//do something else
If a user is at example.com/?foo=abc and clicks on a link to set bar=xyz, I want to easily take them to example.com/?foo=abc&bar=xyz, rather than example.com/?bar=xyz.
I can think of a few very messy ways to do this, but I'm sure there's something cleaner that I don't know about and haven't been able to track down via Google.

Here's one way....
//get passed params
//(you might do some sanitizing at this point)
$params=$_GET;
//morph the params with new values
$params['bar']='xyz';
//build new query string
$query='';
$sep='?';
foreach($params as $name=>$value)
{
$query.=$sep.$name.'='.urlencode($value);
$sep='&';
}

If you are updating the query string you need ot make sure you don't do something like
$qs="a=1&b=2";
$href="$qs&b=4";
$href contains "a=1&b=2&b=4"
What you really want to do is overwrite the current key if you need to .
You can use a function like this. (disclaimer: Off the top of my head, maybe slightly bugged)
function getUpdateQS($key,$value)
{
foreach ($_GET as $k => $v)
{
if ($k != $key)
{
$qs .= "$k=".urlencode($v)."&"
}
else
{
$qs .= "$key=".urlencode($value)."&";
}
}
return $qs
}
View report

Just set the link that changes bar to xyz to also have foo=abc if foo is already set.
$link = ($_GET['foo'] == 'abc') ? 'foo=abc&bar=xyz' : 'bar=xyz';
?>
Click Me

You would have to render out the links with the proper URL querystring to make that happen. This is a design decision that you would need to make on your end depending on how your system is setup.
I have some sites that have this issue, and what I do is setup a querystring global variable that sets the current page data the top of the page request.
Then when I am rendering the page, if I need to make use of the current query string I do something like:
echo '<a href="myurl.php' . querystring . '&bar=foo';
It's not the cleanest, but it all depends on how your system works.

Save some code and use the built-in http_build_query. I use this wrapper in one of my projects:
function to_query_string($array) {
if(is_scalar($array)) $query = trim($array, '? \t\n\r\0\x0B'); // I could split on "&" and "=" do some urlencode-ing here
else $query = http_build_query($array);
return '?'.$query;
}
Also, though it isn't often used, you can have $_GET on the left-hand side of an assignment:
$_GET['overriden_or_new'] = 'new_value';
echo 'Yeah!';
Other than that, just do what Paul Dixon said.

Related

Add/Replace URL GET parameter depending on current URL

I’ve tried for some time now to solve what probably is a small issue but I just can’t seem get my head around it. I’ve tried some different approaches, some found at SO but none has worked yet.
The problem consists of this:
I’ve a show-room page where I show some cloth. On each single item of cloth there is four “views”
Male
Female
Front
Back
Now, the users can filter this by either viewing the male or female model but they can also filter by viewing front or back of both gender.
I’ve created my script so it detects the URL query and display the correct data but my problem is to “build” the URL correctly.
When firstly enter the page, the four links is like this:
example.com?gender=male
example.com?gender=female
example.com?site=front
example.com?site=back
This work because it’s the “default” view (the default view is set to gender=male && site=front) in the model.
But if I choose to view ?gender=female the users should be able to filter it once more by adding &site=back so the complete URL would be: example.com?gender=female&site=back
And if I then press the link to see gender=male it should still keep the URL parameter &site=back.
What I’ve achived so far is to append the parameters to the existing URL but this result in URL strings like: example.com?gender=male&site=front&gender=female and so on…
I’ve tried but to use the parse_url function, the http_build_query($parms) method and to make my “own” function that checks for existing parameters but it does not work.
My latest try was this:
_setURL(‘http://example.com?gender=male’, ‘site’, ‘back’);
function _setURL($url, $key, $value) {
$separator = (parse_url($url, PHP_URL_QUERY) == NULL) ? '?' : '&';
$query = $key."=".$value;
$url .= $separator . $query;
var_dump($url); exit;
}
This function works unless the $_GET parameter already exists and thus should be replaced and not added.
I’m not sure if there is some “best practice” to solve this and as I said I’ve looked at a lot of answers on SO but none which was spot on my issue.
I hope I’ve explained myself otherwise please let me know and I’ll elaborate.
Any help or advice would be appreciated
You can generate the links dynamically using the following method:
$frontLink = (isset($_GET['gender'])) ? 'mydomain.com?gender='.$_GET['gender'].'&site=front':'mydomain.com?site=front';
$backLink = (isset($_GET['gender'])) ? 'mydomain.com?gender='.$_GET['gender'].'&site=back':'mydomain.com?site=back';
This is a 1 line if statement which will set the value of the variables $frontLink and $backlink respectively. The syntax for a 1 line if statement is $var = (if_statement) ? true_result:false_result; this will set the value of $var to the true_result or false_result depending on the return value of the if statement.
You can then do the same for the genders:
$maleLink = (isset($_GET['site'])) ? 'mydomain.com?gender=male&site='.$_GET['site']:'mydomain.com?gender=male';
$femaleLink = (isset($_GET['site'])) ? 'mydomain.com?gender=female&site='.$_GET['site']:'mydomain.com?gender=female';
Found this by searching for a better solution then mine and found this ugly one (That we see a lot on the web), so here is my solution :
function add_get_parameter($arg, $value)
{
$_GET[$arg] = $value;
return "?" . http_build_query($_GET);
}
<?php
function requestUriAddGetParams(array $params)
{
$parseRes=parse_url($_REQUEST['REQUEST_URI']);
$params=array_merge($_GET, $params);
return $parseRes['path'].'?'.http_build_query($params);
}
?>
if(isset($_GET['diagid']) && $_GET['diagid']!='') {
$repParam = "&diagid=".$_GET['diagid'];
$params = str_replace($repParam, "", $_SERVER['REQUEST_URI']);
$url = "http://".$_SERVER['HTTP_HOST'].$params."&diagid=".$ID;
}
else $url = "http://".$_SERVER['HTTP_HOST'].$_SERVER['REQUEST_URI']."&diagid=".$ID;

Adding a query string to a random URL

I want to add a query string to a URL, however, the URL format is unpredictable. The URL can be
http://example.com/page/ -> http://example.com/page/?myquery=string
http://example.com/page -> http://example.com/page?myquery=string
http://example.com?p=page -> http://example.com?p=page&myquery=string
These are the URLs I'm thinking of, but it's possible that there are other formats that I'm not aware of.
I'm wondering if there is a standard, library or a common way to do this. I'm using PHP.
Edit: I'm using Cbroe explanation and Passerby code. There is another function by Hamza but I guess it'd be better to use PHP functions and also have cleaner/shorter code.
function addQuery($url,array $query)
{
$cache=parse_url($url,PHP_URL_QUERY);
if(empty($cache)) return $url."?".http_build_query($query);
else return $url."&".http_build_query($query);
}
// test
$test=array("http://example.com/page/","http://example.com/page","http://example.com/?p=page");
print_r(array_map(function($v){
return addQuery($v,array("myquery"=>"string"));
},$test));
Live demo
I'm wondering if there is a standard, library or a common way to do this. I'm using PHP.
Depends on how failsafe – and thereby more complex – you want it to be.
The simplest way would be to look for whether there’s a ? in the URL – if so, append &myquery=string, else append ?myquery=string. This should cover most cases of standards-compliant URLs just fine.
If you want it more complex, you could take the URL apart using parse_url and then parse_str, then add the key myquery with value string to the array the second function returns – and then put it all back together again, using http_build_query for the new query string part.
Some spaghetti Code:
echo addToUrl('http://example.com/page/','myquery', 'string').'<br>';
echo addToUrl('http://example.com/page','myquery', 'string').'<br>';
echo addToUrl('http://example.com/page/wut/?aaa=2','myquery', 'string').'<br>';
echo addToUrl('http://example.com?p=page','myquery', 'string');
function addToUrl($url, $var, $val){
$array = parse_url($url);
if(isset($array['query'])){
parse_str($array['query'], $values);
}
$values[$var] = $val;
unset($array['query']);
$options = '';$c = count($values) - 1;
$i=0;
foreach($values as $k => $v){
if($i == $c){
$options .= $k.'='.$v;
}else{
$options .= $k.'='.$v.'&';
}
$i++;
}
$return = $array['scheme'].'://'.$array['host'].(isset($array['path']) ? $array['path']: '') . '?' . $options;
return $return;
}
Results:
http://example.com/page/?myquery=string
http://example.com/page?myquery=string
http://example.com/page/wut/?aaa=2&myquery=string
http://example.com?p=page&myquery=string
You should try the http_build_query() function, I think that's what you're looking for, and maybe a bit of parse_str(), too.

Using multiple values with strstr($_SERVER['PHP_SELF']...)

another simple thing that's got me stuck:
I'm using the following to check on the current url and select a div class dependent on the result:
$checkit = $_SERVER['PHP_SELF'];
...
<li "; if(strstr($checkit,'welcome')) { echo "class='active_tab'"; }...
What I want to be able to do is also check if the url includes other words which would also require that same 'li' item to be given the 'active_tab' class, but i can't figure out the format. Something like this, although obviously this doesn't work:
<li "; if(strstr($checkit,'welcome', 'home', 'yourprofile')) { echo "class='active_tab'"; }...
Can someone help?
I know there's a better way but stop-gap fix would be:
$searchStrings = array('welcome','home','yourprofile');
$stringFound = false;
foreach($searchStrings as $checkString)
{
if(strstr($checkit, $checkString))
{
$stringFound = true;
break;
}
}
Then use $stringFound to change your output.
Edit 1: Switched continuefor break thanks ZombieHunter (It's late -_-)
Edit 2: Alternatively you can use a regular expression (though I think that's overkill here)
if(preg_match('/(welcome|home|your profile)/',$checkit))
{
// Do your stuff here
}
But this is not as expressive (easier to read and extend an array) and if those values start piling up its easier to hook the array into some storage like DB query.

php get all url variables

I'm trying to make links to include the current _GET variables.
Example link: Page 2
The current url is: http://example.com/test.php?id=2&a=1
So if someone clicks on the link of page 2 it will take them to:
http://example.com/test.php?id=2&a=1&page=2
Currently if they click on the link it takes them to:
http://example.com/test.php?page=2
As you can see, I need a way to get the current _GET variables in the url and add them to the link. Advice?
The superglobal entry $_SERVER['QUERY_STRING'] has the query string in it. You could just append that to any further links.
update: The alternate response on this page using http_build_query is better because it lets you add new variables to the query string without worrying about extraneous ?s and such. But I'll leave this here because I wanted to mention that you can access the literal query string that's in the current address.
$new_query_string = http_build_query(array_merge($_GET,array('page' => 2)));
Make use of #extract($_GET). So you can access them directly as variables.
Try this may help you......
function get_all_get()
{
$output = "?";
$firstRun = true;
foreach($_GET as $key=>$val) {
if($key != $parameter) {
if(!$firstRun) {
$output .= "&";
} else {
$firstRun = false;
}
$output .= $key."=".$val;
}
}
return $output;
}
As for the question above how to include the name of php file as well in the url, using Your Common Sense's perfect method and adding a question mark worked for me:
echo "<a href='?".$url."'>link</a>"

Need better structure of my code

this is my front controller
$pages = array("matches", "boards", "search", "articles", "interviews", "userlist", "teams", "servers", "awards", "gallery", "qids");
if (!$_SERVER['QUERY_STRING']) include('home_en.php');
elseif (isset($_GET['matchid'])) include('matchid.php');
elseif (isset($_GET['boardid'])) include('boardid.php');
elseif (isset($_GET['articleid'])) include('articleid.php');
elseif (isset($_GET['interviewid'])) include('interviewid.php');
elseif (isset($_GET['userid'])) include('profi.php');
elseif (isset($_GET['teamid'])) include('teamid.php');
elseif (isset($_GET['serverid'])) include('serverid.php');
elseif (isset($_GET['awardid'])) include('awardid.php');
elseif (isset($_GET['galleryid'])) include('galleryid.php');
elseif (isset($_GET['threadid'])) include('threadid.php');
elseif (isset($_GET['blogid'])) include('blogid.php');
..
elseif (in_array($_GET['content'], $pages)) include($_GET['content']);
else echo "File not found =(";
could i somehow add the identifiers to the array too? but i want the pages as index.php?matchid=9438 and for regular pages: index.php?content=matches
would really aprricate some ideas
thanks!
My Suggestion, From My Comment is this:
In order to check what type of id it is, you should use two $_GET parameters. One is the type (match, award, server, etc), one is the ID. That way you don't have to check for 500 different $_GET parameters, just the value of 2. Much more standardized.
Second, you want to make all of it under 1 file for the ID showing.
In the spirit of writing less code, not more, it would be relatively easy to change the SQL statement to grab the record based on if $_GET['type'] was match, award, team, etc. This is of course given that they will probably look the same. If they don't, instead of writing new code to grab each type, instead write code to display it differently
All Variables in this code much be validated/sanatized beforehand.
// First Get the Type
$type = $_GET['type'];
// Then the ID
$id = $_GET['id'];
// SANITIZE YOUR DATA. Replace this with your sanitization.
die("SANITIZE YOUR DATA HERE");
// Get Data Here
$sql = "SELECT * FROM table WHERE type=".$type." AND id=".$id;
$data = mysql_query($sql);
// Next, Include a template based on the data.
// Global the variable so it can be used in the file
Global $data;
include($type."-template.php");
I agree with Tom -- you should look into using a framework such as Zend, Cake, Symfony, Kohana, CodeIgniter, ez-Components, or Seagull. The advantage of using a framework is that they have already solved a lot of issues for you, including:
1) How to structure your code
2) How to interpret pretty urls (i.e. /x/1/y/2 instead of ?x=1&y=2)
3) Where to put certain types of code (html, php, configs, etc)
4) How to fix something you can't figure out (because these frameworks have communities)
and much much more...
That being said, maybe you don't want all the overhead of using a framework (it does require you to learn a lot). In that case, I recommend Rasmus Lerdorf's "No Framework PHP Framework". Rasmus is the creator of PHP, so you know he knows his stuff.
Lastly, to answer your actual question, here's how I would do it:
could i somehow add the identifiers to the array too?
i want the pages as index.php?matchid=9438
and for regular pages: index.php?content=matches
Sure, but yes, as Chacha102 said, you will need 2 parameters: $area (page) and $id.
Example: index.php?area=articles&id=2345
Then you can re-organize & simplify your 'front controller' this way:
/index.php
/areas/articles.php
/areas/boards.php
etc.
Instead of naming the templates articleid.php, just call it articles.php -- this way your area name also tells you which template to use.
$valid_areas = array("matches", "boards", "search", "articles",
"interviews", "userlist", "teams", "servers",
"awards", "gallery", "qids");
$area = strtolower(trim($_REQUEST['area'])); //if you are not posting any forms, use $_GET instead
$id = (int)$_REQUEST['id']; //if you are not posting any forms, use $_GET instead
if(!$id)
{
include('home_en.php');
}
if(!in_array($area), $valid_areas))
{
echo 'Sorry, the area you have requested does not exist: '.$area;
exit();
}
else
{
$template = '/templates/'.$area.'.php';
if(!file_exists($template))
{
echo 'Sorry, the file you have requested does not exist: '.$area.' '.$id);
}
else
{
include($template);
}
}
It might help to go ahead and use a framework such as Zend:
http://framework.zend.com/
You could do this:
<?php
$controllerDefault = 'home';
function sanitize($str)
{
return str_replace(array('.', '/', '\\'), '', $str);
}
//Prevent of Remote File Inclusion
$controller = sanitize($_GET['controller']);
$id = intval($_GET['id']);
if (empty($controller))
{
$controller = $controllerDefault;
}
if (!empty($id))
{
$controller .= 'id';
}
$controllerFile = $controller . '.php';
if (!file_exists($controllerFile)
|| $controller == 'index') //for not recursive index.php include :)
{
exit('Controller "'.$controllerFile.'" not exists');
}
include($controllerFile);
?>
Using this code you can use your application like:
http://yoursite.com/index.php //include('home.php')
http://yoursite.com/index.php?id=285230 //include('homeid.php')
http://yoursite.com/index.php?controller=matches //include('matches.php')
http://yoursite.com/index.php?controller=matches&id=28410 //include('matchesid.php')
http://yoursite.com/index.php?controller=notexists //ERROR! Controller "notexists" not exists
http://yoursite.com/index.php?controller=../../etc/passwd //ERROR! Controller "etcpasswd" not exists
I hope you like it
PD: the code is not tested, but I hope you catch my idea

Categories