Linux SED search replace multiple per line - php

I need to replace a whole bunch of PHP super globals in a clients website with a PHP function I made to clean the superglobals from xss attacks.
Here is what the original code might look like:
echo $_REQUEST['HELLO1'] . ' AND ' . $_REQUEST['HELLO2'];
I need it to look like this:
echo MYCLASS::myfunction($_REQUEST['HELLO1']) . ' AND ' . MYCLASS::myfunction($_REQUEST['HELLO2']);
The main issue, I need to do a search/replace on over 100 files! Yikes!
So my solution was this (in linux shell):
sudo sed -i 's/\$_REQUEST[.*\]/MYCLASS::myfunction(&)/g' *.php
This works great as-long-as only one instance of "$_REQUEST" occurs per line... However with multiple instances, it screws up and does this:
echo MYCLASS::myfunction($_REQUEST['HELLO1'] . ' AND ' . $_REQUEST['HELLO2']);

The problem is that .* is greedy and will find the longest possible match it can. To work around that use [^]]* instead so that you don't inadvertently grab up an extra set of square brackets.
sudo sed -i 's/\$_REQUEST\[[^]]*\]/MYCLASS::myfunction(&)/g' *.php
In other regex dialects you could also write .*? to make the wildcard non-greedy, but that doesn't appear to work in sed (at least not in my version, not even with sed -r).

Try this sed command:
sed -i.bak 's/\$_REQUEST\[\([^]]*\)\]/MYCLASS::myfunction(\1)/g' *.php
or in perl:
perl -pe 's/\$_REQUEST\[([^]]*)\]/MYCLASS::myfunction(\1)/g' file.php

In Perl, the following script will work where you pass the script the name of the file you are interested in
lets say the script is t.pl and your file is file.php
to output back to file.php
perl t.pl file.php > file.php
to output to another file so you don't overwrite your original
perl t.pl file.php > another_file.php
#!/usr/bin/perl
$FILE_NAME = $ARGV[0];
open (FILE_NAME) or die ("Could not open FILE_NAME information file: $FILE_NAME \n");
#file_contents = <FILE_NAME>;
close (FILE_NAME);
foreach $line (#file_contents) {
chomp($line);
$line =~ s/\$_REQUEST\[.*?\]/MYCLASS\:\:myfunction\($&\)/g;
print $line." \n";
}
exit;

sed 's/\$_REQUEST\[[^]]*\]/MYCLASS::myfunction(&)/g'

This should do it:
sed -i "s/\$_REQUEST\[\([^\x5d]*\)\]/MYCLASS::myfunction(\1)/g" *.php
I had a lot of trouble matching ], so I've punted with \x5d.

Related

sed regex cut string

I have about 200 php files that containing some iconv() functions,
something like this:
iconv('GB2312','UTF-8',$aRow[$aColumns[3]])
iconv('GB2312','UTF-8',$rs1['supplier']);
iconv('GB2312','UTF-8',$aRow[ $aColumns[$i] ]);
i don't know what could be the best way to remove iconv('GB2312','UTF-8', and final ) in batch mode without touching the variable.
this RegEx could match my case but i don't know how to use it with sed:
^(iconv\(\'GB2312\'\,\'UTF-8\'\,)+|(\))
And i am also not sure that sed is the right solution in this case
Anyone faced a similar problem before?
You can use this sed command:
sed -i "s/iconv('GB2312','UTF-8',\([^)]*\))\(.*\)/\1\2/" file
which will extract your php variable into \1. /2 is the remaining of the line (a ; in the example you posted)
Try this cut statement with the output.
cat file|cut -d, -f3|tr -d ');'
This might work for you (GNU sed):
sed 's/iconv('\''GB2312'\'','\''UTF-8'\'',\([^)]*\))/\1/g' file
Use an example string as a template, replacing ' by '\'' and the variable to be kept as any characters from after the second , which is not a closing ). This variable is enclosed in quoted (...) i.e. \(...\) which may be transfered to the RHS of the substitution command as a back reference.
Try this sed:
cat file | sed 's/iconv(.*,.*,\(.*\)).*/\1/g'
This will extract only the variable.
With grep
grep -o '$[^)]*' infile

Sed regular expression issue

This is my PHP code for replacing all of the email occurrences from a file:
$pattern = "/[[A-Z0-9._%+-]+[ ]?[\(]?(#|at)[\)]?[ ]?[A-Z0-9.-]+[ ]?[\(]?(\.|dot)[)]?[ ]?[A-Z]{2,4}/i";
$string = preg_replace($pattern, "cs#test.nl", $file );
and it is work. I have to mention that the file is huge. It is an export from a db. I need this regular expression to use it in a sed command:
sed -r -i 's/[[A-Z0-9._%+-]+[ ]?[\(]?(#|at)[\)]?[ ]?[A-Z0-9.-]+[ ]?[\(]?(\.|dot)[)]?[ ]?[A-Z]{2,4}/i/cs#test.nl/g'
Obviously this is not working. Can someone correct the sed command in order to make this work ? thx
You simply need to move the i modifier into the correct position after the replacement.
sed -r -i 's/[[A-Z0-9._%+-]+[ ]?[\(]?(#|at)[\)]?[ ]?[A-Z0-9.-]+[ ]?[\(]?(\.|dot)[)]?[ ]?[A-Z]{2,4}/cs#test.nl/ig'

Replace a char within a pattern with sed

I'm trying to change to migrate my php code using ZF1/PEAR convention to namespaces.
So I want is to change
$locale_test = (new ACME_Common_Factory())->createLocale(ACME_Common_Enum_Civility::MR);
to
$locale_test = (new \ACME\Common\Factory())->createLocale(\ACME\Common\Enum\Civility::MR);
I've tried using the following sed program (which would work for lines containing only 1 class name)
sed -r '/ACME/{h;s/ACME_.*$//1;x;s/^.*(ACME.*)$/\\\1/;s/_/\\/g;x;G;s/\n//1}'
But it actually does little more than
sed -r '/ACME/s/_/\\/g'
I would prefer a solution using sed or awk (just for the sake of improving my cli skill) but any other solution will do.
Spaces as well as most special characters (but, crucially, not _) end a word, so I believe the word boundaries should serve well to identify class names. So, using GNU sed:
sed 's/\>/\n/g; :a s/\<\(ACME[^\n]*\)_\([^\n]*\)/\1\\\2/; ta; s/\<ACME/\\&/g; s/\n//g' filename
This works as follows:
s/\>/\n/g
puts newlines after closing word boundaries. We use this later to match (sort of) non-greedily. After this step, your line becomes
$locale_test
= (new
ACME_Common_Factory
())->createLocale
(ACME_Common_Enum_Civility
::MR
);
This leaves us with an easy way to identify names in the ACME namespace: \<ACME[^\n]*, and to identify names in the ACME namespace that contain an underscore: \<ACME[^\n]*_[^\n]*. We can use this to find underscores in ACME names and replace them one by one:
:a # jump label for looping
s/\<\(ACME[^\n]*\)_\([^\n]*\)/\1\\\2/ # Attempt replacement
ta # if it happened, go back to a.
After that, it's just
s/\<ACME/\\&/g
To put the \ in front, and
s/\n//g
To remove the newline markers we put there.
Mind you, I suspect that this would be easier in Perl.
This might work for you (GNU sed):
sed -r ':a;s/(ACME[a-zA-Z\\]*)_/\1\\/;ta;s/ACME/\\&/g' file
What about this ?
sed -r -e '/ACME_[^\(:]*/s/_/\\/g' -e 's/(ACME\\)/\\\1/g'
I've finally found an answer inspired by #Wintermute
sed -r ':a s/(ACME[^;:\(]*)_([^;:\(]+)/\1\\\2/g; ta' file

php sed like functionality

I am quite familiar with sed on bash shell, so I do
cat $myfile | egrep $pattern | sed -e 's/$pattern/$replace/g'
a lot. Quite a few times, I find that I need to do similar kind of "string parsing" inside PHP.
So my question is simple, what is the equivalent of sed -e 's/$pattern/$replace/g' in PHP ?
I know preg_match , preg_replace , but I haven't used them / not at all familiar with them. I would really appreciate sample code in PHP. (converting say a $var = '_myString' to $newVar = 'getMyString' )
The preg_ functions uses the same regexp library that Perl does, so you should be at home. There's documentation of the syntax here.
For example:
sed -e 's/$pattern/$replace/g'
Would be something like:
$output = preg_replace("/".$pattern."/", $replace, $input);
The most common is to use / as delimiter, but you can use other characters, which can be useful if the pattern contains lots of slashes, as is the case with urls and xml tags. You may also find preg_quote useful.

Bash and PHP, quoting command line arguments

I have a PHP program that uses a Bash script to convert a pdf. However if the filename contains spaces it is not passed through the bash script correctly.
How do you escape filenames with spaces within a bash script? Do you have to do something special to quote the filename for the "OUTFILE" variable?
Bash script:
#!/bin/bash
INFILE=$1
OUTFILE=${INFILE%.*}
gs \
-q \
-dSAFER \
-dBATCH \
-dNOPAUSE \
-sDEVICE=png256 \
-r150x150 \
-sOutputFile=${OUTFILE}.png \
${INFILE}
PHP script:
echo "converting: ".$spool.$file . "\n";
system("/home/user/bin/pdf2png.sh " . escapeshellarg($spool . $file));
Edit: I removed the quotes around the escapeshellarg() variable. This however did not fix the problem. Which I think is in the Bash script OUTFILE variable.
In the last line of your shell script, put quotes around the variable reference:
"${INFILE}"
Considering your code, I would try by, first, removing the single-quotes you are inserting arround the parameter : those shouldn't be necessary, as you are using escapeshellarg.
For instance, the temp.php file might contain :
$spool = "ab cd/";
$file = "gh ij";
system("sh ./test.sh " . escapeshellarg($spool . $file) . "");
And the test.sh :
#!/bin/bash
INFILE=$1
echo $1
With those, the output is :
$ php temp.php
ab cd/gh ij
Which looks like what you expect.
If I put back the single-quotes, like this :
system("sh ./test.sh '" . escapeshellarg($spool . $file) . "'");
The output is broken again :
$ php temp.php
ab
escapeshellarg is escaping data for you (with the right quotes and all that, depending on the operating system), you don't have to do that yourself.
To escape a file name with spaces, just use .
My Tar Ball.tar
My\ Tar\ Ball.tar
So for what you have you will either need to make sure that your arguments contain the back slashes when the script is called, or you will need to add some input checking.
Take a look at escapeshellcmd() and escapeshellarg()

Categories