Get array's value by list of keys in PHP - php

I have a simple methods to access to variables by their names in the class:
function get_value($name) {
return isset($this->vars[$name]) ? $this->vars[$name] : NULL;
}
function set_value($name, $value) {
//Some operations with value
$this->vars[$name] = $value;
}
But i want that vars would be a multidimensional array. Something like:
//$names = array('blocks', 'top', 1)
function get_value($names) {
//Try to return $this->vars['blocks']['top'][1]
}
I can access to value using loop like here https://stackoverflow.com/a/5127874/7462321 But "set_value" code will be uglier. Please, help to to come up with an elegant implementation of this.

Would a function like this be fine?
function get_value($arr, $keys) {
if (!is_array($keys)) {
$keys = [$keys];
}
foreach ($keys as $key) {
if (!isset($arr[$key])) {
return NULL;
}
$arr = $arr[$key];
}
return $arr;
}
Call it like this:
get_value($array, [1, 2, 3])
or:
get_value($array, 1)

Would this fit your needs ?
I had implemented something like this this way :
<?php
class Settings {
// [...] Some stuff
/**
* Sets a value to the corresponding key
* #throws SettingsException If $key is not well written
* #param string $key The depth slahes key
* #param mixed The value to set
*/
public function setValue($key, $value){
if(strpos($key, '/') !== false){
if(($key = trim(preg_replace('#[/]+#', '/', $key), ' /')) === ''){
throw new SettingsException('"' . $key . '" is not valid');
}
$this->_setValue($key, $this->_currentGroup, $value);
} else {
$this->_currentGroup[$key] = $value;
}
$this->_saved = false;
return $this;
}
/**
* Return a setting value
* #throws SettingsException If the key doesn't exists or is null
* #param string $key The depth slashes key
* #return mixed The value corresponding to the key
*/
public function value($key){
if(strpos($key, '/')){
if(($key = trim(preg_replace('#[/]+#', '/', $key), ' /')) === ''){
throw new SettingsException('"' . $key . '" is not valid');
}
return $this->_value($key, $this->_currentGroup, $key);
} else if(isset($this->_currentGroup[$key])) {
return $this->_currentGroup[$key];
} else {
throw new SettingsException('"' . $key . '" is not a valid key');
}
}
private function _setValue($key, &$configDepth, $value){
if(($pos = strpos($key, '/'))){
if(!isset($configDepth[($k = substr($key, 0, $pos))])) {
$configDepth[$k] = array();
}
$this->_setValue(substr($key, $pos+1), $configDepth[$k], $value);
} else {
$configDepth[$key] = $value;
}
}
private function _value($key, &$configDepth, $prefix){
if(($pos = strpos($key, '/'))){
if(!isset($configDepth[($k = substr($key, 0, $pos))])) {
throw new SettingsException('The prefix "' . $prefix . '" doesn\'t exists');
}
return $this->_value(substr($key, $pos+1), $configDepth[$k], $prefix);
} else if(!isset($configDepth[$key])) {
throw new SettingsException('The prefix "' . $prefix . '" doesn\'t exists');
} else {
return $configDepth[$key];
}
}
}
Settings and getting value works like the above :
<?php
$s = new Settings;
$s->setValue('main/foo', 'bar'); // $s::_s[main][foo] = bar;
$main = $s->value('main'); // return Setting like an array(foo => bar);
$bar = $s->value('main/foo'); // return string value bar
//$s['main'] == $s->value('main');
// $s['main']['foo'] = 'bar' == $s->setValue('main/foo', 'bar');

Related

PHP recursive multidimensional loop

$printArr = recursive($newArray); //calls recursive function
$data = [];
var_dump($data);
var_dump($printArr);
function recursive($array, $level = 0)
{
$searchingValue = 'tableName';
foreach($array as $key => $value)
{
//If $value is an array.
if(is_array($value))
{
recursive($value, $level + 1);
}
else
{
//It is not an array, so print it out.
if($key == $searchingValue)
{
echo "[".$key . "] => " . $value, '<br>';
$data[] = $value;
}
}
}
}
So I have this function and I am trying to save $value value into $data[] array. But it always returns it empty and I don't know why I can't get $value saved outside the function.
If i echo $value I get what i need but like I've mentioned the variables doesn't get saved in this case - table names.
You need to pass the $data to your recursive function. Also you need to return the $data.
Try this code :
function recursive($array, $level = 0, $data =[])
{
$searchingValue = 'tableName';
foreach($array as $key => $value)
{
//If $value is an array.
if(is_array($value))
{
recursive($value, $level + 1 , $data);
}
else
{
//It is not an array, so print it out.
if($key == $searchingValue)
{
echo "[".$key . "] => " . $value, '<br>';
$data[] = $value;
}
}
}
return $data;
}
You can't access variable $data, which is outside the function, from the function. You need to pass it by reference or return it. Small example
<?php
$a = 1;
// Your case
function b() {
$a = 4;
return true;
}
// Passing by reference
function c(&$d) {
$d = 5;
return true;
}
// Using return
function d($d) {
$d = 6;
return $d;
}
b();
var_dump($a);
c($a);
var_dump($a);
$a = d($a);
var_dump($a);
https://3v4l.org/UXFdR

My cookie class keeps returning null when getting the cookie

I am creating my own custom cookie class and I can not seem to figure out what I am doing wrong. Here is my cookie class:
<?php
class Cookie implements CookieHandlerInterface {
private $_domain;
private $_secure;
public function __construct(array $config = array()) {
$this->_domain = isset($config['domain']) ? $config['domain'] : 'localhost';
$this->_secure = isset($config['secure']) ? $config['secure'] : false;
}
public function set($name, $value = null, $timeLength) {
if (!is_null($value)) {
if (is_array($value)) {
if ($this->__isMultiArray($array)) {
return null;
} else {
$value = $this->__arrayBuild($value);
$value = 'array(' . $value . ')';
}
} elseif (is_bool($value)) {
if ($value) {
$value = 'bool(true)';
} else {
$value = 'bool(false)';
}
} elseif (is_int($value)) {
$value = 'int(' . strval($value) . ')';
} elseif (is_float($value)) {
$value = 'float(' . strval($value) . ')';
} elseif (is_string($value)) {
$value = 'string(' . $value . ')';
} else {
return null;
}
} else {
$value = 'null(null)';
}
setcookie($name, $value, (time() + $timeLength), '/', $this->_domain, $this->_secure, true);
}
public function get($name, $defualtOutput = null) {
if (isset($_COOKIE[$name])) {
$output = rtrim($_COOKIE[$name], ')');
$xr1 = mb_substr($output, 0, 1);
if (equals($xr1, 'a')) {
$output = ltrim($output, 'array(');
return $this->__arrayBreak($output);
}
if (equals($xr1, 'b')) {
$output = ltrim($output, 'bool(');
if (equals($output, 'true')) {
return true;
} else {
return false;
}
}
if (equals($xr1, 'i')) {
$output = ltrim($output, 'int(');
return (int) $output;
}
if (equals($xr1, 'f')) {
$output = ltrim($output, 'float(');
return (float) $output;
}
if (equals($xr1, 's')) {
$output = ltrim($output, 'string(');
return $output;
}
if (equals($output, 'null(null)')) {
return null;
}
}
if (
!is_array($defualtOutput)
&& !is_bool($defualtOutput)
&& !is_int($defualtOutput)
&& !is_float($defualtOutput)
&& !is_string($defualtOutput)
&& !is_null($defualtOutput)
) {
trigger_error(
'The $defualtOutput var needs to be only certain types of var types. Allowed (array, bool, int, float, string, null).',
E_USER_ERROR
);
}
return $defualtOutput;
}
public function delete($name) {
if (isset($_COOKIE[$name])) {
setcookie($name, '', time() - 3600, '/', $this->_domain, $this->_secure, true);
}
}
private function __arrayBuild($array) {
$out = '';
foreach ($array as $index => $data) {
$out .= ($data != '') ? $index . '=' . $data . '|' : '';
}
return rtrim($out, '|');
}
private function __arrayBreak($cookieString) {
$array = explode('|', $cookieString);
foreach ($array as $i => $stuff) {
$stuff = explode('=', $stuff);
$array[$stuff[0]] = $stuff[1];
unset($array[$i]);
}
return $array;
}
private function __isMultiArray($array) {
foreach ($array as $key => $value) {
if (is_array($value)) {
return true;
}
}
return false;
}
}
?>
I set a test cookie for example app('cookie')->set('test', 'hello', 0);
sure enough it created the cookie like expected. So the cookie reads string(hello)
When I try to echo it, it echos the default value instead of the actual variable, so app('cookie')->get('test', 'test'); returns test
The get function should check if the cookie exists with isset($_COOKIE[$cookieName]) and then it should trim the extra ) with rtrim($_COOKIE[$cookieName], ')') then it should grab the first character in the string with mb_substr($_COOKIE[$cookieName], 0, 1) the 0 starts at the beginning and the 1 grabs only the first character.
After it compares it with the default (a, b, i, f, s) for example if it starts with an s its a string by default, if it was i it was sent as an int by default, etc. etc.
If they all come up as false it checks to see if it was sent as null if so it return null else it returns the default value passed.
The equals function is the same as $var1 == $var2 it is timing attack safe.
so it keeps returning the default value which is null, any help would be helpful thanks in advance.
Lol i feel real stupid i put 0 as the third argument thinking it will tell the cookie to expire when the browser session closes, but it did (time() + 0) which does not equal 0. so as it was setting the cookie it expired upon creation. So i did time() - (time() * 2). i achieved the goal i wanted.

How to merge two arrays and concat the values with PHP

I'm looking for an easy solution to create a little function to merge two arrays with value concat (I'm using it to create html tag attribute):
$default["class"] = "red";
$new["class"] = "green";
$new["style"] = "display:block"
The result:
$res["class"] = "red green";
$res["style"] = "display: block";
and one more option:
if the $new is not an array, just concat with the $default["class"] (if this exist), and the other side: if the $default is a simple string, convert to array: $default["class"] = $default;
I created a function but would like to use an easier, shorter way for that:
function attrMerge( $default, $new="" ){
$res = array();
if(!is_array($default)) {
$res["class"] = $default;
}
else {
$res = $default;
}
if( $new !== "" ){
if(!is_array($new)) {
if(isset($res["class"])){
$res["class"].= " ".$new;
}
}
else {
foreach($new as $key=>$value) {
if( isset($res[$key]) ) {
$res[$key].= " ".$value;
}
else {
$res[$key] = $value;
}
}
}
}
return $res;
}
$a = attrMerge("red", array("class"=>"green", "style"=>"display: block;"));
I think this is the function that you need. I have initialised the css classes and styles as empty and in depends what you pass into the function then you get the relevant array
/**
* This function returns an array of classes and styles
*
* #param $default
* #param $new
* #return array
*/
function attrMerge($default=null, $new=nul)
{
$result = array();
$result['class'] = "";
$result['style'] = "";
// add default class if exists
if (!empty($default) && is_string($default)) {
// $default is string
$result['class'] = $default;
}
if (!empty($default)
&& is_array($default)
) {
if (array_key_exists('class', $default)
&& !empty($default['class'])
) {
// $default['class'] exists and it's not empty
$result['class'] = $default['class'];
}
if (array_key_exists('style', $default)
&& !empty($default['style'])
) {
// $default['style'] exists and it's not empty
$result['style'] = $default['style'];
}
}
// add additional classes OR styles
if (!empty($new)) {
if(!is_array($new)) {
$result['class'] = empty($result['class'])
? $new
: $result['class'] . " " . $new;
} else {
foreach ($new as $key => $value) {
if (isset($result[$key])) {
$result[$key] = empty($result[$key])
? $value
: $result[$key] . " " . $value;
} else {
$result[$key] = $value;
}
}
}
}
return $result;
}
A way I believe suits your need, hopefully it's as adaptable and effecient as you were expecting.
$array1 = array(
'class' => 'class1',
'style' => 'display: none;'
);
$array2 = array(
'class' => 'class2'
);
$arrayFinal = arrayMerge($array1, $array2);
var_dump($arrayFinal);
function arrayMerge($arr1, $arr2 = ''){
// Array of attributes to be concatenated //
$attrs = array('class');
if(is_array($arr2)){
foreach($attrs as $attr){
if(isset($arr1[$attr]) && isset($arr2[$attr])){
// Not using .= to allow for smart trim (meaning empty check etc isn't needed //
$arr1[$attr] = trim($arr1[$attr] . ' ' . $arr2[$attr]);
}
}
}else{
$arr1['class'] = trim($arr1['class'] . ' ' . $arr2);
}
return $arr1;
}
$def = ['class' => 'red'];
$new = ['class' => 'green', 'style' => 'style'];
function to_array($in) {
return is_array($in) ? $in : ['class' => $in];
}
$def = to_array($def);
$new = to_array($new);
$res = $def;
array_walk($new, function ($val, $key) use (&$res) {
$res[$key] = trim(#$res[$key] . ' ' . $val);
});
var_dump($res);

Rewrite config parameter with phalcon

Is it possible to rewrite config parameter with phalcon?
I use ini File Type.
If not - tell me how to implement please.
if you want to create ini file with php, it is possible, even w/o phalcon.
from PHP docs comments:
Read file : $ini = INI::read('myfile.ini');
Write file : INI::write('myfile.ini', $ini);
custom INI class Features :
support [] syntax for arrays
support . in keys like bar.foo.something = value
true and false string are automatically converted in booleans
integers strings are automatically converted in integers
keys are sorted when writing
constants are replaced but they should be written in the ini file between braces : {MYCONSTANT}
class INI {
/**
* WRITE
*/
static function write($filename, $ini) {
$string = '';
foreach(array_keys($ini) as $key) {
$string .= '['.$key."]\n";
$string .= INI::write_get_string($ini[$key], '')."\n";
}
file_put_contents($filename, $string);
}
/**
* write get string
*/
static function write_get_string(& $ini, $prefix) {
$string = '';
ksort($ini);
foreach($ini as $key => $val) {
if (is_array($val)) {
$string .= INI::write_get_string($ini[$key], $prefix.$key.'.');
} else {
$string .= $prefix.$key.' = '.str_replace("\n", "\\\n", INI::set_value($val))."\n";
}
}
return $string;
}
/**
* manage keys
*/
static function set_value($val) {
if ($val === true) { return 'true'; }
else if ($val === false) { return 'false'; }
return $val;
}
/**
* READ
*/
static function read($filename) {
$ini = array();
$lines = file($filename);
$section = 'default';
$multi = '';
foreach($lines as $line) {
if (substr($line, 0, 1) !== ';') {
$line = str_replace("\r", "", str_replace("\n", "", $line));
if (preg_match('/^\[(.*)\]/', $line, $m)) {
$section = $m[1];
} else if ($multi === '' && preg_match('/^([a-z0-9_.\[\]-]+)\s*=\s*(.*)$/i', $line, $m)) {
$key = $m[1];
$val = $m[2];
if (substr($val, -1) !== "\\") {
$val = trim($val);
INI::manage_keys($ini[$section], $key, $val);
$multi = '';
} else {
$multi = substr($val, 0, -1)."\n";
}
} else if ($multi !== '') {
if (substr($line, -1) === "\\") {
$multi .= substr($line, 0, -1)."\n";
} else {
INI::manage_keys($ini[$section], $key, $multi.$line);
$multi = '';
}
}
}
}
$buf = get_defined_constants(true);
$consts = array();
foreach($buf['user'] as $key => $val) {
$consts['{'.$key.'}'] = $val;
}
array_walk_recursive($ini, array('INI', 'replace_consts'), $consts);
return $ini;
}
/**
* manage keys
*/
static function get_value($val) {
if (preg_match('/^-?[0-9]$/i', $val)) { return intval($val); }
else if (strtolower($val) === 'true') { return true; }
else if (strtolower($val) === 'false') { return false; }
else if (preg_match('/^"(.*)"$/i', $val, $m)) { return $m[1]; }
else if (preg_match('/^\'(.*)\'$/i', $val, $m)) { return $m[1]; }
return $val;
}
/**
* manage keys
*/
static function get_key($val) {
if (preg_match('/^[0-9]$/i', $val)) { return intval($val); }
return $val;
}
/**
* manage keys
*/
static function manage_keys(& $ini, $key, $val) {
if (preg_match('/^([a-z0-9_-]+)\.(.*)$/i', $key, $m)) {
INI::manage_keys($ini[$m[1]], $m[2], $val);
} else if (preg_match('/^([a-z0-9_-]+)\[(.*)\]$/i', $key, $m)) {
if ($m[2] !== '') {
$ini[$m[1]][INI::get_key($m[2])] = INI::get_value($val);
} else {
$ini[$m[1]][] = INI::get_value($val);
}
} else {
$ini[INI::get_key($key)] = INI::get_value($val);
}
}
/**
* replace utility
*/
static function replace_consts(& $item, $key, $consts) {
if (is_string($item)) {
$item = strtr($item, $consts);
}
}
}
find out more here: http://lt1.php.net/parse_ini_file

Fix bug in PayPal PHP SDK Core

I am having trouble find the problem in figuring out the problem using merchant-sdk-php I found on github. For some reason its throwing this error. I tried looking at the code but I dont under stand it or see the problem.
Fatal error: Call to undefined method stdClass::toXMLString() in /home/content/08/10639508/html/wp-content/plugins/donation-manager/library/vendor/paypal/paypal-sdk-core-php-bc7822a/lib/PPXmlMessage.php on line 89
<?php
/**
* #author
*/
abstract class PPXmlMessage
{
/**
* #return string
*/
public function toSOAP()
{
return $this->toXMLString();
}
/**
* #return string
*/
public function toXMLString()
{
if (count($properties = get_object_vars($this)) >= 2 && array_key_exists('value', $properties)) {
$attributes = array();
foreach (array_keys($properties) as $property) {
if ($property === 'value') continue;
if (($annots = PPUtils::propertyAnnotations($this, $property)) && isset($annots['attribute'])) {
if (($propertyValue = $this->{$property}) === NULL || $propertyValue == NULL) {
$attributes[] = NULL;
continue;
}
$attributes[] = $property . '="' . PPUtils::escapeInvalidXmlCharsRegex($propertyValue) . '"';
}
}
if (count($attributes)) {
return implode(' ', $attributes) . '>' . PPUtils::escapeInvalidXmlCharsRegex($this->value);
}
}
$xml = array();
foreach ($properties as $property => $defaultValue) {
if (($propertyValue = $this->{$property}) === NULL || $propertyValue == NULL) {
continue;
}
if (is_array($defaultValue) || is_array($propertyValue)) {
foreach ($propertyValue as $item) {
if (!is_object($item)) {
$xml[] = $this->buildProperty($property, $item);
}else{
$xml[] = $this->buildProperty($property, $item);
}
}
} else {
$xml[] = $this->buildProperty($property, $propertyValue);
}
}
return implode($xml);
}
/**
* #param string $property
* #param PPXmlMessage|string $value
* #param string $namespace
* #return string
*/
private function buildProperty($property, $value, $namespace = 'ebl')
{
$annotations = PPUtils::propertyAnnotations($this, $property);
if (!empty($annotations['namespace'])) {
$namespace = $annotations['namespace'];
}
if (!empty($annotations['name'])) {
$property = $annotations['name'];
}
$el = '<' . $namespace . ':' . $property;
if (!is_object($value)) {
$el .= '>' . PPUtils::escapeInvalidXmlCharsRegex($value);
} else {
if (substr($value = $value->toXMLString(), 0, 1) === '<' || $value=='') {
$el .= '>' . $value;
} else {
$el .= ' ' . $value;
}
}
return $el . '</' . $namespace . ':' . $property . '>';
}
/**
* #param array $map
* #param string $prefix
*/
public function init(array $map = array(), $prefix = '')
{
if (empty($map)) {
return;
}
if (($first = reset($map)) && !is_array($first) && !is_numeric(key($map))) {
parent::init($map, $prefix);
return;
}
$propertiesMap = PPUtils::objectProperties($this);
$arrayCtr = array();
foreach ($map as $element) {
if (empty($element) || empty($element['name'])) {
continue;
} elseif (!array_key_exists($property = strtolower($element['name']), $propertiesMap)) {
if (!preg_match('~^(.+)[\[\(](\d+)[\]\)]$~', $property, $m)) {
continue;
}
$element['name'] = $m[1];
$element['num'] = $m[2];
}
$element['name'] = $propertiesMap[strtolower($element['name'])];
if(PPUtils::isPropertyArray($this, $element['name'])) {
$arrayCtr[$element['name']] = isset($arrayCtr[$element['name']]) ? ($arrayCtr[$element['name']]+1) : 0;
$element['num'] = $arrayCtr[$element['name']];
}
if (!empty($element["attributes"]) && is_array($element["attributes"])) {
foreach ($element["attributes"] as $key => $val) {
$element["children"][] = array(
'name' => $key,
'text' => $val,
);
}
if (isset($element['text'])) {
$element["children"][] = array(
'name' => 'value',
'text' => $element['text'],
);
}
$this->fillRelation($element['name'], $element);
} elseif (!empty($element['text'])) {
$this->{$element['name']} = $element['text'];
} elseif (!empty($element["children"]) && is_array($element["children"])) {
$this->fillRelation($element['name'], $element);
}
}
}
/**
* #param string $property
* #param array $element
*/
private function fillRelation($property, array $element)
{
if (!class_exists($type = PPUtils::propertyType($this, $property))) {
trigger_error("Class $type not found.", E_USER_NOTICE);
return; // just ignore
}
if (isset($element['num'])) { // array of objects
$this->{$property}[$element['num']] = $item = new $type();
$item->init($element['children']);
} else {
$this->{$property} = new $type();
$this->{$property}->init($element["children"]);
}
}
}
I had this exact same error (with my live application - it worked fine in my test code). I eventually realized that, when I copied over my test code into the live environment and changed my credentials and URLs from the sandbox ones to the live ones ... I somehow deleted a line of code initializing a PaymentDetailsType object before calling SetExpressCheckout. So this error seemed pretty unrelated, but it was just a problem with setting up the objects before making the call to PayPal.
Perchance are you using json_encode/decode on your PaymentDetail record? It seems that PayPal is very particular about the component classes; stdClass (which json_decode generates) won't cut it. Serialize works, but there are warnings about using it.

Categories