Characters that can follow a $variable in PHP - php

I am looking for a list of characters that can follow a $variable in PHP. Original task is to go through a file and replace every instance of a variable with different text. But if a file contained $cat and $cat2 and I simply replaced every instance of $cat with $dog, I'd have $dog2 and could not replace $cat2 with $dog3 if I wanted.
Possible solution: order by length and do longest variables first?
The most obvious ones: ),.&+-/*:;%?=[<>!|
For example, you could have a PHP file that had lines like this:
$var = explode($sep, $text);
As you can see, variables are followed by " ", "," and ")" in that line.
What other ones am I missing? Thanks for help, guys.

Implemented it just for fun (even though I still don't understand why you need that):
$code = '<?php
$cat = "foo";
$cat2 = "bar";
$dog = "baz";
';
$replace = array(
'cat' => 'dog',
'cat2' => 'not_dog',
'dog' => 'cat',
);
$tokens = token_get_all($code);
$newCode = '';
foreach ($tokens as $token) {
if (is_array($token)) {
if ($token[0] == T_VARIABLE) {
$variableName = substr($token[1], 1);
if (array_key_exists($variableName, $replace)) {
$token[1] = sprintf('$%s', $replace[$variableName]);
}
}
$part = $token[1];
} else {
$part = $token;
}
$newCode .= $part;
}
echo $newCode;
Demo: http://ideone.com/WUlRdo

From the PHP manual -
Variable names follow the same rules as other labels in PHP. A valid variable name starts with a letter or underscore, followed by any number of letters, numbers, or underscores. As a regular expression, it would be expressed thus: '[a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff]*'
So there you go - if you want to replace all instance of a variable, you just negate the second character class in that regular expression.
preg_replace('/\$replaceMe([^a-zA-Z0-9_\x7f-\xff]|$)/', '$bar', $myCode);

In addition to the ones you posted:
Whitespace and new lines
( as in: $obj = new $variableClassName()
See variable variables
\ to escape characters after a variable inside double quoted string, like "\"$variable\""
# for line comments, as in $variable#comment

Related

How to transform preg_replace to wrap words from an array, instead just one word?

I have the following method, which checks for the word 'example' in a text, and if it finds is, it wraps a span around it:
function highlightWords($dreams) {
$wrap_before = '<span class="highlight_match">';
$wrap_after = '</span>';
$key_words = 'example';
$dreams = json_decode($dreams);
foreach ($dreams as &$value) {
$value->dream = preg_replace("/($key_words)/i",
"$wrap_before$1$wrap_after", $value->dream);
}
return $dreams;
}
I've tried to modify the $key_words variable to an array, so I could give multiple words as parameter, but it always gives back an error. Can I even do this with this approach?
Use implode() to convert your array of keywords into a string that you can use as your regex.
It appears that you want to do a whole word match on one of a number of keywords, so use the alternation operator (the | character) as a delimiter.
For example, given an array of:
$key_words = ['foo', 'bar', 'baz'];
$key_words = implode('|', $key_words);
Yields the following string:
foo|bar|baz
Which you can then use in place to create your regex of key words:
// /(foo|bar|baz)/i
preg_replace("/($key_words)/i",
"$wrap_before$1$wrap_after", $value->dream);
Hope this helps :)

How right print result search preg_replace inside fetch_assoc() result mysql?

$i = $result->fetch_assoc();
preg_replace("/\{(.*?)\}/", $i["$1"], $content);
Error - Undefined variable: $1
// $1 - 'string'; // result search preg_replace()
// $i['string'] = 'hello';
How right syntax will be for print 'hello'?
ok next time please spend a little more time on asking the question:
<?php
$i['string'] = 'zzzzzzzzzzzzzzzzzzzzzz';
$content = "test test test {string} testtesttesttesttest";
$x=preg_replace_callback("/\{(.*?)\}/", function($m) use($i){
return $i[$m[1]];
}, $content);
echo $x;
demo: http://codepad.viper-7.com/u29uKh
for this particular approach you need to use preg_replace_callback() requires PHP 5.3+
You can make your replacements faster using strtr. To do that, you only need an associative array, but this time, all keys must be enclosed between curly brackets.
$i = $result->fetch_assoc();
$keys = array_map(function($k) { return '{' . $k . '}'; }, array_keys($i));
$trans = array_combine($keys, $i);
$content = strtr($content, $trans);
A variable name can't start with a number in PHP. It must start with an underscore or letter.

preg_match_all regex with quotes

I am parsing a php file and I want to get an specific variable value from it.
say $str = '$title = "Hello world" ; $author = "Geek Batman"';
I want to get "Geek Batman" given variable say, $author. But I want to do this dynamically.
Let's say from an html form input value
so
$myDynamicVar = $_POST['var']; //coming from form in the HTML
//$myDynamicVar = '$title = '; (the user will provide the dollar sign and the equal sign)
$pattern = '/\'. $myDynamicVar . '"(.*?)"/s';
$result = preg_match_all($pattern, $str, $output, PREG_SET_ORDER);
the result is coming out empty, although I know the variable exists.
I am assuming it has to do with double quotes and I am not escaping them correctly.
Anyone can help?
It is a bit crazy to parse php code with regular expressions when a proper tokenizer is available:
$str = '$title = "Hello world" ; $author="Geek Batman"';
$tokens = token_get_all('<?php ' . $str);
$state = 0;
$result = null;
foreach ($tokens as $token) {
switch ($state) {
case 0:
if ($token[0] == T_VARIABLE && $token[1] == '$author') {
$state = 1;
}
break;
case 1:
if ($token[0] == T_CONSTANT_ENCAPSED_STRING) {
$result = $token[1];
break 2;
}
break;
}
}
var_dump($result);
Demo: http://ideone.com/bcV9ol
The problem more likely has to do with the special characters that the user enters that have some meaning in regex (mainly the dollar in your case, but maybe other characters too). So you need to escape them (with preg_quote) so the regex matches a $ instead of interpreting it as end of line.
(the way you were using to escape the dollar didn't work, it was escaping the quote to close the string, instead of escaping the dollar in the variable contents)
Try the following:
$myDynamicVar = $_POST['var']; //coming from form in the HTML
//$myDynamicVar = '$title = '; (the user will provide the dollar sign and the equal sign)
$pattern = '/'. preg_quote($myDynamicVar) . '"(.*?)"/s';
$result = preg_match_all($pattern, $str, $output, PREG_SET_ORDER);

PHP word censor with keeping the original caps

We want to censor certain words on our site but each word has different censored output.
For example:
PHP => P*P, javascript => j*vascript
(However not always the second letter.)
So we want a simple "one star" censor system but with keeping the original caps. The datas coming from the database are uncensored so we need the fastest way that possible.
$data="Javascript and php are awesome!";
$word[]="PHP";
$censor[]="H";//the letter we want to replace
$word[]="javascript";
$censor[]="a"//but only once (j*v*script would look wierd)
//Of course if it needed we can use the full censored word in $censor variables
Expected value:
J*vascript and p*p are awesome!
Thanks for all the answers!
You can put your censored words in key-based array, and value of the array should be the position of what char is replaced with * (see $censor array example bellow).
$string = 'JavaSCRIPT and pHp are testing test-ground for TEST ŠĐČĆŽ ŠĐčćŽ!';
$censor = [
'php' => 2,
'javascript' => 2,
'test' => 3,
'šđčćž' => 4,
];
function stringCensorSlow($string, array $censor) {
foreach ($censor as $word => $position) {
while (($pos = mb_stripos($string, $word)) !== false) {
$string =
mb_substr($string, 0, $pos + $position - 1) .
'*' .
mb_substr($string, $pos + $position);
}
}
return $string;
}
function stringCensorFast($string, array $censor) {
$pattern = [];
foreach ($censor as $word => $position) {
$word = '~(' . mb_substr($word, 0, $position - 1) . ')' . mb_substr($word, $position - 1, 1) . '(' . mb_substr($word, $position) . ')~iu';
$pattern[$word] = '$1*$2';
}
return preg_replace(array_keys($pattern), array_values($pattern), $string);
}
Use example :
echo stringCensorSlow($string, $censor);
# J*vaSCRIPT and p*p are te*ting te*t-ground for TE*T ŠĐČ*Ž ŠĐč*Ž!
echo stringCensorFast($string, $censor) . "\n";
# J*vaSCRIPT and p*p are te*ting te*t-ground for TE*T ŠĐČ*Ž ŠĐč*Ž!
Speed test :
foreach (['stringCensorSlow', 'stringCensorFast'] as $func) {
$time = microtime(true);
for ($i = 0; $i < 10000; $i++) {
$func($string, $censor);
}
$time = microtime(true) - $time;
echo "{$func}() took $time\n";
}
output on my localhost was :
stringCensorSlow() took 1.9752140045166
stringCensorFast() took 0.11587309837341
Upgrade #1: added multibyte character safe.
Upgrade #2: added example for preg_replace, which is faster than mb_substr. Tnx to AbsoluteƵERØ
Upgrade #3: added speed test loop and result on my local PC machine.
Make an array of words and replacements. This should be your fastest option in terms of processing, but a little more methodical to setup. Remember when you're setting up your patterns to use the i modifier to make each pattern case insensitive. You could ultimately pull these from a database into the arrays. I've hard-coded the arrays here for the example.
<!DOCTYPE html>
<html>
<meta content="text/html; charset=UTF-8" http-equiv="content-type">
<?php
$word_to_alter = array(
'!(j)a(v)a(script)(s|ing|ed)?!i',
'!(p)h(p)!i',
'!(m)y(sql)!i',
'!(p)(yth)o(n)!i',
'!(r)u(by)!i',
'!(ВЗЛ)О(М)!iu',
);
$alteration = array(
'$1*$2*$3$4',
'$1*$2',
'$1*$2',
'$1$2*$3',
'$1*$2',
'$1*$2',
);
$string = "Welcome to the world of programming. You can learn PHP, MySQL, Python, Ruby, and Javascript all at your own pace. If you know someone who uses javascripting in their daily routine you can ask them about becoming a programmer who writes JavaScripts. взлом прохладно";
$newstring = preg_replace($word_to_alter,$alteration,$string);
echo $newstring;
?>
</html>
Output
Welcome to the world of programming. You can learn P*P, M*SQL, Pyth*n,
R*by, and J*v*script all at your own pace. If you know someone who
uses j*v*scripting in their daily routine you can ask them about
becoming a programmer who writes J*v*Scripts. взл*м прохладно
Update
It works the same with UTF-8 characters, note that you have to specify a u modifier to make the pattern treated as UTF-8.
u (PCRE_UTF8)
This modifier turns on additional functionality of PCRE that is incompatible with Perl. Pattern strings are treated as UTF-8. This
modifier is available from PHP 4.1.0 or greater on Unix and from PHP
4.2.3 on win32. UTF-8 validity of the pattern is checked since PHP 4.3.5.
Why not just use a little helper function and pass it a word and the desired censor?
function censorWord($word, $censor) {
if(strpos($word, $censor)) {
return preg_replace("/$censor/",'*', $word, 1);
}
}
echo censorWord("Javascript", "a"); // returns J*avascript
echo censorWord("PHP", "H"); // returns P*P
Then you can check the word against your wordlist and if it is a word that should be censored, you can pass it to the function. Then, you also always have the original word as well as the censored one to play with or put back in your sentence.
This would also make it easy to change the number of letters censored by just changing the offset in the preg_replace. All you have to do is keep an array of words, explode the sentence on spaces or something, and then check in_array. If it is in the array, send it to censorWord().
Demo
And here's a more complete example doing exactly what you said in the OP.
function censorWord($word, $censor) {
if(strpos($word, $censor)) {
return preg_replace("/$censor/",'*', $word, 1);
}
}
$word_list = ['php','javascript'];
$data = "Javascript and php are awesome!";
$words = explode(" ", $data);
// pass each word by reference so it can be modified inside our array
foreach($words as &$word) {
if(in_array(strtolower($word), $word_list)) {
// this just passes the second letter of the word
// as the $censor argument
$word = censorWord($word, $word[1]);
}
}
echo implode(" ", $words); // returns J*vascript and p*p are awesome!
Another Demo
You could store a lowercase list of the censored words somewhere, and if you're okay with starring the second letter every time, do something like this:
if (in_array(strtolower($word), $censored_words)) {
$word = substr($word, 0, 1) . "*" . substr($word, 2);
}
If you want to change the first occurrence of a letter, you could do something like:
$censored_words = array('javascript' => 'a', 'php' => 'h', 'ruby' => 'b');
$lword = strtolower($word);
if (in_array($lword, array_keys($censored_words))) {
$ind = strpos($lword, $censored_words[$lword]);
$word = substr($word, 0, $ind) . "*" . substr($word, $ind + 1);
}
This is what I would do:
Create a simple database (text file) and make a "table" of all your censored words and expected censored results. E.G.:
PHP --- P*P
javascript --- j*vascript
HTML --- HT*L
Write PHP code to compare the database information to your simple censored file. You will have to use array explode to create an array of only words. Something like this:
/* Opening database of censored words */
$filename = "/files/censored_words.txt";
$file = fopen( $filename, "r" );
if( $file == false )
{
echo ( "Error in opening file" );
exit();
}
/* Creating an array of words from string*/
$data = explode(" ", $data); // What was "Javascript and PHP are awesome!" has
// become "Javascript", "and", "PHP", "are",
// "awesome!". This is useful.
If your script finds matching words, replace the word in your data with the censored word from your list. You would have to delimit the file first by \r\n and finally by ---. (Or whatever you choose for separating your table with.)
Hope this helped!

php how to return only character value from the variable

i am using following code to return only digital values from the variable, wounder how to get only character value "testing" from the variable and want to remove "on" from the string.
<?php
$valuecheck="testing on 123568";
$check1=preg_replace('/\D/', '', $valuecheck);
echo $check1;
?>
Output required:
testing
Thanks
Instead of \D, use [^a-zA-Z] (assuming that's what you mean by "character value"). Basically, put [^SOMETHING], where that "something" is a set of all the characters you want to consider valid.
I'm afraid my solution would be a little more verbose:
$result = '';
$c = explode( ' ', $valuecheck );
foreach ($c as $ci) {
if (preg_match( '[\D]', $ci ) == 1) { continue; }
$result = $ci; break;
}
echo $result;
Treating space as a delimiter, this will ignore any strings with at least one numeric and return the first "qualified" string found.

Categories