echo a php syntax from a database php/codeigniter [duplicate] - php

I have string like this in database (the actual string contains 100s of word and 10s of variable):
I am a {$club} fan
I echo this string like this:
$club = "Barcelona";
echo $data_base[0]['body'];
My output is I am a {$club} fan. I want I am a Barcelona fan. How can I do this?

Use strtr. It will translate parts of a string.
$club = "Barcelona";
echo strtr($data_base[0]['body'], array('{$club}' => $club));
For multiple values (demo):
$data_base[0]['body'] = 'I am a {$club} fan.'; // Tests
$vars = array(
'{$club}' => 'Barcelona',
'{$tag}' => 'sometext',
'{$anothertag}' => 'someothertext'
);
echo strtr($data_base[0]['body'], $vars);
Program Output:
I am a Barcelona fan.

I would suggest the sprintf() function.
Instead of storing I am a {$club} fan, use I am a %s fan, so your echo command would go like:
$club = "Barcelona";
echo sprintf($data_base[0]['body'],$club);
Output: I am a Barcelona fan
That would give you the freedom of use that same code with any other variable (and you don't even have to remember the variable name).
So this code is also valid with the same string:
$food = "French fries";
echo sprintf($data_base[0]['body'], $food);
Output: I am a French fries fan
$language = "PHP";
echo sprintf($data_base[0]['body'], $language);
Output: I am a PHP fan

/**
* A function to fill the template with variables, returns filled template.
*
* #param string $template A template with variables placeholders {$variable}.
* #param array $variables A key => value store of variable names and values.
*
* #return string
*/
public function replaceVariablesInTemplate($template, array $variables){
return preg_replace_callback('#{(.*?)}#',
function($match) use ($variables){
$match[1] = trim($match[1], '$');
return $variables[$match[1]];
},
' ' . $template . ' ');
}

Edit: This answer still gets upvotes, so people need to be aware that there's a security vulnerability in the naive interpolation technique present in the below code snippets. An adversary could include arbitrary variables in the input string which would reveal information about the server or other data in the runtime variable register. This is due to the way the general expression search is performed in that it finds any arbitrary variable name pattern, and then uses those variable names verbatim in the subsequent compact call. This causes clients to control server-side behavior similar to eval. I'm leaving this answer for posterity.
You are looking for nested string interpolation. A theory can be read in the blog post Wanted: PHP core function for dynamically performing double-quoted string variable interpolation.
The major problem is that you don't really know all of the variables available, or there may be too many to list.
Consider the following tested code snippet. I stole the regex from Mohammad Mohsenipur.
$testA = '123';
$testB = '456';
$testC = '789';
$t = '{$testA} adsf {$testB}adf 32{$testC} fddd{$testA}';
echo 'before: ' . $t . "\n";
preg_match_all('~\{\$(.*?)\}~si', $t, $matches);
if ( isset($matches[1])) {
$r = compact($matches[1]);
foreach ( $r as $var => $value ) {
$t = str_replace('{$' . $var . '}', $value, $t);
}
}
echo 'after: ' . $t . "\n";
Your code may be:
$club = 'Barcelona';
$tmp = $data_base[0]['body'];
preg_match_all('~\{\$(.*?)\}~si', $tmp, $matches);
if ( isset($matches[1])) {
$r = compact($matches[1]);
foreach ( $r as $var => $value ) {
$tmp = str_replace('{$' . $var . '}', $value, $tmp);
}
}
echo $tmp;

if (preg_match_all('#\$([a-zA-Z0-9]+)#', $q, $matches, PREG_SET_ORDER));
{
foreach ($matches as $m)
{
eval('$q = str_replace(\'' . $m[0] . '\', $' . $m[1] . ', $q);');
}
}
This matches all $variables and replaces them with the value.
I didn't include the {}'s, but it shouldn't be too hard to add them something like this...
if (preg_match_all('#\{\$([a-zA-Z0-9]+)\}#', $q, $matches, PREG_SET_ORDER));
{
foreach ($matches as $m)
{
eval('$q = str_replace(\'' . $m[0] . '\', $' . $m[1] . ', $q);');
}
}
Though it seems a bit slower than hard coding each variable. And it introduces a security hole with eval. That is why my regular expression is so limited. To limit the scope of what eval can grab.
I wrote my own regular expression tester with Ajax, so I could see, as I type, if my expression is going to work. I have variables I like to use in my expressions so that I don't need to retype the same bit for each expression.

I've found these approaches useful at times:
$name = 'Groot';
$string = 'I am {$name}';
echo eval('return "' . $string . '";');
$data = array('name' => 'Groot');
$string = 'I am {$data[name]}';
echo eval('return "' . $string . '";');
$name = 'Groot';
$data = (object)get_defined_vars();
$string = 'I am {$data->name}';
echo eval('return "' . $string . '";');

Here is my solution:
$club = "Barcelona";
$string = 'I am a {$club} fan';
preg_match_all("/\{\\$([a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff]*)\}/", $string, $matches);
foreach ($matches[0] as $key => $var_name) {
if (!isset($GLOBALS[$matches[1][$key]]))
$GLOBALS[$matches[1][$key]] = 'default value';
$string = str_replace($var_name, $GLOBALS[$matches[1][$key]], $string);
}

You can use a simple parser that replaces {$key} with a value from a map if it exists.
Use it like:
$text = templateWith('hello $item}', array('item' => 'world'...));`
My first version is:
/**
* Template with a string and simple map.
* #param string $template
* #param array $substitutions map of substitutions.
* #return string with substitutions applied.
*/
function templateWith(string $template, array $substitutions) {
$state = 0; // forwarding
$charIn = preg_split('//u', $template, -1, PREG_SPLIT_NO_EMPTY);
$charOut = array();
$count = count($charIn);
$key = array();
$i = 0;
while ($i < $count) {
$char = $charIn[$i];
switch ($char) {
case '{':
if ($state === 0) {
$state = 1;
}
break;
case '}':
if ($state === 2) {
$ks = join('', $key);
if (array_key_exists($ks, $substitutions)) {
$charOut[] = $substitutions[$ks];
}
$key = array();
$state = 0;
}
break;
case '$': if ($state === 1) {
$state = 2;
}
break;
case '\\': if ($state === 0) {
$i++;
$charOut[] = $charIn[$i];
}
continue;
default:
switch ($state) {
default:
case 0: $charOut[] = $char;
break;
case 2: $key[] = $char;
break;
}
}
$i++;
}
return join('', $charOut);
}

Maybe the following snippet is (partly) usefull for someone.
/**
* Access an object property using "dot" notation
*
* #param object $object
* #param string|null $path
* #param mixed $default
* #return mixed
*/
function xobject_get(object $object, $path, $default = null) {
return array_reduce(explode('.', $path), function ($o, $p) use ($default) {
return is_numeric($p) ? $o[$p] ?? $default : $o->$p ?? $default;
}, $object);
}
/**
* Access an array's property using "dot" notation
*
* #param array $array
* #param string|null $path
* #param mixed $default
* #return mixed
*/
function xarray_get(array $array, $path, $default = null) {
return array_reduce(explode('.', $path), function ($a, $p) use ($default) {
return $a[$p] ?? $default;
}, $array);
}
/**
* Replaces placeholders from a string with object or array values using "dot" notation
*
* Example:
* "The book {title} was written by {author.name}" becomes "The book Harry Potter was written by J.K. Rowling"
*
* #param array|object $data
* #param string $template
* #return string
*/
function render_template($data, string $template) {
preg_match_all("/\{([^\}]*)\}/", $template, $matches);
$replace = [];
foreach ($matches[1] as $param) {
$replace['{'.$param.'}'] = is_object($data) ? xobject_get($data, $param) : xarray_get($data, $param);
}
return strtr($template, $replace);
}

Try the preg_replace PHP function.
<?php
$club = "Barcelona";
echo $string = preg_replace('#\{.*?\}#si', $club, 'I am a {$club} fan');
?>

You can use preg_replace_callback for getting a variable name like:
$data_base[0]['body'] = preg_replace_callback(
'#{(.*?)}#',
function($m) {
$m[1] = trim($m[1], '$');
return $this->$m[1];
},
' ' . $data_base[0]['body'] . ' '
);
Attention: This code I wrote is for class($this);. You can declare a variable into the class. Then use this code for detecting the variables and replace them like:
<?php
class a {
function __construct($array) {
foreach($array as $key => $val) {
$this->$key = $val;
}
}
function replace($str){
return preg_replace_callback(
'#{(.*?)}#', function($m) {$m[1] = trim($m[1], '$'); return $this->$m[1];},
' ' . $str . ' ');
}
}
$obj = new a(array('club' => 3523));
echo $obj->replace('I am a {$club} fan');
Output:
I am a 3523 fan

For your case, honestly, I do not see a reason not to use eval :)
Here is some extra way to define your variables if they are too into your database:
$my_variable_name = 'club'; //coming from database
$my_value = 'Barcelona'; //coming from database
$my_msg= 'I am a {$club} fan'; //coming from database
$$my_variable_name = $my_value; // creating variable $club dinamically
$my_msg = eval("return \"$my_msg\";"); // eating the forbidden fruit
echo $my_msg; // prints 'I am Barcelona fan'
This code is fully tested and working with php 7.
But if you allow your users to define such strings into your database, better don't do it.
You should run eval only with trusted data.

Something like this should solve your problem:
$club = "Barcelona";
$var = 'I am a {$club} fan';
$res = preg_replace('/\{\$([a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff]*)\}/e', "$$1", $var);
echo "$res\n";
It's a one-line preg_replace.
With PHP 5.5, /e modifier is deprecated. You can use a callback instead:
$club = "Barcelona";
$var = 'I am a {$club} fan';
$res = preg_replace_callback('/\{\$([a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff]*)\}/',
create_function(
'$matches',
'extract($GLOBALS, EXTR_REFS | EXTR_SKIP); return $$matches[1];'),
$var);
echo "$res\n";
Note that this uses a hack of importing all global variables. This may not be exactly what you want. Possibly using closures would be a better idea.

Related

How to define variables in a sql row to be used with php? [duplicate]

I have string like this in database (the actual string contains 100s of word and 10s of variable):
I am a {$club} fan
I echo this string like this:
$club = "Barcelona";
echo $data_base[0]['body'];
My output is I am a {$club} fan. I want I am a Barcelona fan. How can I do this?
Use strtr. It will translate parts of a string.
$club = "Barcelona";
echo strtr($data_base[0]['body'], array('{$club}' => $club));
For multiple values (demo):
$data_base[0]['body'] = 'I am a {$club} fan.'; // Tests
$vars = array(
'{$club}' => 'Barcelona',
'{$tag}' => 'sometext',
'{$anothertag}' => 'someothertext'
);
echo strtr($data_base[0]['body'], $vars);
Program Output:
I am a Barcelona fan.
I would suggest the sprintf() function.
Instead of storing I am a {$club} fan, use I am a %s fan, so your echo command would go like:
$club = "Barcelona";
echo sprintf($data_base[0]['body'],$club);
Output: I am a Barcelona fan
That would give you the freedom of use that same code with any other variable (and you don't even have to remember the variable name).
So this code is also valid with the same string:
$food = "French fries";
echo sprintf($data_base[0]['body'], $food);
Output: I am a French fries fan
$language = "PHP";
echo sprintf($data_base[0]['body'], $language);
Output: I am a PHP fan
/**
* A function to fill the template with variables, returns filled template.
*
* #param string $template A template with variables placeholders {$variable}.
* #param array $variables A key => value store of variable names and values.
*
* #return string
*/
public function replaceVariablesInTemplate($template, array $variables){
return preg_replace_callback('#{(.*?)}#',
function($match) use ($variables){
$match[1] = trim($match[1], '$');
return $variables[$match[1]];
},
' ' . $template . ' ');
}
Edit: This answer still gets upvotes, so people need to be aware that there's a security vulnerability in the naive interpolation technique present in the below code snippets. An adversary could include arbitrary variables in the input string which would reveal information about the server or other data in the runtime variable register. This is due to the way the general expression search is performed in that it finds any arbitrary variable name pattern, and then uses those variable names verbatim in the subsequent compact call. This causes clients to control server-side behavior similar to eval. I'm leaving this answer for posterity.
You are looking for nested string interpolation. A theory can be read in the blog post Wanted: PHP core function for dynamically performing double-quoted string variable interpolation.
The major problem is that you don't really know all of the variables available, or there may be too many to list.
Consider the following tested code snippet. I stole the regex from Mohammad Mohsenipur.
$testA = '123';
$testB = '456';
$testC = '789';
$t = '{$testA} adsf {$testB}adf 32{$testC} fddd{$testA}';
echo 'before: ' . $t . "\n";
preg_match_all('~\{\$(.*?)\}~si', $t, $matches);
if ( isset($matches[1])) {
$r = compact($matches[1]);
foreach ( $r as $var => $value ) {
$t = str_replace('{$' . $var . '}', $value, $t);
}
}
echo 'after: ' . $t . "\n";
Your code may be:
$club = 'Barcelona';
$tmp = $data_base[0]['body'];
preg_match_all('~\{\$(.*?)\}~si', $tmp, $matches);
if ( isset($matches[1])) {
$r = compact($matches[1]);
foreach ( $r as $var => $value ) {
$tmp = str_replace('{$' . $var . '}', $value, $tmp);
}
}
echo $tmp;
if (preg_match_all('#\$([a-zA-Z0-9]+)#', $q, $matches, PREG_SET_ORDER));
{
foreach ($matches as $m)
{
eval('$q = str_replace(\'' . $m[0] . '\', $' . $m[1] . ', $q);');
}
}
This matches all $variables and replaces them with the value.
I didn't include the {}'s, but it shouldn't be too hard to add them something like this...
if (preg_match_all('#\{\$([a-zA-Z0-9]+)\}#', $q, $matches, PREG_SET_ORDER));
{
foreach ($matches as $m)
{
eval('$q = str_replace(\'' . $m[0] . '\', $' . $m[1] . ', $q);');
}
}
Though it seems a bit slower than hard coding each variable. And it introduces a security hole with eval. That is why my regular expression is so limited. To limit the scope of what eval can grab.
I wrote my own regular expression tester with Ajax, so I could see, as I type, if my expression is going to work. I have variables I like to use in my expressions so that I don't need to retype the same bit for each expression.
I've found these approaches useful at times:
$name = 'Groot';
$string = 'I am {$name}';
echo eval('return "' . $string . '";');
$data = array('name' => 'Groot');
$string = 'I am {$data[name]}';
echo eval('return "' . $string . '";');
$name = 'Groot';
$data = (object)get_defined_vars();
$string = 'I am {$data->name}';
echo eval('return "' . $string . '";');
Here is my solution:
$club = "Barcelona";
$string = 'I am a {$club} fan';
preg_match_all("/\{\\$([a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff]*)\}/", $string, $matches);
foreach ($matches[0] as $key => $var_name) {
if (!isset($GLOBALS[$matches[1][$key]]))
$GLOBALS[$matches[1][$key]] = 'default value';
$string = str_replace($var_name, $GLOBALS[$matches[1][$key]], $string);
}
You can use a simple parser that replaces {$key} with a value from a map if it exists.
Use it like:
$text = templateWith('hello $item}', array('item' => 'world'...));`
My first version is:
/**
* Template with a string and simple map.
* #param string $template
* #param array $substitutions map of substitutions.
* #return string with substitutions applied.
*/
function templateWith(string $template, array $substitutions) {
$state = 0; // forwarding
$charIn = preg_split('//u', $template, -1, PREG_SPLIT_NO_EMPTY);
$charOut = array();
$count = count($charIn);
$key = array();
$i = 0;
while ($i < $count) {
$char = $charIn[$i];
switch ($char) {
case '{':
if ($state === 0) {
$state = 1;
}
break;
case '}':
if ($state === 2) {
$ks = join('', $key);
if (array_key_exists($ks, $substitutions)) {
$charOut[] = $substitutions[$ks];
}
$key = array();
$state = 0;
}
break;
case '$': if ($state === 1) {
$state = 2;
}
break;
case '\\': if ($state === 0) {
$i++;
$charOut[] = $charIn[$i];
}
continue;
default:
switch ($state) {
default:
case 0: $charOut[] = $char;
break;
case 2: $key[] = $char;
break;
}
}
$i++;
}
return join('', $charOut);
}
Maybe the following snippet is (partly) usefull for someone.
/**
* Access an object property using "dot" notation
*
* #param object $object
* #param string|null $path
* #param mixed $default
* #return mixed
*/
function xobject_get(object $object, $path, $default = null) {
return array_reduce(explode('.', $path), function ($o, $p) use ($default) {
return is_numeric($p) ? $o[$p] ?? $default : $o->$p ?? $default;
}, $object);
}
/**
* Access an array's property using "dot" notation
*
* #param array $array
* #param string|null $path
* #param mixed $default
* #return mixed
*/
function xarray_get(array $array, $path, $default = null) {
return array_reduce(explode('.', $path), function ($a, $p) use ($default) {
return $a[$p] ?? $default;
}, $array);
}
/**
* Replaces placeholders from a string with object or array values using "dot" notation
*
* Example:
* "The book {title} was written by {author.name}" becomes "The book Harry Potter was written by J.K. Rowling"
*
* #param array|object $data
* #param string $template
* #return string
*/
function render_template($data, string $template) {
preg_match_all("/\{([^\}]*)\}/", $template, $matches);
$replace = [];
foreach ($matches[1] as $param) {
$replace['{'.$param.'}'] = is_object($data) ? xobject_get($data, $param) : xarray_get($data, $param);
}
return strtr($template, $replace);
}
Try the preg_replace PHP function.
<?php
$club = "Barcelona";
echo $string = preg_replace('#\{.*?\}#si', $club, 'I am a {$club} fan');
?>
You can use preg_replace_callback for getting a variable name like:
$data_base[0]['body'] = preg_replace_callback(
'#{(.*?)}#',
function($m) {
$m[1] = trim($m[1], '$');
return $this->$m[1];
},
' ' . $data_base[0]['body'] . ' '
);
Attention: This code I wrote is for class($this);. You can declare a variable into the class. Then use this code for detecting the variables and replace them like:
<?php
class a {
function __construct($array) {
foreach($array as $key => $val) {
$this->$key = $val;
}
}
function replace($str){
return preg_replace_callback(
'#{(.*?)}#', function($m) {$m[1] = trim($m[1], '$'); return $this->$m[1];},
' ' . $str . ' ');
}
}
$obj = new a(array('club' => 3523));
echo $obj->replace('I am a {$club} fan');
Output:
I am a 3523 fan
For your case, honestly, I do not see a reason not to use eval :)
Here is some extra way to define your variables if they are too into your database:
$my_variable_name = 'club'; //coming from database
$my_value = 'Barcelona'; //coming from database
$my_msg= 'I am a {$club} fan'; //coming from database
$$my_variable_name = $my_value; // creating variable $club dinamically
$my_msg = eval("return \"$my_msg\";"); // eating the forbidden fruit
echo $my_msg; // prints 'I am Barcelona fan'
This code is fully tested and working with php 7.
But if you allow your users to define such strings into your database, better don't do it.
You should run eval only with trusted data.
Something like this should solve your problem:
$club = "Barcelona";
$var = 'I am a {$club} fan';
$res = preg_replace('/\{\$([a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff]*)\}/e', "$$1", $var);
echo "$res\n";
It's a one-line preg_replace.
With PHP 5.5, /e modifier is deprecated. You can use a callback instead:
$club = "Barcelona";
$var = 'I am a {$club} fan';
$res = preg_replace_callback('/\{\$([a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff]*)\}/',
create_function(
'$matches',
'extract($GLOBALS, EXTR_REFS | EXTR_SKIP); return $$matches[1];'),
$var);
echo "$res\n";
Note that this uses a hack of importing all global variables. This may not be exactly what you want. Possibly using closures would be a better idea.

PHP Better way to Replace/Match $1

I am trying to replace $1, $2, $3 variables in a URL with another URL.
You can copy paste my example below and see my solution.
But I feel like there is a more elegant way with an array mapping type function or a better preg_replace type of thing. I just need a kick in the right direction, can you help?
<?php
/**
* Key = The DESIRED string
* Value = The ORIGINAL value
*
* Desired Result: project/EXAMPLE/something/OTHER
*/
$data = array(
'project/$1/details/$2' => 'newby/EXAMPLE/something/OTHER'
);
foreach($data as $desiredString => $findMe)
{
/**
* Turn these URI's into arrays
*/
$desiredString = explode('/', $desiredString);
$findMe = explode('/', $findMe);
/**
* Store the array position of the match
*/
$positions = array();
foreach($desiredString as $key => $value) {
/**
* Look for $1, $2, $3, etc..
*/
if (preg_match('#(\$\d)#', $value)) {
$positions[$key] = $value;
}
}
/**
* Loop through the positions
*/
foreach($positions as $key => $value){
$desiredString[$key] = $findMe[$key];
}
/**
* The final result
*/
echo implode('/', $desiredString);
}
Sometimes you are out of luck and the functions you need to solve a problem directly just aren't there. This happens with every language regardless of how many libraries and builtins it has.
We're going to have to write some code. We also need to solve a particular problem. Ultimately, we want our solution to the problem to be just as clean as if we had the ideal functions given to us in the first place. Therefore, whatever code we write, we want most of it to be out of the way, which probably means we want most of the code in a separate function or class. But we don't just want to just throw around arbitrary code because all of our functions and classes should be reusable.
My approach then is to extract a useful general pattern out of the solution, write that as a function, and then rewrite the original solution using that function (which will simplify it). To find that general pattern I made the problem bigger so it might be applicable to more situations.
I ended up making the function array array_multi_walk(callback $callback [, array $array1 [, array $array2 ... ]]). This function walks over each array simultaneously and uses $callback to select which element to keep.
This is what the solution looks like using this function.
$chooser = function($a, $b) {
return strlen($a) >= 2 && $a[0] == '$' && ctype_digit($a[1])
? $b : $a;
};
$data = array(
'project/$1/details/$2' => 'newby/EXAMPLE/something/OTHER'
);
$explodeSlashes = function($a) { return explode('/', $a); };
$find = array_map($explodeSlashes, array_keys($data));
$replace = array_map($explodeSlashes, array_values($data));
$solution = array_multi_walk(
function($f, $r) use ($chooser) {
return array_multi_walk($chooser, $f, $r);
},
$find, $replace);
And, as desired, array_multi_walk can be used for other problems. For example, this sums all elements.
$sum = function() {
return array_sum(func_get_args());
};
var_dump(array_multi_walk($sum, array(1,2,3), array(1,2,3), array(10)));
// prints the array (12, 4, 6)
You might want to make some tweaks to array_multi_walk. For example, it might be better if the callback takes the elements by array, rather than separate arguments. Maybe there should be option flags to stop when any array runs out of elements, instead of filling nulls.
Here is the implementation of array_multi_walk that I came up with.
function array_multi_walk($callback)
{
$arrays = array_slice(func_get_args(), 1);
$numArrays = count($arrays);
if (count($arrays) == 0) return array();
$result = array();
for ($i = 0; ; ++$i) {
$elementsAti = array();
$allNull = true;
for ($j = 0; $j < $numArrays; ++$j) {
$element = array_key_exists($i, $arrays[$j]) ? $arrays[$j][$i] : null;
$elementsAti[] = $element;
$allNull = $allNull && $element === null;
}
if ($allNull) break;
$result[] = call_user_func_array($callback, $elementsAti);
}
return $result;
}
So at the end of the day, we had to write some code, but not only is the solution to the original problem slick, we also gained a generic, reusable piece of code to help us out later.
Why there should not be $2,$4 but $1,$2 ?if you can change your array then it can be solved in 3 or 4 lines codes.
$data = array(
'project/$2/details/$4' => 'newby/EXAMPLE/something/OTHER'
);
foreach($data as $desiredString => $findMe)
{
$regexp = "#(".implode(')/(',explode('/',$findMe)).")#i";
echo preg_replace($regexp,$desiredString,$findMe);
}
I've shortened your code by removing comments for better readability. I'm using array_map and the mapping function decides what value to return:
<?php
function replaceDollarSigns($desired, $replace)
{
return preg_match('#(\$\d)#', $desired) ? $replace : $desired;
}
$data = array(
'project/$1/details/$2' => 'newby/EXAMPLE/something/OTHER',
);
foreach($data as $desiredString => $findMe)
{
$desiredString = explode('/', $desiredString);
$findMe = explode('/', $findMe);
var_dump(implode('/', array_map('replaceDollarSigns', $desiredString, $findMe)));
}
?>
Working example: http://ideone.com/qVLmn
You can also omit the function by using create_function:
<?php
$data = array(
'project/$1/details/$2' => 'newby/EXAMPLE/something/OTHER',
);
foreach($data as $desiredString => $findMe)
{
$desiredString = explode('/', $desiredString);
$findMe = explode('/', $findMe);
$result = array_map(
create_function(
'$desired, $replace',
'return preg_match(\'#(\$\d)#\', $desired) ? $replace : $desired;'
),
$desiredString,
$findMe);
var_dump(implode('/', $result));
}
?>
Working example: http://ideone.com/OC0Ak
Just saying, why don't use an array pattern/replacement in preg_replace? Something like this:
<?php
/**
* Key = The DESIRED string
* Value = The ORIGINAL value
*
* Desired Result: project/EXAMPLE/something/OTHER
*/
$data = array(
'project/$1/details/$2' => 'newby/EXAMPLE/details/OTHER'
);
$string = 'project/$1/details/$2';
$pattern[0] = '/\$1/';
$pattern[1] = '/\$2/';
$replacement[0] = 'EXAMPLE';
$replacement[1] = 'OTHER';
$result = preg_replace($pattern, $replacement, $string);
echo $result;
I think that it's much easier than what you're looking for. You can see that it works here: http://codepad.org/rCslRmgs
Perhaps there's some reason to keep the array key => value to accomplish the replace?

Replace all substring instances with a variable string

If you had the string
'Old string Old more string Old some more string'
and you wanted to get
'New1 string New2 more string New3 some more string'
how would you do it?
In other words, you need to replace all instances of 'Old' with variable string 'New'.$i. How can it be done?
An iterative solution that doesn't need regular expressions:
$str = 'Old string Old more string Old some more string';
$old = 'Old';
$new = 'New';
$i = 1;
$tmpOldStrLength = strlen($old);
while (($offset = strpos($str, $old, $offset)) !== false) {
$str = substr_replace($str, $new . ($i++), $offset, $tmpOldStrLength);
}
$offset in strpos() is just a little bit micro-optimization. I don't know, if it's worth it (in fact I don't even know, if it changes anything), but the idea is that we don't need to search for $old in the substring that is already processed.
See Demo
Old string Old more string Old some more string
New1 string New2 more string New3 some more string
Use preg_replace_callback.
$count = 0;
$str = preg_replace_callback(
'~Old~',
create_function('$matches', 'return "New".$count++;'),
$str
);
From the PHP manual on str_replace:
Replace all occurrences of the search string with the replacement string
mixed str_replace ( mixed $search , mixed $replace , mixed $subject [, int &$count ] )
search
The value being searched for, otherwise known as the needle. An array may be used to designate multiple needles.
replace
The replacement value that replaces found search values. An array may be used to designate multiple replacements.
subject
The string or array being searched and replaced on, otherwise known as the haystack.
If subject is an array, then the search and replace is performed with every entry of subject, and the return value is an array as well.
count
If passed, this will be set to the number of replacements performed.
Use:
$str = 'Old string Old more string Old some more string';
$i = 1;
while (preg_match('/Old/', $str)) {
$str = preg_replace('/Old/', 'New'.$i++, $str, 1);
}
echo $str,"\n";
Output:
New1 string New2 more string New3 some more string
I had some similar solution like KingCrunch's, but as he already answered it, I was wondering about a str_replace variant with a callback for replacements and came up with this (Demo):
$subject = array('OldOldOld', 'Old string Old more string Old some more string');
$search = array('Old', 'string');
$replace = array(
function($found, $count) {return 'New'.$count;},
function($found, $count) {static $c=0; return 'String'.(++$c);}
);
$replace = array();
print_r(str_ureplace($search, $replace, $subject));
/**
* str_ureplace
*
* str_replace like function with callback
*
* #param string|array search
* #param callback|array $replace
* #param string|array $subject
* #param int $replace_count
* #return string|array subject with replaces, FALSE on error.
*/
function str_ureplace($search, $replace, $subject, &$replace_count = null) {
$replace_count = 0;
// Validate input
$search = array_values((array) $search);
$searchCount = count($search);
if (!$searchCount) {
return $subject;
}
foreach($search as &$v) {
$v = (string) $v;
}
unset($v);
$replaceSingle = is_callable($replace);
$replace = $replaceSingle ? array($replace) : array_values((array) $replace);
foreach($replace as $index=>$callback) {
if (!is_callable($callback)) {
throw new Exception(sprintf('Unable to use %s (#%d) as a callback', gettype($callback), $index));
}
}
// Search and replace
$subjectIsString = is_string($subject);
$subject = (array) $subject;
foreach($subject as &$haystack) {
if (!is_string($haystack)) continue;
foreach($search as $key => $needle) {
if (!$len = strlen($needle))
continue;
$replaceSingle && $key = 0;
$pos = 0;
while(false !== $pos = strpos($haystack, $needle, $pos)) {
$replaceWith = isset($replace[$key]) ? call_user_func($replace[$key], $needle, ++$replace_count) : '';
$haystack = substr_replace($haystack, $replaceWith, $pos, $len);
}
}
}
unset($haystack);
return $subjectIsString ? reset($subject) : $subject;
}

PHP - Extremely light templating system

does anyone know a php templating system that is very simple, something like almost as simple as str_replace("{variable}", $variable); ?
I need this for a series of textareas in the administration panel, where the site admin should change templates for various elements of the website (not complex stuff like pages etc, just blocks of content)
/**
* Renders a single line. Looks for {{ var }}
*
* #param string $string
* #param array $parameters
*
* #return string
*/
function renderString($string, array $parameters)
{
$replacer = function ($match) use ($parameters)
{
return isset($parameters[$match[1]]) ? $parameters[$match[1]] : $match[0];
};
return preg_replace_callback('/{{\s*(.+?)\s*}}/', $replacer, $string);
}
$findReplaces = array(
'first_name' => $user['first_name'],
'greeting' => 'Good ' . (date('G') < 12 ) ? 'morning' : 'afternoon'
);
$finds = $replaces = array();
foreach($findReplaces as $find => $replace) {
$finds[] = '{' . $find . '}';
$replaces[] = $replace;
}
$content = str_replace($finds, $replaces, $content);

Convert a String to Variable

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.

Categories