Req #43901 [Opn->Wfx]: PHP needs new function to expand strings
| From: | ajf@php.net | Date: | Fri, 09 Jan 2015 01:07:36 +0000 |
| Subject: | Req #43901 [Opn->Wfx]: PHP needs new function to expand strings | ||
| References: | 1 | Groups: | php.bugs |
| Request: | Send a blank email to php-bugs+get-189813@lists.php.net to get a copy of this message | ||
Edit report at https://bugs.php.net/bug.php?id=43901&edit=1
ID: 43901
Updated by: ajf@php.net
Reported by: t03 at springtimesoftware dot com
Summary: PHP needs new function to expand strings
-Status: Open
+Status: Wont fix
Type: Feature/Change Request
Package: Strings related
Operating System: *
PHP Version: 5.2.5
Block user comment: N
Private report: N
New Comment:
The "Zend mechanism for this that is already there" is, well, eval(). It's a feature
of the lexer parsing source code, there's no magical internal function we could easily expose.
Also, you can call functions within string escapes, so this is just as dangerous as eval() anyway.
If you really want something like this, do it yourself with preg_match and some variable variables
($$).
Previous Comments:
------------------------------------------------------------------------
[2008-12-03 07:19:28] cvolny at gmail dot com
I wrote two functions to display ways of accomplishing this already (although a built-in function
would be nice).
This function is very restrictive and requires you to pass a hash (name=>value) as $vars. I
prefer and use this function to build page layout with predefined variables to be placed in a
template file (I put stuff like <div id="content">$content</div> where a
page's specific content should go). I consider this a safer way to string expand as you are
explicitly limiting what can be expanded. Some improvements can be done to it to handle arrays, but
I haven't had a need for it yet.
function stringExpand($subject, array $vars) {
// loop over $vars map
foreach ($vars as $name => $value) {
// use preg_replace to match ${
$name} or $$name
$subject = preg_replace(sprintf('/\$\{?%s\}?/', $name), $value, $subject);
}
// return variable expanded string
return $subject;
}
This second function accomplishes the same task only using eval() and variables in the current
symbol table (with the help of extract()). I opted to use heredoc with optionally a randomly
generated delimiter. This allows access to all variables available to the function (static members,
globals, $vars, etc) so it could potentially allow access to preferably private data. I won't
even go into the security implications of using eval() to accomplish this, it's probably better
to use something like the above. here it is:
function stringExpandDangerous($subject, array $vars = array(), $random = true) {
// extract $vars into current symbol table
extract($vars);
$delim;
// if requested to be random (default), generate delim, otherwise use predefined (trivially faster)
if ($random)
$delim = '___' . chr(mt_rand(65,90)) . chr(mt_rand(65,90)) . chr(mt_rand(65,90)) .
chr(mt_rand(65,90)) . chr(mt_rand(65,90)) . '___';
else
$delim = '__ASDFZXCV1324ZXCV__'; // button mashing...
// built the eval code
$statement = "return <<<$delim\n\n" . $subject . "\n$delim;\n";
// execute statement, saving output to $result variable
$result = eval($statement);
// if eval() returned FALSE, throw a custom exception
if ($result === false)
throw new EvalException($statement);
// return variable expanded string
return $result;
}
As you can see you can easily (and dangerously) accomplish this task using eval() or you can
cautiously accomplish it using a variant of regex. I would recommend limiting the access of your
string expansion script as well as avoiding eval(), you can capture variable names & values
easily using compact(). I wouldnt allow your script access to $GLOBALS like the above comment,
you might not want that data as accessible as youre making it.
------------------------------------------------------------------------
[2008-01-24 20:02:40] t03 at springtimesoftware dot com
In case anyone else reads this and needs a workaround, here is function to expand any embedded
variables of the form "$name" found inside a given string. Note: this uses the global
scope, even if called from inside a function.
// Expand global variables if found in a string
// ExpandVars ver=1/24/08
function ReplaceVarCallback($M)
{
if (!isset($GLOBALS[$M[1]]))
die("Variable ".@$M[0]." is undefined.");
return $GLOBALS[$M[1]];
} // ReplaceVarCallback
function ExpandVars($Str)
{
for (;;)
{
$Res=preg_replace_callback('#\$([A-Za-z_][A-Za-z0-9_]*)#',
"ReplaceVarCallback",$Str);
if ($Res==$Str)
break;
$Str=$Res;
}
return $Str;
} // ExpandVars
------------------------------------------------------------------------
[2008-01-21 01:56:50] t03 at springtimesoftware dot com
Description:
------------
(Note: This feature request is similar to some existing ones, but provides much clearer explanation,
motivation, and details. I hope it will be considered on its own and that this proposal gets
elevated to the PHP design team for serious consideration.)
In PHP, string literals that are specified using quotation marks (") or HEREDOC syntax are
implicitly expanded in several ways, including translation of backslash-escaped characters and
substitution of the actual values of variables, as indicated by leading left brace or dollar signs.
There are many common programming situations where a string contains backslash sequences or
variables that need to be expanded in this way, such as when the string is read in from a text file.
The most frequent solution adopted by PHP programmers is a simple use of the eval function. However,
this solution represents a large security risk if the string to be expanded comes from an external
and possibly malicious user, since such a string can contain arbitrary code that will be executed by
the eval function.
There are many safe solutions, including the use of the str_replace function in a loop to expand
each possible variable.
However, all these solutions involve inefficient and error-prone coding that could be avoided simply
by exposing the Zend mechanism used in the implicit expansion of string literals. The mechanism is
already there; it merely needs to be exposed to the programmer.
Therefore, I hereby request that the PHP team consider adding a new function to PHP that would
expand a given string as is done in the implicit expansion of string literals, returning the
expanded string. I leave it up to the team to determine the specifics (the name of the function and
possible flags to limit the expansion to certain kinds, such as backslash-escaped characters and
variables).
The PHP team has made many intelligent decisions throughout the history of the development of PHP,
including adding new and useful functions. I hope they will consider my proposal seriously,
forgiving me if I have made mistakes or overlooked something that I should have been considered.
David Spector
Springtime Software
Reproduce code:
---------------
(Note: this is not a bug report, but a new feature request.)
------------------------------------------------------------------------
--
Edit this bug report at https://bugs.php.net/bug.php?id=43901&edit=1