PHP form array notation, reversed? - php

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
}
}

Related

PHP array, assigning two values in array with the first data be exact

I've some problem to join an array in PHP array, I want the first data to be exact from variable but the second would be dynamic data, here's the example
I have some string like
my_str = "TEST"
then I would join so the result would be like:
my_arr = array(
array("TEST",22,18),
array("TEST",15,13),
array("TEST",5,2),
array("TEST",17,15)
);
how to join the string with the arr so the first index would be always the exact value?
If your arrays' depth is always the same, this script below will solve the problem for you. It loops through each element of $my_arr, typecasts your $my_str to an array and merges it to the beginning of each element.
$my_str = "TEST";
$my_arr = array(
array(22,18),
array(15,13),
array(5,2),
array(17,15)
);
foreach( $my_arr as &$value ) {
$value = array_merge( (array) $my_str, $value );
}
print_r( $my_arr );

How to make key value by explode and arrange matching key values into one key?

I am recently facing a practical problem.I am working with ajax form submission and there has been some checkboxes.I need all checkboxes with same name as key value pair.Suppose there is 4 checkboxes having name attribute =checks so i want something like $arr['checks'] = array(value1, value2, ...)
So i am getting my ajax $_POST code as suppose like: name=alex&checks=code1&checks=code2&checks=code3
I am using below code to make into an array
public function smdv_process_option_data(){
$dataarray = array();
$newdataarray = array();
$new = array();
$notices = array();
$data = $_POST['options']; // data received by ajax
$dataarray = explode('&', $data);
foreach ($dataarray as $key => $value) {
$i = explode('=', $value);
$j = 1;
if(array_key_exists($i[0], $newdataarray)){
if( !is_array($newdataarray[$i[0]]) ){
array_push($new, $newdataarray[$i[0]]);
}else{
array_push($new, $i[1]);
}
$newdataarray[$i[0]] = $new;
}else{
$newdataarray[$i[0]] = $i[1];
}
}
die($newdataarray);
}
Here i want $newdataarray as like below
array(
'name' => 'alex',
'checks => array(code1, code2, code3),
)
But any how I am missing 2nd value from checks key array.
As I see it you only need to do two explode syntaxes.
The first on is to get the name and here I explode on & and then on name= in order to isolate the name in the string.
The checks is an explode of &checks= if you omit the first item with array_slice.
$str = 'name=alex&checks=code1&checks=code2&checks=code3';
$name = explode("name=", explode("&", $str)[0])[1];
// alex
$checks = array_slice(explode("&checks=", $str), 1);
// ["code1","code2","code3"]
https://3v4l.org/TefuG
So i am getting my ajax $_POST code as suppose like: name=alex&checks=code1&checks=code2&checks=code3
Use parse_str instead.
https://php.net/manual/en/function.parse-str.php
parse_str ( string $encoded_string [, array &$result ] ) : void
Parses encoded_string as if it were the query string passed via a URL and sets variables in the current scope (or in the array if result is provided).
$s = 'name=alex&checks=code1&checks=code2&checks=code3';
parse_str($s, $r);
print_r($r);
Output
Array
(
[name] => alex
[checks] => code3
)
You may think this is wrong because there is only one checks but technically the string is incorrect.
Sandbox
You shouldn't have to post process this data if it's sent correctly, as that is not included in the question, I can only make assumptions about it's origin.
If your manually creating it, I would suggest using serialize() on the form element for the data for AJAX. Post processing this is just a band-aid and adds unnecessary complexity.
If it's from a source outside your control, you'll have to parse it manually (as you attempted).
For example the correct way that string is encoded is this:
name=alex&checks[]=code1&checks[]=code2&checks[]=code3
Which when used with the above code produces the desired output.
Array
(
[name] => alex
[checks] => Array
(
[0] => code1
[1] => code2
[2] => code3
)
)
So is the problem here, or in the way it's constructed...
UPDATE
I felt obligated to give you the manual parsing option:
$str = 'name=alex&checks=code1&checks=code2&checks=code3';
$res = [];
foreach(explode('&',$str) as $value){
//PHP 7 array destructuring
[$key,$value] = explode('=', $value);
//PHP 5.x list()
//list($key,$value) = explode('=', $value);
if(isset($res[$key])){
if(!is_array($res[$key])){
//convert single values to array
$res[$key] = [$res[$key]];
}
$res[$key][] = $value;
}else{
$res[$key] = $value;
}
}
print_r($res);
Sandbox
The above code is not specific to your keys, which is a good thing. And should handle any string formatted this way. If you do have the proper array format mixed in with this format you can add a bit of additional code to handle that, but it can become quite a challenge to handle all the use cases of key[] For example these are all valid:
key[]=value&key[]=value //[key => [value,value]]
key[foo]=value&key[bar]=value //[key => [foo=>value,bar=>value]]
key[foo][]=value&key[bar][]=value&key[bar][]=value //[key => [foo=>[value]], [bar=>[value,value]]]
As you can see that can get out of hand real quick, so I hesitate to try to accommodate that if you don't need it.
Cheers!

Get array value based on variable and indexes as string

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;

Array of strings to array of arrays

I have an array of strings in PHP like this:
people = array("John","Kim");
I want to convert each of those strings into arrays themselves. Basically, I now want a 2-dimensional array like
people(John[],Kim[]);
I've been struggling with the implementation and am not sure how to do it.
$people = array_fill_keys(array("John","Kim"), array());
Based on your comment, you should be using a combination of keys or values if you want to do this with multi dimensional arrays (which I'm not sure is the best way, but can't say w/o further context).
$people = array(
"john" => array()
);
Then when you want to add products, just go like:
$people["john"]["couch"] = 3; // bought 3 times.
$people["john"][$item] = 0; // if you don't know the count yet for whatever reason. You can always chagne it later the same way.
Now:
foreach( $people as $person => $purchases ){
echo UCFirst( $person );
if( ! empty( $purchases ) ){
echo ' has bought:<br />';
foreach( $purchases as $item => $qty ){
echo $item.' ('.$qty.')<br />';
}
}
}
I would recommend always making your keys either uppercase or lowercase if you are going to use named. Your call though.
If you give us more code / context, there may be much better ways to do this stuff.

Whats the best way to manage QUERY_STRING in php?

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;

Categories