evaluate string with array php - php

I have a string like
"subscription link :%list:subscription%
unsubscription link :%list:unsubscription%
------- etc"
AND
I have an array like
$variables['list']['subscription']='example.com/sub';
$variables['list']['unsubscription']='example.com/unsub';
----------etc.
I need to replace %list:subscription% with $variables['list']['subscription'],And so on
here list is first index and subscription is the second index from $variable
.Is possible to use eval() for this? I don't have any idea to do this,please help me

Str replace should work for most cases:
foreach($variables as $key_l1 => $value_l1)
foreach($value_l1 as $key_l2 => $value_l2)
$string = str_replace('%'.$key_l1.':'.$key_l2.'%', $value_l2, $string);
Eval forks a new PHP process which is resource intensive -- so unless you've got some serious work cut out for eval it's going to slow you down.
Besides the speed issue, evals can also be exploited if the origin of the code comes from the public users.

You could write the string to a file, enclosing the string in a function definition within the file, and give the file a .php extension.
Then you include the php file in your current module and call the function which will return the array.

I would use regular expression and do it like that:
$stringWithLinks = "";
$variables = array();
// your link pattern, in this case
// the i in the end makes it case insensitive
$pattern = '/%([a-z]+):([a-z]+)%/i';
$matches = array();
// http://cz2.php.net/manual/en/function.preg-replace-callback.php
$stringWithReplacedMarkers = preg_replace_callback(
$pattern,
function($mathces) {
// important fact: $matches[0] contains the whole matched string
return $variables[$mathces[1]][$mathces[2]];
},
$stringWithLinks);
You can obviously write the pattern right inside, I simply want to make it clearer. Check PHP manual for more regular expression possibilities. The method I used is here:
http://cz2.php.net/manual/en/function.preg-replace-callback.php

Related

PHP preg_match template array as a second argument not working

I found this neat code from: https://www.webmasterworld.com/php/3444822.htm
First example seems to work well:
$firstname = "Eric";
$lastname = "Johnsson";
echo preg_replace("/\{([^\{]{1,100}?)\}/e", "$$1", "{lastname}, {firstname}");
But when I try to use second array version, it gives me index and other errors what ever combinations I try:
$values = array('firstname'=>'Eric', 'lastname'=>'Johnsson');
echo preg_replace("/\{([^\{]{1,100}?)\}/e", "$values[$1]", "{lastname}, {firstname}");
In PHP 5.5x it "should" work. PHP 7.x -> needs to have second argument a function, not accepting -e argument on regex.
Does anyone know working solution to second version? I rather not use export function to extract variables to the working scope.
You need to use preg_replace_callback as in the code below:
$values = array('firstname'=>'Eric', 'lastname'=>'Johnsson');
echo preg_replace_callback("/{([^{}]*)}/", function($m) use ($values) {
return !empty($values[$m[1]]) ? $values[$m[1]] : $m[0];
}, "{lastname}, {firstname} {somestring}");
See the PHP demo
Note that to pass the $values to the anonymous callback function, you need to pass it within use argument. With !empty($values[$m[1]]) you can check if your array contains the necessary key-value, and if yes, replace with it, and if not, just restore the match with the current match value, $m[0].
Note you do not need to escape { and } in this pattern, and you may just use {([^{}]*)} to match any number of chars other than { and } between { and }. If you are only interested in the substrings containing word chars, a {(\w+)} pattern could be more suitable.

How do I concatenate PHP strings without making PHP copy values from one location to another in memory?

I made a function which takes any number of words for a parameter and capitalizes the first letter of each word.
I looked at this site: http://www.carlconrad.net/en/2014/03/17/improving-php-performance/ and it states:
Avoid string concatenations in loops. When placed in a loop, string concatenation results in the creation of large numbers of temporary objects and unnecessary use of the garbage collector. Both consume memory and can dramatically slow down script execution.
I'm trying to figure out how I can modify my code below to make it run faster. Is there another way to concatenate strings in PHP without relying on the value of the original?
I know in raw C language, I could use the address pointer of the string plus an offset within defined bounds to add data without worrying about the original string being copied elsewhere which sources claim what PHP does during concatenation.
Ideally, I want my string concatenation to work like the way this C code works (assume we are in the main() function here):
char string[1000];
memcpy(string,'ABCD',4); //place ABCD at start
memcpy(string+4,'EFGH',4); //add EFGH to the string (no previous string copying required)
Just plain concatenation without manipulating the previous value of the string.
This is my php code that needs advice on improvement:
function capitalize($words){
$words=$words.' ';
$returnedwords='';
$eachword=explode(' ',$words);$numberofwords=count($eachword);
if ($numberofwords >=1){
$wordkey=array_keys($eachword);
for($thiswordno=0;$thiswordno<$numberofwords;$thiswordno++){
$word=$eachword[$wordkey[$thiswordno]];
$returnedwords.=' '.strtoupper(substr($word,0,1)).strtolower(substr($word,1));
}
return substr($returnedwords,1);
}
}
Any ideas how I can follow the websites recommendation to avoid string concatenation in loops like I have in mine?
In php it have function to make first word of string as capital.
example 1: ucword of string:
$str = 'this is test value of data';
echo ucwords('this is test value of data');
output: This Is Test Value Of Data
example 2: create ucword string from array having many words:
$str = array(
'this',
'is',
'test',
'VALUE',
'of',
'Data'
);
$str = array_map('ucwords', array_map('strtolower', $str));
echo implode(' ', $str);
output: This Is Test Value Of Data
for more detail have a look at: PHP String Functions

Pass a closure to an array value

Please forgive me if I'm way off here but I'm trying to create a simple template parser and to do this I'm using regular expressions to find template tags and replace them with dynamic text.
I want to be able to use a closure to return the replacement text. For example:
// Example 1
$tag['\{{title:(.*)}}\'] = function($1)
{
return $1;
};
// Example 2
$tag['\{{title:(.*)}}\'] = function($1)
{
$something = ['One', 'Two', 'Three'];
return $1 . implode($something);
};
// Now do the replacements
foreach($tag as $pattern=>$replacement)
{
preg_replace($pattern, $replacement, $template);
}
I've included example 2 to explain that the result maybe dynamic and this is why I can't simply use strings.
I also feel like I need to explain why I'd need such functionality. The patterns are meant to be expandable, so other developers can add their own patterns easily.
If I've completely off the mark and this isn't going to be achievable, could you point me in the direction to achieve the same/similar functionality?
also, side note - not my main question - but is there a way to do multiple preg_replace in one go instead of looping through, seems inefficient.

Is it possible to render the content of a file without using eval in PHP?

I'm trying to create a simple framework in PHP which will include a file (index.bel) and render the variables within the file. For instance, the index.bel could contain the following:
<h1>{$variable_name}</h1>
How would I achieve this without using eval or demanding the users of the framework to type index.bel like this:
$index = "<h1>{$variable_name}</h1>";
In other words: Is it possible to render the content of a file without using eval? A working solution for my problem is this:
index.php:
<?php
$variable_name = 'Welcome!';
eval ('print "'.file_get_contents ("index.bel").'";');
index.bel:
<h1>{$variable_name}</h1>
I know many have recommended you to add template engine, but if you want to create your own, easiest way in your case is use str_replace:
$index = file_get_contents ("index.bel");
$replace_from = array ('$variable_a', '$variable_b');
$replace_to = array ($var_a_value, $var_b_value);
$index = str_replace($replace_from,$replace_to,$index);
Now that is for simple variable replace, but you soon want more tags, more functionality, and one way to do things like these are using preg_replace_callback. You might want to take a look at it, as it will eventually make possible to replace variables, include other files {include:file.bel}, replace text like {img:foo.png}.
EDIT: reading more your comments, you are on your way to create own framework. Take a look at preg_replace_callback as it gives you more ways to handle things.
Very simple example here:
...
$index = preg_replace_callback ('/{([^}]+)}>/i', 'preg_callback', $index);
...
function preg_callback($matches) {
var_dump($matches);
$s = preg_split("/:/",$matches[1]); // string matched split by :
$f = 'func_'.strtolower($s[0]); // all functions are like func_img,func_include, ...
$ret = $f($s); // call function with all split parameters
return $ret;
}
function func_img($s) {
return '<img src="'.$s[1].'" />';
}
From here you can improve this (many ways), for example dividing all functionalities to classes, if you want.
Yes, this is possible, but why are you making your own framework? The code you provided clearly looks like Smarty Template. You could try to look how they did it.
A possible way to run those code is splitting them into pieces. You split on the dollar sign and the next symbol which is not an underscore, a letter or an number. Once you did that. You could parse it into a variable.
$var = 'variable_name'; // Split it first
echo $$var; // Get the given variable
Did you mean something like this?

Regex Match PHP Comment

Ive been trying to match PHP comments using regex.
//([^<]+)\r\n
Thats what ive got but it doesn't really work.
Ive also tried
//([^<]+)\r
//([^<]+)\n
//([^<]+)
...to no avail
In what program are you coding this regex? Your final example is a good sanity check if you're worried that the newline chars aren't working. (I have no idea why you don't allow less-than in your comment; I'm assuming that's specific to your application.)
Try
//[^<]+
and see if that works. As Draemon says, you might have to escape the diagonals. You might also have to escape the parentheses. I can't tell if you know this, but parentheses are often used to enclose capturing groups. Finally, check whether there is indeed at least one character after the double slashes.
To match comments, you have to think there are two types of comments in PHP 5 :
comments which start by // and go to the end of the line
comments that start by /* and go to */
Considering you have these two lines first :
$filePath = '/home/squale/developpement/astralblog/website/library/HTMLPurifier.php';
$str = file_get_contents($filePath);
You could match the first ones with :
$matches_slashslash = array();
if (preg_match_all('#//(.*)$#m', $str, $matches_slashslash)) {
var_dump($matches_slashslash[1]);
}
And the second ones with :
$matches_slashstar = array();
if (preg_match_all('#/\*(.*?)\*/#sm', $str, $matches_slashstar)) {
var_dump($matches_slashstar[1]);
}
But you will probably get into troubles with '//' in the middle of string (what about heredoc syntax, btw, did you think about that one ? ), or "toggle comments" like this :
/*
echo 'a';
/*/
echo 'b';
//*/
(Just add a slash at the begining to "toggle" the two blocks, if you don't know the trick)
So... Quite hard to detect comments with only regex...
Another way would be to use the PHP Tokenizer, which, obviously, knows how to parse PHP code and comments.
For references, see :
token_get_all
List of Parser Tokens
With that, you would have to use the tokenizer on your string of PHP code, iterate on all the tokens you get as a result, and detect which ones are comments.
Something like this would probably do :
$tokens = token_get_all($str);
foreach ($tokens as $token) {
if ($token[0] == T_COMMENT
|| $token[0] == T_DOC_COMMENT) {
// This is a comment ;-)
var_dump($token);
}
}
And, as output, you'll get a list of stuff like this :
array
0 => int 366
1 => string '/** Version of HTML Purifier */' (length=31)
2 => int 57
or this :
array
0 => int 365
1 => string '// :TODO: make the config merge in, instead of replace
' (length=55)
2 => int 117
(You "just" might to strip the // and /* */, but that's up to you ; at least, you have extracted the comments ^^ )
If you really want to detect comments without any kind of strange error due to "strange" syntax, I suppose this would be the way to go ;-)
You probably need to escape the "//":
\/\/([^<]+)
This will match comments in PHP (both /* */ and // format)
/(\/\*).*?(\*\/)|(\/\/).*?(\n)/s
To get all matches, use preg_match_all to get array of matches.

Categories