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.
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
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);
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 'Next page';
?>
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, '&'); // 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).
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)
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.
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;
Related
i have an array containing several ids sent by GET method, and i want to get each id by a variable , my code was fixed for 2 ids only and i retrieved them using the following code :
$searchString = ',';
if( strpos($_GET['id'], $searchString) != false )
{
$claimID = explode( ',', $_GET['id'] );
$claimID1=$claimID[0];
$claimID2=$claimID[1];
}
Now after a change, is it possible to get more than 2 ids, unlimited, and i want to retrieve them all and use them in queries and layouts, how could i achieve this ? i have to use a loop when exploding and whenever i want to do an operation on all the ids ( query for each id ) i have to loop ?
Ok so i used to explode on , and get the 2 values in 2 different parameters and do 2 queries to get amounts and add them together into 1 amount, and then use an update query for each id, my objective is still the same but for 2+ ids, note that in User No. it takes the 3 values sent but concatinated by commas for now
You can actually dynamically name variables, altough its not recommended:
$arr = [1, 2, 5];
$i = 1;
foreach($arr as $val) {
$name = "claimID" . $i++;
$$name = $val;
}
// Outputs 5
echo $claimID3;
You can create variable variables in PHP but I would not use and do that. Keeping everything in an array is much more easier.
Infos on variable variables: http://php.net/manual/en/language.variables.variable.php
(This is untested and as I said, I wouldn't do it).
if( strpos($_GET['id'], $searchString) != false ) {
$claimID = explode( ',', $_GET['id'] );
for($i=0;$i<count($claimID);$i++) {
$varname = 'claimID' . $i;
$$varname = $claimID[$i];
}
}
I'm trying to execute variable which part of it is a string.
Here it is:
$row = array(
'index_1' => array(
'index_2' => 'my-value'
)
);
$pattern = "['index_1']['index_2']";
I tried to do it in following ways:
// #1
$myValue = $row{$pattern};
// #2
$myValue = eval("$row$pattern");
I also trying to get it working with variable variable, but not successful.
Any tips, how should I did it? Or myabe there is other way. I don't know how may look array, but I have only name of key indexes (provided by user), this is: index_1, index_2
You could use eval but that would be quite risky since you say the values come from user input. In that case, the best way might be to parse the string and extract the keys. Something like this should work:
$pattern = "['index_1']['index_2']";
preg_match('/\[\'(.*)\'\]\[\'(.*)\'\]/', $pattern, $matches);
if (count($matches) === 3) {
$v = $row[$matches[1]][$matches[2]];
var_dump($v);
} else {
echo 'Not found';
}
This can help -
$row = array(
'index_1' => array(
'index_2' => 'my-value'
)
);
$pattern = "['index_1']['index_2']";
$pattern = explode("']['", $pattern); // extract the keys
foreach($pattern as $key) {
$key = str_replace(array("['", "']"), '', $key); // remove []s
if (isset($row[$key])) { // check if exists
$row = $row[$key]; // store the value
}
}
var_dump($row);
Storing the $row in temporary variable required if used further.
Output
string(8) "my-value"
If you always receive two indexes then the solution is quite straight forward,
$index_1 = 'index_1';// set user input for index 1 here
$index_2 = 'index_2';// set user input for index 2 here
if (isset($row[$index_1][$index_2])) {
$myValue = $row[$index_1][$index_2];
} else {
// you can handle indexes that don't exist here....
}
If the submitted indexes aren't always a pair then it will be possible but I will need to update my answer.
As eval is not safe, only when you know what you are ding.
$myValue = eval("$row$pattern"); will assign the value you want to $myValue, you can add use return to make eval return the value you want.
here is the code that use eval, use it in caution.
demo here.
<?php
$row = array(
'index_1' => array(
'index_2' => 'my-value'
)
);
$pattern = 'return $row[\'index_1\'][\'index_2\'];';
$myValue = eval($pattern);
echo $myValue;
So, I have this form that is rather complicated, and the form fields are named to comply with PHP array notation, as such:
<input name='service[123][info]' value=''>
And this of course works as intended and I get the array in $_POST, which I sanitize and then keep in $in. But now I want to reverse-engineer this, when I am iterating over the form again, I have this in $in:
array(
123 => array(
"info" => "foo"
)
)
And when I come to any given form field, I know that the field name is "service[123][info]" but how do I find "foo" in the sent array? Basically, I want to set the value="" parameter in the input when I have data for this field, and the data is kept in the $in array but the only reference to the data I have is the string "service[123][info]". Should I use regexp to parse that string? Sounds inflexible.
Basically, I would like something like:
$name = "service[123][info]";
$value = form_array_lookup($name, $in);
That sets $value to the correct value from $in as referenced by $name. I hope I am making myself clear. Thanks for any comment.
This is a very case-specific (and therefore, not very desirable) example, but the general idea is to use only one delimiter between items, explode the string, and then loop through the result, checking if each item index exists.
function parse_array_path( $string,array $subject ){
// remove ending brackets
$string = str_replace( "]","",$string );
// "[" is now the sole delimiter
$part = explode( "[",$string );
// loop and check for each index in subject array
$i = reset( $part );
do{
if( ! isset( $subject[$i] ) ){
return null;
}
$subject = $subject[$i];
}
while( $i = next( $part ) );
return $subject;
}
example usage:
<?php
$a = array(
"service"=>array(
123=>array(
"info"=>"hello, world"
)
)
);
$s = "service[123][info]";
print parse_array_path( $s,$a ); // "hello, world"
Use a 'foreach' to loop through the array and you can reassign the keys or values in any order you wish.
foreach ($in AS $in_key => $in_val) {
foreach ($in_val AS $in_val_key => $in_val_val) {
// ASSIGN VALUES TO A NEW ARRAY IF YOU WISH
// YOU NOW HAVE $in_key, $in_val_key, $in_val_val
// THAT YOU CAN WORK WITH AND ASSIGN
$array[$in_val_val] = $in_val_key; // OR WHATEVER
}
}
I have a code like that:
session_start();
$user = $_GET['user'];
$mode = $_GET['mode'];
$id1 = $_GET['id1'];
$id2 = $_GET['id2'];
$id3 = $_GET['id3'];
$id4 = $_GET['id4'];
$id5 = $_GET['id5'];
$id6 = $_GET['id6'];
$id7 = $_GET['id7'];
$id8 = $_GET['id8'];
$dep= $mode;
switch ($dep)
{
case "3m":
$dep = "Text 1";
break;
case "all":
$dep = "More text";
break;
default:
$dep = "Text1";
}
There are more other cases. I think I will have more id's and cases soon. Is there a simpler way to get all id's from URL push them into PHP code for evaluating?
I have found a code foreach:
foreach($_GET as $key => $value) {
echo 'key is: <b>' . $key . '</b>, value is: <b>' .$value. '</b><br />';
}
And it gets all variables from URL, but how to change the code in order to have it like this:
$variable = $_GET['variable'];
Any help appreciated :)
Use arrays, that's exactly what they're for. Name the parameters in the URL like:
id[]=1&id[]=2&...
Then $_GET['id'] is an array which you can easily loop through.
Many ids means you're looking for an array of ids, not id1, id2, id3 etc. An array allows you to access them virtually the same way as $id[1], $id[2] etc, but without the headache of needing to herd hundreds of independent variables.
There's also no need to assign each value from $_GET into its own variable, you can use those values directly from $_GET. They're not getting any better by assigning them into individual variables.
Assuming I understood correctly and you want all GET variables to be actual variables you can use, there's a function extract to do that.
However, as noted in the documentation:
Do not use extract() on untrusted data, like user input (i.e. $_GET,
$_FILES, etc.). If you do, for example if you want to run old code
that relies on register_globals temporarily, make sure you use one of
the non-overwriting flags values such as EXTR_SKIP and be aware that
you should extract in the same order that's defined in variables_order
within the php.ini.
So basically you should not do this unless you have good reasons, and be careful if you do as to not overwrite any existing values.
However, if your alternative is to do this:
foreach($_GET as $key => $value) {
$$key=$value;
}
then extract is certainly better, as a) you can set it to not overwrite any existing variables, and b) you can have a prefix, so those imported variables can be distinguished. Like this:
extract ( $_GET, EXTR_SKIP);
For $user, $mode, $id which don't overwrite anything, or
extract ( $_GET, EXTR_PREFIX_ALL, 'user_input' );
for $user_input_mode, $user_input_user, $user_input_id etc.
function getIDs()
{
$ids = array();
if(isset($_GET['id']))
{
foreach($_GET['id'] as $key => $value)
{
$ids[$key] = $value;
}
}
return $ids;
}
If you can get your URL to send an array of id GET parameters to a PHP script you can just parse the $_GET['id'] array in the above function, assuming the URI looks like ?id[]=1&id[]=2&id[]=3
$ids = getIDs();
You can write
foreach($_GET as $key => $value) {
$$key=$value;
}
this will assign every key name as a varibale.
How can I remove ?cat= from the example 1 so it can look like example 2 using PHP.
Example 1
?cat=some-cat
Example 2
some-cat
Easy, use str_replace:
$cat = '?cat=some-cat';
$cat = str_replace('?cat=', '', $cat);
EDIT:
If you are pulling this query string through something like $_SERVER['QUERY_STRING'], then I'd opt for you to use $_GET, which is an associative array of the GET variables passed to your script, so if your query string looked like this:
?cat=some-cat&dog=some-dog
The $_GET array would look like this:
(
'cat' => 'some-cat',
'dog' => 'some-dog'
)
$cat = $_GET['cat']; //some-cat
$dog = $_GET['dog']; //some-dog
Another edit:
Say you had an associative array of query vars you wish to append onto a URL string, you'd do something like this:
$query_vars = array();
$query_vars['cat'] = 'some-cat';
$query_vars['dog'] = 'some-dog';
foreach($query_vars as $key => $value) {
$query_vars[] = $key . '=' . $value;
unset($query_vars[$key]);
}
$query_string = '?' . implode('&', $query_vars); //?cat=some-cat&dog=some-dog
Yes, you can, very easily:
$cat = '?cat=some-cat';
$cat = substr($cat, 5); // remove the first 5 characters of $cat
This may not be the best way to do this. That will depend on what you are attempting to achieve...