Solved

click on one link to change one (out of many) query string variable

Posted on 2013-05-31
18
477 Views
Last Modified: 2013-06-01
toggle on/off 1 query_string variable with one href click (no checkboxes of choices)

website.com/index.php?query_variable1=45&query_variable2=59499&query_variable3=8


want

website.com/index.php?query_variable1=45&query_variable2=59499&

or
website.com/index.php?query_variable1=45&query_variable3=8




real world example toggle on/off different variables of query string:
videos:
captioning: on/off
video quality: 720,480,360,240
video size: small, large, full-screen
website.com/video.php?caption=on&video_quality=720&video_size=full_screen

separate links to click

click on link 'video size-small'
to change query to
website.com/video.php?caption=on&video_quality=720&video_size=small

click on link 'video quality-480'
to change query to
website.com/video.php?caption=on&video_quality=480&video_size=full_screen


clicking on one should not affect other
0
Comment
Question by:rgb192
  • 8
  • 4
  • 3
  • +1
18 Comments
 
LVL 108

Expert Comment

by:Ray Paseur
ID: 39210476
Each of these links needs to be its own entity (its own anchor tag in the HTML document).  The PHP script that generates the links will be responsible for all of the UTL parameters.  Your examples seem to make sense -- just put them into HTML anchor tags and the task is complete!
0
 

Author Comment

by:rgb192
ID: 39210488
I dont understand

how to keep the current query string and only modify the clicked link (video size)

does this need a complex regular expression
or a preg replace to modify current query string
0
 
LVL 108

Expert Comment

by:Ray Paseur
ID: 39210500
How to keep the current query string
This information is available in the $_GET array.  You can use var_dump($_GET) to print it out.  Then you can see the arguments by index name and array value.  You can write programming to iterate over the GET array, but if you do that, you want to make sure that anything in the GET array is "sanitary" since the URL is a common attack vector.
does this need a complex regular expression or a preg replace to modify current query string
No, nothing like that.  Just substitute the value you want in a copy of the $_GET array and rebuild the URL before writing the anchor tag to the browser output stream. Or you can hardcode the options (which is what I would probably do) in an array or object and call a method to build the anchor tag with the request variables.
0
 
LVL 51

Expert Comment

by:Julian Hansen
ID: 39210640
Where do you want to modify the query string - in the browser or on the server?

From your questions it sounds like you want to dynamically update the query string before sending to the server - is this correct?
0
 
LVL 108

Expert Comment

by:Ray Paseur
ID: 39210998
You might use something like this.  It avoids attacks via invalid URL parameters, choosing among known good values.  It will also trigger a run-time error if the script tries to set a value that is unusable.
http://www.laprbass.com/RAY_temp_rgb192.php

If I had some more time, I might pretty it up some, but all the basic functionality is there.  As written, the script takes advantage of the fact that the last (rightmost) query variable overwrites identically named variables in the request array.

<?php // RAY_temp_rgb192.php
error_reporting(E_ALL);

/* PROBLEM DEFINITION
 *
 * SEE http://www.experts-exchange.com/Web_Development/Web_Languages-Standards/PHP/Q_28143970.html
 *
 * captioning: on/off
 * video quality: 720,480,360,240
 * video size: small, large, full-screen
 * website.com/video.php?caption=on&video_quality=720&video_size=full_screen
 */

Class Get
{
    // ACTUAL REQUEST ARGUMENTS
    protected $is = array();

    // ALLOWABLE REQUEST ARGUMENTS
    protected $ok = array
    ( 'c' => array('on',   'off')
    , 'q' => array('720',  '480',   '360', '240')
    , 's' => array('full', 'large', 'small')
    )
    ;

    // CONSTUCTOR OVERRIDES DEFAULT ARGUMENTS WITH THE REQUEST VARS
    public function __construct()
    {
        // COPY DEFAULT SETTINGS
        foreach ($this->ok as $key => $arr)
        {
            $this->is[$key] = $arr[0];
        }

        // SET REQUEST VARS
        foreach ($_GET as $key => $val)
        {
            // IGNORE ATTACK VECTORS
            if (array_key_exists($key, $this->ok))
            {
                // CHOOSE ONLY VALID SETTINGS
                if (in_array($val, $this->ok[$key])) $this->is[$key] = $val;
            }
        }
    }

    // SETTER PERMITS RUN-TIME SETTINGS (NOT JUST URL LINKS)
    public function setArg($key, $val)
    {
        // HANDLE PROGRAMMING ERRORS
        if (!in_array($key, $this->ok))       trigger_error("FAIL KEY: $key => $val", E_USER_ERROR);
        if (!in_array($val, $this->ok[$key])) trigger_error("FAIL VAL: $key => $val", E_USER_ERROR);

        // SET THE VALUE
        $this->is[$key] = $val;
        return $this->getURL();
    }

    // GETTER PERMITS RUN-TIME OBSERVATION OF SETTINGS
    public function getIs()
    {
        // RETURN THE CURRENT SETTING VALUES
        return $this->is;
    }

    public function getURL()
    {
        return 'http://'
        . $_SERVER['HTTP_HOST']
        . $_SERVER['PHP_SELF']
        . '?'
        . http_build_query($this->is)
        ;
    }
}

// SHOW THE USE CASE
$myreq = new GET;
$str = $myreq->getURL();

$html = <<<EOD
<p>
Caption: <a href="$str&c=off">Off</a> | <a href="$str&c=on">On</a>
<br>
Quality: <a href="$str&q=720">720</a> | <a href="$str&q=480">480</a> | <a href="$str&q=360">360</a> | <a href="$str&q=240">240</a>
<br>
Display: <a href="$str&s=small">Small</a> | <a href="$str&s=large">Large</a> | <a href="$str&s=full">Full Screen</a>
</p>
EOD;

echo $html;

// SHOW THE REMEMBERED SETTINGS, PLUS ANY CHANGES FROM THE LINKS
echo "<pre>";
echo "REMEMBERED STATUS SETTINGS:" . PHP_EOL;
print_r($myreq->getIs());

Open in new window

Best regards, ~Ray
0
 
LVL 108

Expert Comment

by:Ray Paseur
ID: 39211188
Variation on the theme...

<?php // RAY_temp_rgb192.php
error_reporting(E_ALL);

/* PROBLEM DEFINITION
 *
 * SEE http://www.experts-exchange.com/Web_Development/Web_Languages-Standards/PHP/Q_28143970.html
 *
 * captioning: on/off
 * video quality: 720,480,360,240
 * video size: small, large, full-screen
 * website.com/video.php?caption=on&video_quality=720&video_size=full_screen
 */

Class Get
{
    // ACTUAL REQUEST ARGUMENTS
    protected $is = array();

    // ALLOWABLE REQUEST ARGUMENTS
    protected $ok = array
    ( 'caption' => array('on',   'off')
    , 'quality' => array('720',  '480',   '360', '240')
    , 'display' => array('full', 'large', 'small')
    )
    ;

    // CONSTUCTOR OVERRIDES DEFAULT ARGUMENTS WITH THE REQUEST VARS
    public function __construct()
    {
        // COPY DEFAULT SETTINGS
        foreach ($this->ok as $key => $arr)
        {
            $this->is[$key] = $arr[0];
        }

        // SET REQUEST VARS
        foreach ($_GET as $key => $val)
        {
            // IGNORE ATTACK VECTORS
            if (array_key_exists($key, $this->ok))
            {
                // CHOOSE ONLY VALID SETTINGS
                if (in_array($val, $this->ok[$key])) $this->is[$key] = $val;
            }
        }
    }

    // SETTER PERMITS RUN-TIME SETTINGS (NOT JUST URL LINKS)
    public function setArg($key, $val)
    {
        // HANDLE PROGRAMMING ERRORS
        if (!in_array($key, $this->ok))       trigger_error("FAIL KEY: $key => $val", E_USER_ERROR);
        if (!in_array($val, $this->ok[$key])) trigger_error("FAIL VAL: $key => $val", E_USER_ERROR);

        // SET THE VALUE
        $this->is[$key] = $val;
        return $this->getURL();
    }

    // GETTER PERMITS RUN-TIME OBSERVATION OF SETTINGS
    public function getIs()
    {
        // RETURN THE CURRENT SETTING VALUES
        return $this->is;
    }

    public function getURL()
    {
        return 'http://'
        . $_SERVER['HTTP_HOST']
        . $_SERVER['PHP_SELF']
        . '?'
        . http_build_query($this->is)
        ;
    }

    public function getLinks($break='<br>', $delim='|')
    {
        $url = $this->getURL();
        $lnk = NULL;
        foreach ($this->ok as $key => $arr)
        {
            $lnk .= ucfirst($key) . ': ';
            foreach ($arr as $val)
            {
                $lnk .= '<a href="' . $url . '&' . $key . '=' . urlencode($val) . '">' . ucfirst($val) . '</a>' . $delim;
            }
            $lnk = rtrim($lnk, $delim);
            $lnk .= $break;
        }
        $len = strlen($lnk) - strlen($break);
        $lnk = substr($lnk, 0, $len);
        return $lnk;
    }
}

// SHOW THE USE CASE
$myreq = new GET;

// SHOW THE REMEMBERED SETTINGS, PLUS ANY CHANGES FROM THE LINKS
echo "<pre>";
echo "REMEMBERED STATUS SETTINGS:" . PHP_EOL;
print_r($myreq->getIs());

echo $myreq->getLinks();

Open in new window

0
 

Author Comment

by:rgb192
ID: 39211303
>>Where do you want to modify the query string - in the browser or on the server?

From your questions it sounds like you want to dynamically update the query string before sending to the server - is this correct?


either client or server works

I do not fully understand the question


there are repeats of the variable I clicked on
so I do not know the value I will $_GET if it is listed twice

first code:
?c=on&q=720&s=full&s=full
?c=on&q=720&s=full&s=large
?c=on&q=720&s=large&c=off

second code:
?caption=on&quality=720&display=large&quality=240
?caption=on&quality=240&display=large&quality=360
?caption=on&quality=360&display=large&caption=off
0
 
LVL 108

Expert Comment

by:Ray Paseur
ID: 39211356
I do not know the value I will $_GET if it is listed twice
Yes, you do know.  
As written, the script takes advantage of the fact that the last (rightmost) query variable overwrites identically named variables in the request array.
This is the nature of associative arrays.  Identical keys permit overwriting.  You can prove this to yourself by installing and running the script.
0
 
LVL 33

Expert Comment

by:Slick812
ID: 39211377
hello rgb192,  , , I can not understand what you are trying to say about how you get the values INTO the "query string"

Not sure if you use some kind of "javascript"  "query string" builder, that adds to the "query string" as a button-check-link is clicked ? ?,, , although you say - "toggle on/off 1 query_string variable with one href click (no checkboxes of choices)"  you do NOT show any code for how that is done, If you have code for that, please show us that code. .
OR, , are you asking for Javascript code to do a "query string"  build up for the video choices you have as button-check-links?

You might also show us your code for the - "toggle on/off 1 query_string variable with one href click (no checkboxes of choices)" , maybe you have something like -

<a href="#" onclick="makeQuery(Cap-On);">caption on</a>
0
How your wiki can always stay up-to-date

Quip doubles as a “living” wiki and a project management tool that evolves with your organization. As you finish projects in Quip, the work remains, easily accessible to all team members, new and old.
- Increase transparency
- Onboard new hires faster
- Access from mobile/offline

 
LVL 51

Expert Comment

by:Julian Hansen
ID: 39211496
This makes no sense

?c=on&q=720&s=full&s=full <== Here you have two 's' parameters same value
?c=on&q=720&s=full&s=large <== Here you have 2 's' parameters different value
?c=on&q=720&s=large&c=off <== Here you have 1 s 1 c parameter

In the first and second - the value of s in the $_GET will always be the second instance of the parameter - the first will be overwritten. It makes no sense at all to have two parameters with the same name in a query string.

The only one that makes sense is the third one - in which case

$_GET['s'] will contain 'large' and
$_GET['c'] will contain 'off'

Beyond that I have no idea what you are trying to do.
0
 
LVL 108

Expert Comment

by:Ray Paseur
ID: 39211537
@julianH:  Actually it makes perfect sense; it's just that it may be a novel concept.  I see it used only occasionally, but it's a powerful concept.  Install the script and run it.  No special tools are required.  Click on some of the links and watch what happens to the internal values.  It's doing what the author asked for, "clicking on one should not affect other."   It's providing a link that allows a single click to change a single value, while preserving all of the other values.

In all instances of duplicate keys in associative arrays, the latter key's value overwrites the prior key's value.  In PHP the raw request strings are turned into associative arrays by the PHP interpreter before the user script gets control.  That's how a URL request string that looks like this...

c=on&q=720&s=full

... gets turned into the $_GET array that looks (more or less) like this:

'c'  => 'on',   'q' => '720',   's '=> 'full'

As you can see, the array has named strings for the keys.  So if you add another argument to the request string with a matching key, it will replace the previous value when PHP creates $_GET.  This is a useful piece of knowledge when your script is handling arrays.
0
 
LVL 33

Expert Comment

by:Slick812
ID: 39211639
OK, here is some of my javascript to do this, It will give the Changed Web Address with the Get Query as "var queryStr"  in the  makeQuery(arryPos,value)  function -

<script>/* <![CDATA[ */

var queryArry = ["caption=on","quality=240","size=small"];

function makeQuery(arryPos,value){
queryArry[arryPos] = value;
var queryStr = "website.com/video.php?"+queryArry[0]+"&"+queryArry[1]+"&"+queryArry[2];
document.getElementById("vidInfo").innerHTML = queryStr;
}

/* ]]> */</script>
<table border="1">
<tr><td colspan="2"><span id="vidInfo">website.com/video.php?caption=on&quality=240&size=small</span></td></tr> 
<tr><td>Caption: </td><td><a href="#" onclick="makeQuery(0,'caption=on');">On</a> - <a href="#" onclick="makeQuery(0,'caption=off');">Off</a></td></tr>
<tr><td>Quality: </td><td><a href="#" onclick="makeQuery(1,'quality=240');">240</a> - <a href="#" onclick="makeQuery(1,'quality=360');">360</a> - <a href="#" onclick="makeQuery(1,'quality=480');">480</a> - <a href="#" onclick="makeQuery(1,'quality=720');">720</a></td></tr>
<tr><td>Video Size: </td><td><a href="#" onclick="makeQuery(2,'size=small');">Small</a> - <a href="#" onclick="makeQuery(2,'size=large');">Large</a> - <a href="#" onclick="makeQuery(2,'size=full');">Full Screen</a></td></tr>
</table>

Open in new window

This works in firefox for me.
0
 
LVL 108

Expert Comment

by:Ray Paseur
ID: 39211997
@Slick812: It works in Chrome and IE, too.
0
 
LVL 51

Expert Comment

by:Julian Hansen
ID: 39212683
@Ray - I get what you are saying but in this case I disagree

The parameters given make no sense - having the same parameter repeated with the same value is just a waste of space - effect will be the same as if there is one. However having the same paramter twice with different values is ambiguous.

In PHP the $_GET array will organise the parameters nicely for you and overwrite the dupes - and you can access the string directly and parse it yourself - you can also drive your car using your feet if you try hard enough - doesn't mean it is a good idea.

Based on other questions posted by the author there seems to be something he wants to do with selecting options in the page - he mentioned in the opening not wanting to use checkboxes. As with many of the authors questions there is a riddle element that needs to be solved to find out what the actual question is - trying to read between the lines to figure out what he is trying to achieve so we can go back to first principles and suggest a way forward.

What it seems he is asking is given a page of options where you can switch options on and off how do you build a query string that caters to those choices - but not using checkboxes. This is where I am confused - how is he presenting the choices in his interface. I suspect the solution is very simple - just need to figure out the question.
0
 
LVL 108

Accepted Solution

by:
Ray Paseur earned 300 total points
ID: 39212936
having the same paramter [sic] twice with different values is ambiguous.
That's not true; it is totally unambiguous.  The last (rightmost) value takes precedence.  This works correctly 100% of the time because that is the intent of the design of associative arrays.  If you work with associative arrays a lot, this feature will eventually show its value.  It's the go-to technique in any de-duplication project.

Consider this task: Sort a ten-million row array of objects and extract the objects with the highest signal properties.  You could sort the array with usort(), but ten million of anything is a lot of data and the sort is likely to be inefficient and slow.  So instead of sorting the initial array, you can traverse the array once, building a semi-reflective mirror in an associative array, using the object->signal as the associative array key.  You can thus exploit the fact that duplicate keys overwrite.  At the end of the traversal, you can ksort() the smaller associative array and the objects at the end of the associative array are the ones you want.
repeated with the same value is just a waste of space
Every year on my birthday I make an assessment of the cost of storage.  Last year, I found that you can buy a gigabyte of storage for the cost of a couple of sheets of toilet paper.  So I do not worry very much about wasted space.  Some things are just not worth optimizing.
you can access the string [raw GET request] directly and parse it yourself
Of course you can, but that seems academic.  I have never encountered a professional requirement to do this.
suspect the solution is very simple
Agreed.  It could be made more complex than what has already been offered but there's a working solution on the table.  One way to make it more complicated would be to store the GET request data in the session.  It would make the URLs "prettier" but it would also add the risk that the client session might time out and the other request data would not be preserved.  It would also prevent the client from using copy/paste to send a useful URL to a friend or colleague.  Another way to make it more complicated would be to ignore the behavior of the associative array and pretend that you needed to program your way around the issue of having a repeated array key.  I thought about that when I first looked at the question, but decided it wasn't worth the effort since (1) only a programmer would care and (2) the solution was obvious and easy.

Here is a version of the class that removes the initial setting of each of the GET request variables.  It works exactly the same as the earlier versions - it just takes a little more code.  If it makes anyone more comfortable, choose this version instead ;-)

<?php // RAY_temp_rgb192.php
error_reporting(E_ALL);

/* PROBLEM DEFINITION
 *
 * SEE http://www.experts-exchange.com/Web_Development/Web_Languages-Standards/PHP/Q_28143970.html
 *
 * captioning: on/off
 * video quality: 720,480,360,240
 * video size: small, large, full-screen
 * website.com/video.php?caption=on&video_quality=720&video_size=full_screen
 */

Class Get
{
    // ACTUAL REQUEST ARGUMENTS
    protected $is = array();

    // ALLOWABLE REQUEST ARGUMENTS
    protected $ok = array
    ( 'caption' => array('on',   'off')
    , 'quality' => array('720',  '480',   '360', '240')
    , 'display' => array('full', 'large', 'small')
    )
    ;

    // CONSTUCTOR OVERRIDES DEFAULT ARGUMENTS WITH THE REQUEST VARS
    public function __construct()
    {
        // COPY DEFAULT SETTINGS FROM LAST IN EACH ARRAY OF OPTIONS
        foreach ($this->ok as $key => $arr)
        {
            $this->is[$key] = end($arr);
        }

        // SET REQUEST VARS
        foreach ($_GET as $key => $val)
        {
            // IGNORE ATTACK VECTORS
            if (array_key_exists($key, $this->ok))
            {
                // CHOOSE ONLY VALID SETTINGS
                if (in_array($val, $this->ok[$key])) $this->is[$key] = $val;
            }
        }
    }

    // SETTER PERMITS RUN-TIME SETTINGS (NOT JUST URL LINKS)
    public function setArg($key, $val)
    {
        // HANDLE PROGRAMMING ERRORS
        if (!in_array($key, $this->ok))       trigger_error("FAIL KEY: $key => $val", E_USER_ERROR);
        if (!in_array($val, $this->ok[$key])) trigger_error("FAIL VAL: $key => $val", E_USER_ERROR);

        // SET THE VALUE
        $this->is[$key] = $val;
        return $this->getURL();
    }

    // GETTER PERMITS RUN-TIME OBSERVATION OF SETTINGS
    public function getIs()
    {
        // RETURN THE CURRENT SETTING VALUES
        return $this->is;
    }

    // GET THE CURRENT URL
    public function getURL($is=NULL)
    {
        if (!$is) $is = $this->is;
        return 'http://'
        . $_SERVER['HTTP_HOST']
        . $_SERVER['PHP_SELF']
        . '?'
        . http_build_query($is)
        ;
    }

    // REDACT THE CURRENT URL TO REMOVE ONE PARAMETER
    public function redactURL($key)
    {
        $is = $this->is;
        unset($is[$key]);
        return $this->getURL($is);
    }

    // BUILD ONE LINK TO CHANGE ONE SETTING
    public function getLink($key, $delim='|')
    {
        $url = $this->redactURL($key);
        $lnk = ucfirst($key) . ': ';

        // USE ONLY PREDEFINED ACCEPTABLE VALUES
        foreach ($this->ok[$key] as $val)
        {
            $lnk .= '<a href="' . $url . '&' . $key . '=' . urlencode($val) . '">' . ucfirst($val) . '</a>' . $delim;
        }
        $lnk = rtrim($lnk, $delim);
        return $lnk;
    }

    // BUILD ALL LINKS TO CHANGE THE SETTINGS
    public function getLinks($break='<br>')
    {
        $lnk = NULL;

        // USE ONLY PREDEFINED ACCEPTABLE VALUES
        foreach ($this->ok as $key => $arr)
        {
            $lnk .= $this->getLink($key) . $break;
        }

        // REMOVE THE FINAL BREAK TAG
        $len = strlen($lnk) - strlen($break);
        $lnk = substr($lnk, 0, $len);
        return $lnk;
    }
}

// SHOW THE USE CASE
$myreq = new GET;

// SHOW THE REMEMBERED SETTINGS, PLUS ANY CHANGES FROM THE LINKS
echo "<pre>";
echo "EXISTING AND REMEMBERED STATUS SETTINGS:" . PHP_EOL;
print_r($myreq->getIs());

echo $myreq->getLinks();

Open in new window

Best to all, over and out, ~Ray
0
 
LVL 33

Assisted Solution

by:Slick812
Slick812 earned 200 total points
ID: 39213026
not that it matters, and so far  rgb192  has trouble expressing what this code does or  how it is used, but from all appearances this is for javascript generating an AJAX call to the "video.php" with the specs for the vid display in the GET params, , which will return some DHTML to place in a DIV, to embed or use a video (flash I guess). Although  rgb192 says = "either client or server works", this seems like an uninformed statement, since  there are so many places that refer to "clicked on" and " links to click "  and  "clicking on one should not affect other ", , , the click is a browser event, and has nothing to do with server side PHP, except if you made a unneeded effort to get the url string made in the server through AJAX.

changed the javascript some to get an independent variable for the query string
<script>/* <![CDATA[ */

var queryArry = ["caption=on","quality=240","size=small"];
var queryStr = "website.com/video.php?caption=on&quality=240&size=small";// you can access this string for any purpose

function makeQuery(arryPos,value){
queryArry[arryPos] = value;
queryStr = "website.com/video.php?"+queryArry[0]+"&"+queryArry[1]+"&"+queryArry[2];
document.getElementById("vidInfo").innerHTML = queryStr;
}

/* ]]> */</script>

Open in new window

0
 
LVL 51

Expert Comment

by:Julian Hansen
ID: 39213459
@Ray - you misunderstand me - associative arrays will sort the problem out - that does not detract from the fact that the question is ambiguous because we don't know why there are two parameters in the query string with same name different value. How PHP deals with it and the fact that effect is that the last param wins - is beside the point - in this case the author (for all we know) might want the first value to prevail. It is ambiguous as to what the requirement is.
0
 

Author Closing Comment

by:rgb192
ID: 39213556
this was the Ray_Paseur script that I used although all worked but the urls looked cleaner

also tried Slick812 javascript

thanks
0

Featured Post

Better Security Awareness With Threat Intelligence

See how one of the leading financial services organizations uses Recorded Future as part of a holistic threat intelligence program to promote security awareness and proactively and efficiently identify threats.

Join & Write a Comment

Suggested Solutions

Title # Comments Views Activity
php mail headers 2 11
PHP and Soap 3 27
WooCommerce Sort by Date 4 6
windows 10 bash shell 4 33
Introduction HTML checkboxes provide the perfect way for a web developer to receive client input when the client's options might be none, one or many.  But the PHP code for processing the checkboxes can be confusing at first.  What if a checkbox is…
Deprecated and Headed for the Dustbin By now, you have probably heard that some PHP features, while convenient, can also cause PHP security problems.  This article discusses one of those, called register_globals.  It is a thing you do not want.  …
Learn how to match and substitute tagged data using PHP regular expressions. Demonstrated on Windows 7, but also applies to other operating systems. Demonstrated technique applies to PHP (all versions) and Firefox, but very similar techniques will w…
The viewer will learn how to count occurrences of each item in an array.

707 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question

Need Help in Real-Time?

Connect with top rated Experts

15 Experts available now in Live!

Get 1:1 Help Now