Thing for me is not clear. Before I just used preg_replace but on a newer version of php had to use preg_replace_callback after that happened to me this
PHP message: PHP Warning: preg_replace_callback(): Requires argument 2, '[$1_1]', to be a valid callback in
this &c=jQuery31102606949325169924_1480249921485?_=1484049921486
$this->aURI = explode('/', $_SERVER['SCRIPT_NAME']);
$sRequest = preg_replace('!'.$this->sURI.'(.*)$!i', '$1', $_SERVER['REQUEST_URI']);
if(substr($sRequest, -1)!='/')
$sRequest .= '/';
$sGets = $this->parseUrl($sRequest);
I dont know but i figure out when i insert url which has number 404 as value in any place I have a white page
private function parseUrl($sRequest){
$sVars = null;
foreach($this->aRoutingParse AS $k => $v){
if(!is_array($v))
continue;
preg_match_all('!\[(.+?)\]!i', $v[0], $aExpression_);
$sExpression = preg_replace_callback('!\[(.+?)\]!i', function($m) use ($k){
return $this->transformParam($m[1], $k);
}, $v[0]);
if(preg_match_all('!'.$sExpression.'!i', $sRequest, $aExpression__)){
foreach($aExpression__ AS $k_ => $v_){
foreach($v_ AS $kkk => $vvv){
if(!isset($aExpression_[1][$k_-1]))
$aExpression_[1][$k_-1] = null;
if($kkk>0)
$aExpression[] = array($aExpression_[1][$k_-1].'_'.$kkk, $vvv);
else
$aExpression[] = array($aExpression_[1][$k_-1], $vvv);
}
}
unset($aExpression[0]);
$iCount = count($aExpression__[0]);
if($iCount>1){
for($i=0;$i<$iCount;$i++){
if($i>0)
$sVars .= '&'.preg_replace_callback('!\[(.+?)\]!i', '[$1_'.$i.']', $v[1]);
else
$sVars = '&'.$v[1];
}
}else
$sVars = '&'.$v[1];
foreach($aExpression AS $k => $v_){
if(!isset($v['_'.$v_[0]]))
$v['_'.$v_[0]] = null;
if(!is_array($v['_'.$v_[0]]))
$sVars = str_replace('['.$v_[0].']', $v_[1], $sVars);
else {
$this->aRoutingParse = array($v['_'.$v_[0]]);
$sVars = $sVars.$this->parseUrl($v_[1]);
}
}
break;
}
}
return $sVars;
}
solution:
method return first the first found value
in $this->aRoutingParse i have this and somehow crash
array('404' => array('404', 'task=page&action=404'),
The preg_replace_callback expects a callback function as the second argument. You pass a string replacement pattern in preg_replace_callback('!\[(.+?)\]!i', '[$1_'.$i.']', $v[1]).
Instead preg_replace_callback('!\[(.+?)\]!i', '[$1_'.$i.']', $v[1]) use:
preg_replace('!\[(.+?)\]!i', '[$1_'.$i.']', $v[1])
Related
I use the below block of code to validate Unique username.
function validateRepositoryUnique($field, $list, &$valid) {
if ( preg_grep('/^'.preg_quote($field->value).'$/i', $list) == -1) {
$valid = false;
$field->valid = false;
$field->error = '"' . $field->value . '" already exists.';
return false;
}
return true;
}
Example.
$filed->value = "test";
$list = array('test','test1','Test');
However I passed "test" in $filed->value. the Boolean kept showing value bool(true) when i did var_dump(validateRepositoryUnique($field, $list, &$valid));
And whatever I have inputted "test", "abc", "a", the Boolean kept return value bool(true).
My intention is when text found in array, it will return the $valid's value to false and print out the error.
Apology for my bad English and my basic knowledge of PHP programming language.
preg_grep does not return -1 if it finds no results. If returns an array of what it found. You can see the output in the example below.
Notice that I somewhat rewrote your function.
function validateRepositoryUnique($field, $list, &$valid) {
$preg = preg_grep('/^'.preg_quote($field->value).'$/i', $list) ;
var_dump($preg);
echo "\n";
if ( count($preg) == 0 ) {
$valid = false;
$field->valid = false;
$field->error = '"' . $field->value . '" already exists.';
return false;
}
return true;
}
$v;
$list = ['square', 'round', 'long'];
$f1 = new stdclass;
$f1->value = 'round';
$result = validateRepositoryUnique($f1, $list, $v);
var_dump($result);
echo "\n";
$f1->value = 'grass';
$result = validateRepositoryUnique($f1, $list, $v);
var_dump($result);
echo "\n";
$f1->value = 'triangle';
$result = validateRepositoryUnique($f1, $list, $v);
var_dump($result);
echo "\n";
I have the following in an INI file:
[country]
SE = Sweden
NO = Norway
FI = Finland
However, when var_dump()ing PHP's parse_ini_file() function, I get the following output:
PHP Warning: syntax error, unexpected BOOL_FALSE in test.ini on line 2
in /Users/andrew/sandbox/test.php on line 1
bool(false)
It appears that "NO" is reserved. Is there any other way I can set a variable named "NO"?
Another hack would be to reverse your ini keys with their values and use array_flip:
<?php
$ini =
"
[country]
Sweden = 'SE'
Norway = 'NO'
Finland = 'FI'
";
$countries = parse_ini_string($ini, true);
$countries = array_flip($countries["country"]);
echo $countries["NO"];
Still you will need to use quotes around NO (at least), if you do
Norway = NO
you don't get an error but value for $countries["NO"] will be an empty string.
This propably comes a little late but the way PHPs parse_ini_file works bothered me so much that I wrote my own little parser.
Feel free to use it, but use with care it has only been shallowly tested!
// the exception used by the parser
class IniParserException extends \Exception {
public function __construct($message, $code = 0, \Exception $previous = null) {
parent::__construct($message, $code, $previous);
}
public function __toString() {
return __CLASS__ . ": [{$this->code}]: {$this->message}\n";
}
}
// the parser
function my_parse_ini_file($filename, $processSections = false) {
$initext = file_get_contents($filename);
$ret = [];
$section = null;
$lineNum = 0;
$lines = explode("\n", str_replace("\r\n", "\n", $initext));
foreach($lines as $line) {
++$lineNum;
$line = trim(preg_replace('/[;#].*/', '', $line));
if(strlen($line) === 0) {
continue;
}
if($processSections && $line{0} === '[' && $line{strlen($line)-1} === ']') {
// section header
$section = trim(substr($line, 1, -1));
} else {
$eqIndex = strpos($line, '=');
if($eqIndex !== false) {
$key = trim(substr($line, 0, $eqIndex));
$matches = [];
preg_match('/(?<name>\w+)(?<index>\[\w*\])?/', $key, $matches);
if(!array_key_exists('name', $matches)) {
throw new IniParserException("Variable name must not be empty! In file \"$filename\" in line $lineNum.");
}
$keyName = $matches['name'];
if(array_key_exists('index', $matches)) {
$isArray = true;
$arrayIndex = trim($matches['index']);
if(strlen($arrayIndex) == 0) {
$arrayIndex = null;
}
} else {
$isArray = false;
$arrayIndex = null;
}
$value = trim(substr($line, $eqIndex+1));
if($value{0} === '"' && $value{strlen($value)-1} === '"') {
// too lazy to check for multiple closing " let's assume it's fine
$value = str_replace('\\"', '"', substr($value, 1, -1));
} else {
// special value
switch(strtolower($value)) {
case 'yes':
case 'true':
case 'on':
$value = true;
break;
case 'no':
case 'false':
case 'off':
$value = false;
break;
case 'null':
case 'none':
$value = null;
break;
default:
if(is_numeric($value)) {
$value = $value + 0; // make it an int/float
} else {
throw new IniParserException("\"$value\" is not a valid value! In file \"$filename\" in line $lineNum.");
}
}
}
if($section !== null) {
if($isArray) {
if(!array_key_exists($keyName, $ret[$section])) {
$ret[$section][$keyName] = [];
}
if($arrayIndex === null) {
$ret[$section][$keyName][] = $value;
} else {
$ret[$section][$keyName][$arrayIndex] = $value;
}
} else {
$ret[$section][$keyName] = $value;
}
} else {
if($isArray) {
if(!array_key_exists($keyName, $ret)) {
$ret[$keyName] = [];
}
if($arrayIndex === null) {
$ret[$keyName][] = $value;
} else {
$ret[$keyName][$arrayIndex] = $value;
}
} else {
$ret[$keyName] = $value;
}
}
}
}
}
return $ret;
}
What does it differently? Variable names may only consist of alphanumerical characters but other than that no restrictions to them. Strings must be encapsulated with " everything else has to be a special value like no, yes, true, false, on, off, null or none. For mapping see code.
Kind of a hack but you can add backticks around the key names:
[country]
`SE` = Sweden
`NO` = Norway
`FI` = Finland
Then access them like so:
$result = parse_ini_file('test.ini');
echo "{$result['`NO`']}\n";
Output:
$ php test.php
Norway
I was getting this error when there were single quote combinations in the string such as 't or 's. To get rid of the problem, I wrapped the string in double quotes:
Before:
You have selected 'Yes' but you haven't entered the date's flexibility
After:
"You have selected 'Yes' but you haven't entered the date's flexibility"
I ran into the same problem and tried to escape the name in every possible way.
Then I remembered that because of the INI syntax both names and values will be trimmed, so the following workaround MAYBE should do the trick:
NL = Netherlands
; A whitespace before the name
NO = Norway
PL = Poland
And it works ;) As long as your co-workers read the comments (which is not always the case) and don't delete it accidentally. So, yes, the array flipping solution is a safe bet.
From the manual page for parse_ini_file:
There are reserved words which must not be used as keys for ini files. These include: null, yes, no, true, false, on, off, none.
So no, you can't set a variable NO.
I have a script which handles the naming of parent/child elements on another page. The format for the name is like E5-2-3 which represents the third child of the second child of the fifth element.
What I need to do is pass in the parent name to the function and return the name for the next child. This value would be the increment of the last child or 1 if it is the first child.
(I hope this makes some sense to someone)
The index array looks something like this:
1=>null
2=>null
3=>
1=>null
2=>null
3=>
1=>null
4=>null
5=>
1=>null
2=>
1=>null
2=>null
3=>null //the element I was talking about above
6=>
1=>null
7=>null
My Code so far is
$projectNumber = $_GET['project_number'];
#$parentNumber = $_GET['parent_number']; //suppressed as it may not be set
$query = mysql_query("SELECT e_numbers FROM project_management WHERE project_number = '$projectNumber'");
$resultArray = mysql_fetch_assoc($query);
$eNumbers = unserialize($resultArray['e_numbers']);
if (!is_array($eNumbers)&&!isset($parentNumber)){ //first e_number assigned
$eNumbers[1] = null; //cant possibly have children so null for now
$nextENumber = 'E1';
}else{
if (!isset($parentNumber)){
$nextNumber = count($eNumbers)+1;
$eNumbers[$nextNumber] = null; //cant possibly have children so null for now
$nextENumber = 'E'.$nextNumber;
}else{
$parentIndex = explode('-', str_replace('E', '', $parentNumber));
//$nextENumber = //assign $nextENumber the incremented e number
}
}
echo $nextENumber;
//(then goes on to update sql etc etc)
This is all fine but for the line where I need to get/assign deep numbers. I think this should be some kind of recursive function based on the $parentIndex and $eNumbers arrays, however I'm a bit out of my depth when it comes to recursion.
Any pointer in the right direction will be a great help.
PS
If there is a better way to handle incrementing parent/child relationships I'm all ears. The only thing out of my control is the format of the numbers being passed in/out (Has to be EX-Y-Z-...)
UPDATE I was able to develop #ircmaxell 's function to function more better in my context. The function required you to pass in a zero based array(can be empty) and an optional path. It returns the new path and updates the index array to include the new path. An error message is returned if the index is not found.
function getNextPath(&$array, $path) { //thanks to ircmaxell # stackoverflow for the basis of this function
$newPath = '';
$tmp =& $array;
if (is_string($path)) {
$path = explode('-', str_replace('E', '', $path));
$max = count($path);
foreach ($path as $key => $subpath) {
if (is_array($tmp)) {
if (array_key_exists($subpath, $tmp)){
$tmp =& $tmp[$subpath];
$newPath[] = $subpath;
}else{
return "Parent Path Not Found";
}
}
}
}
$tmp[] = null;
$newPath[] = count($tmp)-1;
if (count($newPath)>1){
$newPath = implode('-', $newPath);
}else{
$newPath = $newPath[0];
}
return "E".$newPath;
}
Here's one way:
function incrementPath(&$array, $path) {
if (is_string($path)) {
$path = explode('-', str_replace('E', '', $path);
}
$tmp =& $array;
foreach ($path as $subpath) {
if (is_array($tmp) && isset($tmp[$subpath])) {
$tmp =& $tmp[$subpath];
} else {
return false; // Could not find entire path
}
}
$tmp++;
return true;
}
Now, if you want it to dynamically create paths, just change the return false; to:
$tmp[$subpath] = array();
$tmp =& $tmp[$subpath];
And then add a check after the loop to see if it's not an integer, and explicitly set to 0 if it isn't...
Edit: AHHH, now I understand:
function getNextPath(&$array, $path) {
if (is_string($path)) {
$path = explode('-', str_replace('E', '', $path);
}
$newPath = '';
$tmp =& $array;
$max = count($path) - 1;
foreach ($path as $key => $subpath) {
if (is_array($tmp) && isset($tmp[$subpath])) {
$tmp =& $tmp[$subpath];
if ($key < $max) {
$newPath .= '-'.$subpath;
}
} else {
return 'E' . ltrim($newPath . '-1', '-'); // Could not find entire path
}
}
if (is_array($tmp)) {
return 'E' . ltrim($newPath . '-' . count($tmp), '-');
} else {
//it's a value, so make it an array
$tmp = array();
return 'E' . ltrim($newPath . '-' . 1, '-');
}
}
I think that should do what you want (it returns the next available path under what you're looking for).
}
If I had an array such as:
testarray = array('foo'=>34, 'bar'=>array(1, 2, 3));
How would I go about converting a string such as testarray[bar][0] to find the value its describing?
Well, you can do something like this (Not the prettiest, but far safer than eval)...:
$string = "testarray[bar][0]";
$variableBlock = '[a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff]*';
$regex = '/^('.$variableBlock.')((\[\w+\])*)$/';
if (preg_match($regex, $string, $match)) {
$variableName = $match[1]; // "testarray"
if (!isset($$variableName)) {
//Error, the variable does not exist
return null;
} else {
$array = $$variableName;
if (preg_match_all('/\[(\w+)\]/', $match[2], $matches)) {
foreach ($matches[1] as $match) {
if (!is_array($array)) {
$array = null;
break;
}
$array = isset($array[$match]) ? $array[$match] : null;
}
}
return $array;
}
} else {
//error, not in correct format
}
You could use PHP's eval function.
http://php.net/manual/en/function.eval.php
However, make absolutely sure the input is sanitized!
Cheers
I've got a multidimensional associative array which includes an elements like
$data["status"]
$data["response"]["url"]
$data["entry"]["0"]["text"]
I've got a strings like:
$string = 'data["status"]';
$string = 'data["response"]["url"]';
$string = 'data["entry"]["0"]["text"]';
How can I convert the strings into a variable to access the proper array element? This method will need to work across any array at any of the dimensions.
PHP's variable variables will help you out here. You can use them by prefixing the variable with another dollar sign:
$foo = "Hello, world!";
$bar = "foo";
echo $$bar; // outputs "Hello, world!"
Quick and dirty:
echo eval('return $'. $string . ';');
Of course the input string would need to be be sanitized first.
If you don't like quick and dirty... then this will work too and it doesn't require eval which makes even me cringe.
It does, however, make assumptions about the string format:
<?php
$data['response'] = array(
'url' => 'http://www.testing.com'
);
function extract_data($string) {
global $data;
$found_matches = preg_match_all('/\[\"([a-z]+)\"\]/', $string, $matches);
if (!$found_matches) {
return null;
}
$current_data = $data;
foreach ($matches[1] as $name) {
if (key_exists($name, $current_data)) {
$current_data = $current_data[$name];
} else {
return null;
}
}
return $current_data;
}
echo extract_data('data["response"]["url"]');
?>
This can be done in a much simpler way. All you have to do is think about what function PHP provides that creates variables.
$string = 'myvariable';
extract(array($string => $string));
echo $myvariable;
done!
You can also use curly braces (complex variable notation) to do some tricks:
$h = 'Happy';
$n = 'New';
$y = 'Year';
$wish = ${$h.$n.$y};
echo $wish;
Found this on the Variable variables page:
function VariableArray($data, $string) {
preg_match_all('/\[([^\]]*)\]/', $string, $arr_matches, PREG_PATTERN_ORDER);
$return = $arr;
foreach($arr_matches[1] as $dimension) { $return = $return[$dimension]; }
return $return;
}
I was struggling with that as well,
I had this :
$user = array('a'=>'alber', 'b'=>'brad'...);
$array_name = 'user';
and I was wondering how to get into albert.
at first I tried
$value_for_a = $$array_name['a']; // this dosen't work
then
eval('return $'.$array_name['a'].';'); // this dosen't work, maybe the hoster block eval which is very common
then finally I tried the stupid thing:
$array_temp=$$array_name;
$value_for_a = $array_temp['a'];
and this just worked Perfect!
wisdom, do it simple do it stupid.
I hope this answers your question
You would access them like:
print $$string;
You can pass by reference with the operator &. So in your example you'll have something like this
$string = &$data["status"];
$string = &$data["response"]["url"];
$string = &$data["entry"]["0"]["text"];
Otherwise you need to do something like this:
$titular = array();
for ($r = 1; $r < $rooms + 1; $r ++)
{
$title = "titular_title_$r";
$firstName = "titular_firstName_$r";
$lastName = "titular_lastName_$r";
$phone = "titular_phone_$r";
$email = "titular_email_$r";
$bedType = "bedType_$r";
$smoker = "smoker_$r";
$titular[] = array(
"title" => $$title,
"first_name" => $$firstName,
"last_name" => $$lastName,
"phone" => $$phone,
"email" => $$email,
"bedType" => $$bedType,
"smoker" => $$smoker
);
}
There are native PHP function for this:
use http://php.net/manual/ru/function.parse-str.php (parse_str()).
don't forget to clean up the string from '"' before parsing.
Perhaps this option is also suitable:
$data["entry"]["0"]["text"];
$string = 'data["entry"]["0"]["text"]';
function getIn($arr, $params)
{
if(!is_array($arr)) {
return null;
}
if (array_key_exists($params[0], $arr) && count($params) > 1) {
$bf = $params[0];
array_shift($params);
return getIn($arr[$bf], $params);
} elseif (array_key_exists($params[0], $arr) && count($params) == 1) {
return $arr[$params[0]];
} else {
return null;
}
}
preg_match_all('/(?:(\w{1,}|\d))/', $string, $arr_matches, PREG_PATTERN_ORDER);
array_shift($arr_matches[0]);
print_r(getIn($data, $arr_matches[0]));
P.s. it's work for me.