Access array index using EVAL in PHP - php

I need to access specific indexes and keys of given arrays using eval, but somehow I cannot do so when my "path" is specified by a String. The code and content I am trying to access is bellow.
$final_eval = eval('
var_dump($contents->beneficiarios[0]->nomeOperadora);//returns ok value 'Operadora 123'
var_dump($contents->$temp_eval);//doesnt work when $temp_eval's value is 'beneficiarios[0]->nomeOperadora'
return $contents->$temp_eval;
');
Now if I use $temp_eval with value 'mensagem', without quotes, it works fine for the specified json key. (returns '2 users found').
The only problem seems to be when my "path" specifies an array index, as I need to access a value inside given array.
Bellow is the $contents value (I already decoded it before trying to access in my code):
{
"sucesso": true,
"mensagem": "2 users found",
"beneficiarios": [
{
"nomeOperadora": "Operadora 123",
"codigoBeneficiario": "XXAADD123"
},
{
"nomeOperadora": "Operadora 456",
"codigoBeneficiario": "XXBBEE843"
}
]
}
I need to access values such as in my first var_dump from the first code spinnet, json_key[index]->json_key, passing their "path" dinamically.
Any suggestions? Thanks in advance!

As Jeto and Jerson questioned, eval is indeed not necessary. I have tried using it because I get each object's path dynamically, and as my first approach it seemed correctly.
Anyway, the problem is that passing a string that contains the denotation '->' or '[index]' doesn't correctly access the object's property.
My solution is to explode the string and then loop as given bellow:
$explode = explode('->', '$contents->beneficiarios[0]->nomeOperadora');
$i = 0;
foreach($explode as $item):
$has_array_index = false;
$array_index = null;
$has_array_index = preg_match("/\[(.*?)\]/", $item, $array_index, PREG_UNMATCHED_AS_NULL);
if($has_array_index):
$item = str_replace($array_index[0], '', $item);
$array_index = substr($array_index[0], 1, -1);
endif;
if($i == 0):
if($has_array_index)
$final_eval = $contents->$item[$array_index];
else
$final_eval = $contents->$item;
else:
if($has_array_index)
$final_eval = $final_eval->$item[$array_index];
else
$final_eval = $final_eval->$item;
endif;
$i++;
endforeach;
It may not be the prettiest solution, but it's good enough to move on to more important things for now.

Related

Variable Variables for Array Key

Currently I am attempting to call a multidimensional array, using a string as a key or keys. I would like to use the following code, but I think the key is being interpreted as a string. Any solution?
$data= [];
$data['volvo'] = "nice whip";
$test = "['volvo']";
$data['drivers']['mike'] = "decent";
$test2 = "['drivers']['mike']";
echo $data$test; // should read 'nice whip'
echo $data$test2; // should read 'decent'
You just use the variable (which should just be the string and not PHP syntax) in place of the string literal.
$cars = [];
$cars['volvo'] = 'nice whip';
$test = 'volvo';
echo $cars[$test];
If you need a dynamic array access solution, you could also write a function, which does the actual array access like this:
function path($array, $path) {
$path = is_array($path) ? $path : explode('.', $path);
$current = $array;
while (count($path)) {
$seg = array_shift($path);
if (!isset($current[$seg])) throw new Exception('Invalid path segment: ' . $seg);
$current = $current[$seg];
}
return $current;
}
In your case, this would look like this
echo path($data, 'volvo');
echo path($data, 'drivers.mike');
or
echo path($data, ['volvo']);
echo path($data, ['drivers', 'mike']);
The problem is you can't pass multiple levels in one string like that. (If so, PHP would have to start looking for code fragments inside string array keys. And how would it know whether to interpret them as fragments and then split the string key up, or keep treating it as one string??)
Alt 1
One solution is to change the structure of $data, and make it a single level array. Then you supply keys for all the levels needed to find your data, joined together as a string. You would of course need to find a separator that works in your case. If the keys are plain strings then something simple like underscore should work just fine. Also, this wouldn't change the structure of your database, just the way data is stored.
function getDbItem($keys) {
// Use this to get the "old version" of the key back. (I.e it's the same data)
$joinedKey = "['".implode("'],['", $keys)."']";
$joinedKey = implode('_', $keys);
return $data[$joinedKey];
}
// Example
$data = [
'volvo' => 'nice whip',
'drivers_mike' => 'decent'
];
var_dump(getDbItem(['drivers', 'mike'])); // string(6) "decent"
Alt 2
Another way is to not change number of levels in $data, but simply traverse it using the keys passed in:
$tgt = $data;
foreach($keys as $key) {
if (array_key_exists($key, $tgt)) {
$tgt = $tgt[$key];
}
else {
// Non existing key. Handle properly.
}
}
// Example
$keys = ['drivers', 'mike'];
// run the above code
var_dump($tgt); // string(6) "decent"

PHP cURL string get everything before and after certain part of string

Im usin cURL to crabb some data from webpage.
But as the data is array based, but the size changes and varies.
Then i need to search for parts of string and want to get everyhting after the
part til next comma.
{"id":2988001,"teatiseNr":"50000099027","mkood":74,
Now here is the string.
I would only like to have everything after {"id":
til the first comma.
So my output would be 2988001
Why i need the search criteria is because some times there are more variables and that messes up the order.
Right now im using simple
$pieces = explode(",", $page);
And then just delete the rest with
str_replace('{"id":','',$pieces[0]);
There must be more elegant way to make this work.
this is a json string, so you can simply do:
$data = json_decode($string);
echo $data->id;
If it is array based then alistaircol, matei, and neil are right you should use something like
$data = json_decode($page);
$id = $data->id
Let's say for some reason the response actually not JSON and the order of the item with id is variable then something like this could work too
$no_braces = str_ireplace('{','',$page);
$no_quotes = str_ireplace('"','',$no_braces);
$items = explode(",",$no_quotes);
function getID($items){
foreach($items as $item){
$parts = explode($item, ':');
$key = $parts[0];
if($key === 'id'){
return $parts[1];
}
}
return null;
}

How to specify integers as keys in an associative array?

I have some code that grabs some rows from a table and I want to make an associative array in PHP that will be like [row_id] => row_title. This will then be used to populate a select list. The problem is, the key, unless I include a string in it, always reverts to an ordered number starting with 0. If I add a string in with the key, then the key retains the ID that I want. But obviously I don't want the string in the key.
Here's my code:
public static function select_array(){
$courses = ORM::factory('course')->order_by('title')->find_all();
$out = array();
foreach($courses as $c){
$out[$c->id] = $c->title;
}
return $out;
}
The $c->id should be the id from the database, but PHP is overriding this with a count number. If I do this:
public static function select_array(){
$courses = ORM::factory('course')->order_by('title')->find_all();
$out = array();
foreach($courses as $c){
$test = "." . $c->id;
$out[$test] = $c->title;
}
return $out;
}
Then the key will include the correct ID, but with a "." in front... I've tried using (string)$c->id but no luck with that either. I've also tried setting $test as " " . $c->id and then trimming it, but that doesn't work, and it's just a weird hacky attempt anyway.
Hope that makes sense. My question: How to simply tell the key to be a specific number?
Can you var_dump $courses before the foreach statement and $out before the return?
Well if it's overwriting it, I don't see why. Try this...
foreach($courses as $c){
$test = "" . $c->id;
$out[(int)$test] = $c->title;
}
The first snippet looks like it should work the way you want. Assuming that $c->id doesn't produce an ordered list of ints, are you sorting the array after retrieving from select_array()? Have you tried var_dump()'ng $out after the foreach and before the return statement?
If converting to a string solves the problem, try something like
$out[(string)$c->id] = $c->title;

How to access a $_POST item through the following array kind of syntax?

If i send four POST variables, but the second one — I dont know that the name="" tag will be; how can I access it? Can i use $_POST[1] or not?
Here's one solution using internal pointers:
if(count($_POST) > 1){ // just a check here.
reset($_POST); // reset the pointer regardless of its position
$second_value = next($_POST); // get the next value, aka 2nd element.
}
By the way with regards to the numeric index: PHP $_POST and $_GET are associative arrays! They do not support something like $_POST[0] or $_POST[1]. They will return NULL because they are not set. Instead $_POST["name"] would work.
From the PHP Manual: "An associative array of variables passed to the current script via the HTTP POST (or GET) method."
i have a handy function for this
function nth($ary, $n) {
$b = array_slice($ary, intval($n), 1);
return count($b) ? reset($b) : null;
}
in your case
$foo = nth($_POST, 1);
foreach( $_POST as $key => $value ){
if( is_int($key) ) //do something with $value
}
This will work if you know the other $_POST values have names in your forms (i.e., keys that aren't numbers).
You can loop through it:
foreach ($_POST as $k => $v) {
if (substr($k, 0, 3) == 'id_') {
// do stuff
}
}
But it really depends on what the criteria for the search is. In the above example it's pulling all the POST variables that start with "id_". You may be able to do it simpler if you have a different/better criteria.
You can if you convert it using array_values() first.
Example
<?php
$a = array(
"first key" => "first value",
"second key" => "second value",
);
$v = array_values($a);
echo "First value: {$v[0]}\n";
?>
Output
$ php -f a.php
First value: first value
EDIT: Thanks for commentators pointing out the initial error.
use
<?php
print_r($_POST);
?>
this will give you an idea of what is the key of the field you don't know.
Make a copy :
$vars = $_POST;
Remove the names you know :
unset( $vars[ "known variable 1" ] );
unset( $vars[ "known variable 2" ] );
All that remains is the variables you need : extract them with array_values or enumerate them with foreach, whatever.
a simple for each will do the trick if you do not know the array keys on the $_POST array
foreach($_POST as $key=>$value):
print 'key'.$key.' value'.$value
endforeach;
But it is recommended to know what your post variables are if you are planning on processing them.

A $_GET input parameter that is an Array

I'm trying to pass 3 parameter to a script, where the 3rd parameter $_GET['value3'] is supposed to be an array
$_GET['value1']
$_GET['value2']
$_GET['value3'] //an array of items
I'm calling the script like this: (notice my syntax for value3, I'm not sure it's correct)
http://localhost/test.php?value1=test1&value2=test2&value3=[the, array, values]
I then use a foreach to hopefully loop through the third parameter value3 which is the array
//process the first input $_GET['value1']
//process the second input $_GET['value2']
//process the third input $_GET['value3'] which is the array
foreach($_GET['value3'] as $arrayitem){
echo $arrayitem;
}
but I get the error Invalid argument supplied for foreach()
I'm not sure if my methodology is correct. Can some clarify how you'd go about doing the sort of thing
There is no such thing as "passing an array as a URL parameter" (or a form value, for that matter, because this is the same thing). These are strings, and anything that happens to them beyond that is magic that has been built into your application server, and therefore it is non-portable.
PHP happens to support the &value3[]=the&value3[]=array&value3[]=values notation to automagically create $_GET['value3'] as an array for you, but this is special to PHP and does not necessarily work elsewhere.
You can also be straight-forward and go for a cleaner URL, like this: value3=the,array,values, and then use explode(',', $_GET['value3']) in your PHP script to create an array. Of course this implies that your separator char cannot be part of the value.
To unambiguously transport structured data over HTTP, use a format that has been made for the purpose (namely: JSON) and then use json_decode() on the PHP side.
try
http://localhost/test.php?value1=test1&value2=test2&value3[]=the&value3[]=array&value3[]=values
For arrays you need to pass the query parameters as
value3[]=abc&value3[]=pqr&value3[]=xyz
You can cast the name of the index in the string too
?value1[a]=test1a&value1[b]=test1b&value2[c][]=test3a&value2[c][]=test3b
would be
$_GET['value1']['a'] = test1a
$_GET['value1']['b'] = test1b
$_GET['value2']['c'] = array( 'test3a', 'test3b' );
http://php.net/manual/en/reserved.variables.get.php
Check out the above link..
You will see how the GET method is implemented.
What happens is that the URL is taken, it is delimited using '&' and then they are added as a key-value pair.
public function fixGet($args) {
if(count($_GET) > 0) {
if(!empty($args)) {
$lastkey = "";
$pairs = explode("&",$args);
foreach($pairs as $pair) {
if(strpos($pair,":") !== false) {
list($key,$value) = explode(":",$pair);
unset($_GET[$key]);
$lastkey = "&$key$value";
} elseif(strpos($pair,"=") === false)
unset($_GET[$pair]);
else {
list($key, $value) = explode("=",$pair);
$_GET[$key] = $value;
}
}
}
return "?".((count($_GET) > 0)?http_build_query($_GET).$lastkey:"");
}
Since, they are added as a key-value pair you can't pass array's in the GET method...
The following would also work:
http://localhost/test.php?value3[]=the&value3[]=array&value3[]=values
A more advanced approach would be to serialize the PHP array and print it in your link:
http://localhost/test.php?value3=a:3:{i:0;s:3:"the";i:1;s:5:"array";i:2;s:6:"values";}
would, essentially, also work.

Categories