Trying to make a simple Perl script that looks at a GET parameter to determine which php version to use, and then pass on the request. Here is the whole script:
#!/usr/bin/perl
use FCGI;
$cnt = 0;
local ($buffer, #pairs, $pair, $name, $value);
while(FCGI::accept >= 0){
$php = "php";
$ENV{PHP_FCGI_CHILDREN}=3;
$ENV{PHP_FCGI_MAX_REQUESTS}=5000;
$buffer = $ENV{'QUERY_STRING'};
#pairs = split(/&/, $buffer);
foreach $pair (#pairs) {
($name, $value) = split(/=/, $pair);
if($name == "php") {
$php = "php".$value;
}
}
print "Content-Type: text/html\r\n\r\n";
print `$php $ENV{PATH_TRANSLATED}`;
}
The idea is that the PHP version can be switched with a GET parameter... that part seems to be working fine when I test with phpversion().
So this thing seems to be "working" but a test file with a simple <?php phpinfo(); ?> outputs a pure string, NOT the formatted HTML. It gives the exact output as if phpinfo() were run from the command line, because that's exactly whats going on.
So the two parts to my question are
Is this actually a problem?
How would I "pass the request" to PHP, instead of invoking the command line?
Nice command injection vulnerability you built there.
QUERY_STRING='0=5;echo "fail_at_Web_security_forever";rm -rf /'
String comparison is eq, not ==. You must validate user input, white-list acceptable input and reject all other. The lack of a standard CGI parameter parsing library is typical for bad code like that: use CGI.pm or similar.
To forward/proxy a request, call PHP via HTTP: use LWP::UserAgent or similar.
Related
I'm trying to use php with awk. The awk command is just to print out the password of a database so i can feed it to the php code to connect to mysql and work the rest of the code.
My awk code looks something like this ( in the php file):
$pass = system('awk FS='=' '/Mydbpass/ {print $2}'; file.conf');
That code works perfect but it prints the passwod when i open the php file in my browser, how can i make the php mysql read it without having it printed ? I would use include but the file.conf doesn't have the password as a variable. If there's any other way to this also please share.
One way would be to use the exec function which returns the output of the command being executed without sending it to the output.
However, it would be most likely much better to read the file directly in your php script and parse it there. Something like:
#open the file
$fp = fopen('file.conf', 'r');
if ($fp) {
while(($line = fgets($fp)) !== false){
#split the line using = as delimiter
$cols = array_map(trim, explode('=', $line));
#do something with the columns
print_r($cols);
}
fclose($fp);
}
Use parse_ini_file() it suits best for this kind of things, no need of using system function and awk, you can achieve this in php itself.
<?php
$content=parse_ini_file("your.conf");
// Your password
$password = $content['Mydbpass'];
?>
For example if you have input file like below
Input
$ cat test.conf
Mydbpass=somesecretpass
Mydbuser=user12344
Output
$ php -r '$content=parse_ini_file("test.conf");print_r($content);'
Array
(
[Mydbpass] => somesecretpass
[Mydbuser] => user12344
)
I am trying to get PHP to search a text file for a string. I know the string exists in the text, PHP can display all the text, and yet strpos returns false.
Here is my code:
<?php
$pyscript = "testscript.py";
//$path = "C:\\Users\\eneidhart\\Documents\\Python Scripts\\";
$process_path = "C:\\Users\\eneidhart\\Documents\\ProcessList.txt";
//$processcmd = "WMIC /OUTPUT: $process PROCESS get Caption,Commandline,Processid";
$process_file = fopen($process_path, "r") or die("Unable to open file!");
$processes = fread($process_file);
if (strpos($processes, $pyscript) !== FALSE) {
echo "$pyscript found";
} elseif (strpos($processes, $pyscript) === FALSE) {
echo "$pyscript NOT found :(";
} else {
echo "UHHHHHHHH...";
}
echo "<br />";
while (!feof($process_file)) {
echo fgets($process_file)."<br />";
}
fclose($processfile);
echo "End";
?>
The while loop will print out every line of the text file, including
python.exe python testscript.py
but strpos still can't seem to find "testscript.py" anywhere in it.
The final goal of this script is not necessarily to read that text file, but to check whether or not a particular python script is currently running. (I'm working on Windows 7, by the way.) The text file was generated using the commented out $processcmd and I've tried having PHP return the output of that command like this:
$result = `$processcmd`;
but no value was returned. Something about the format of this output seems to be disagreeing with PHP, which would explain why strpos isn't working, but this is the only command I know of that will show me which python script is running, rather than just showing me that python.exe is running. Is there a way to get this text readable, or even just a different way of getting PHP to recognize that a python script is running?
Thanks in advance!
EDIT:
I think I found the source of the problem. I created my own text file (test.txt) which only contained the string I was searching for, and used file_get_contents as was suggested, and that worked, though it did not work for the original text file. Turns out that the command listed under $processcmd creates a text file with Unicode encoding, not ANSI (which my test.txt was encoded in). Is it possible for that command to create a text file with a different encoding, or even simpler, tell PHP to use Unicode, not ANSI?
You can use the functions preg_grep() and file():
$process_path = "C:\\Users\\eneidhart\\Documents\\ProcessList.txt";
$results = preg_grep('/\btestscript.py\b/', file($process_path));
if(count($results)) {
echo "string was found";
}
You should follow the advice given in the first comment and use either:
file_get_contents($process_path);
or
fread($process_file, filesize($process_path));
If that fix is not enough and there is actually a problem on strpos (which shouldn't be the case), you can use:
preg_match("/.*testscript\.py.*/", $processes)
NB: Really try to use strpos and not preg_match as it's not advised by the documentation.
Well, I found the answer. Thanks to those of you who suggested using file_get_contents(), as I would not have gotten here without that advice. Turns out that WMIC outputs Unicode, and PHP did not like reading that. The solution was another command which converts Unicode to ANSI:
cmd.exe /a /c TYPE unicode_file.txt > ansi_file.txt
I hope this helps, for those of you out there trying to check if a particular python script is working, or if you're just trying to work with WMIC.
I'm building a RAKEFILE and I want to display the output on a php generated page as it gets executed.
I tried using system() since the PHP docs mention this:
The system() call also tries to automatically flush the web server's output buffer after each line of output if PHP is running as a server module.
This seems to work with multiple shell comands but when I execute rake I only get the first line:
(in /Users/path/to/proj)
Any ideas?
Cheers!
Try use exec() function
exec($command, $output);
$output is an array
//retrieved data
for($out = '',$x = 0,$len = count($output); $x < $len; $x++) {
$out .= $output[$x] . "\r\n";
}
or simple:
$out = join("\r\n", $output);
The system() call also tries to automatically flush the web server's output buffer after > each line of output if PHP is running as a server module.
This means you would only get the last line of output from the return value. The example in the system() manual page shows that and it suggests to use passthru() to get raw output. I usually use exec() though.
Turs out both functions system() & exec() actually work. The generated rake output when using --verbose isn't taken into consideration though. That's why I was confused. If anyone has more extensive knowledge on the distinction, do share :)
Is it possible to create an interactive shell, using PHP alone?
I mean something like you have with databases, Python, etc. If it is, how?
Yes, it's possible. In order to be interactive, the program must be able to wait for and read in user input from stdin. In PHP, you can read from stdin by opening a file descriptor to 'php://stdin'. Taken from an answer to different question, here's an example of an interactive user prompt in PHP (when run from the command line, of course):
echo "Continue? (Y/N) - ";
$stdin = fopen('php://stdin', 'r');
$response = fgetc($stdin);
if ($response != 'Y') {
echo "Aborted.\n";
exit;
}
Of course, to get a full line of input rather than a single character, you'd need fgets() instead of fgetc(). Depending what your program/shell will do, the whole program might be structured as one big continuous loop. Hopefully that gives you an idea how to get started. If you wanted to get really fancy (CLI pseudo-GUI), you could use ncurses.
Since this question has been asked and answered, a better solution has been added to PHP. In all recent PHP versions, at least PHP 5.4, you can easily get user input as so:
$input = fgets(STDIN);
The way I understand your question you just want the PHP interpreter to run on the command line so you that it will evaluate any PHP code that you type. I use that feature of Python all the time to test code snippets. In which case I believe the answer you are looking for is to execute (from the command line):
php -a
Assuming PHP is in your path this will drop you in to the PHP interpreter, like it does on mine:
php -a
Interactive shell
php >
From there you can start to evaluate arbitrary PHP expressions and see the results:
php > $a = 'abcdef';
php > echo strlen($a);
6
Here's an expanded take on this. I've added an isCLI() check in case you're run your script both in CLI and on a web server. Otherwise the server could loop using my function. This solution will prompt the user, check the input, and re-prompt the user for fixed input if necessary.
I rtrim() the input, because if the user uses return to submit their entry, that may be appended to the entry. Validation is not necessary; just don't pass a function in that case.
function isCLI() {
return (php_sapi_name() === 'cli' OR defined('STDIN'));
}
function userPrompt($message, $validator=null) {
if (!isCLI())
return null;
print($message);
$handle = fopen ('php://stdin','r');
$line = rtrim(fgets($handle), "\r\n");
if (is_callable($validator) && !call_user_func($validator, $line)) {
print("Invalid Entry.\r\n");
return userPrompt($message, $validator);
} else {
print("Continuing...\r\n");
return $line;
}
}
// Example =====================
function validateSetLangCode($str) {
return preg_match("/^[A-Z0-9]{3}-[A-Z]{2}$/", $str);
}
$code = userPrompt("Please enter the set / language codes. Use the format 'SET-EN', where SET is the three-letter set code and EN is the two-letter lang code. \r\n", 'validateSetLangCode') ?: 'SET-EN';
var_dump($code);
Since PHP has a built-in Unix-only function readline() to do exactly that, note:
We can use and hold the result of readline in a variable.
#!/usr/bin/php
<?php
$user = readline("List dir [l] | Say hello [h] | exit [q]: ");
if ($user === "l"){ system("ls"); }
if ($user === "h"){ echo "Hello!"; }
if ($user === "q"){ exit; }
echo "\nThanks!";
Example output:
l ls result
h «hello»
q exit
Ctrl + C exit.
Ctrl + D with empty input, continue to the next sequence. «Thanks». $user is defined and empty, no error.
Ctrl + D with some input: No action. Still waiting for input.
Ctrl + M Continue and take the current input in $user.
Ctrl + J Continue and take the current input in $user, same behavior as Ctrl + M.
Return continue to the next sequence «Thanks». $user can stay empty, no error.
Ctrl + Z may be used to cancel a loop and move to the top one. $user will be unset if the var is not defined in this scope.
Depending input, we can define empty values using!empty or do more surgical testings (the readline response can be many chars).
$user can be tested with !isset if not yet asked.
There is also the built-in readline_add_history() to store the user input into an object, where values can be retrieved directly by their name (nice for code clarity):
readline_add_history($user);
print_r(readline_list_history());
print_r(readline_user());
It is very useful to build real complex stuffs!
See how to catch and send POSIX signals.
PHP function readline()
If you want the interactive shell to process PHP commands, one example is phpsh which was apparently created at Facebook, but it is written in Python.
I know the questioner didn't want the second option, but for those that wanted the second option as I did, in addition to phpsh, PHP also has its own shell:
Just run php -a.
Check out Sheldon.
It's pretty easy to get started. It includes Symfony 2 and Zend Framework libraries that do a lot of the basic console I/O work and gives you a higher-level abstraction built around command objects (with regex routes) and Contexts (which hold immutable state).
One of the things I love is that "out of the box", your application can run as either an interactive shell, or as a standard script that you can run from the command line, specify a command, pass any arguments, and when the command is finished the application exits.
I normally call perl scripts from PHP as below and pass in variables this way, and it works fine, however now I am building a component for re-use where I want to also variablize the perl script name that I am passing in and this is giving me some headaches, so I am wondering if anyone can point out a better way to do this as my way isn't working.. thanks..
the way that works without variablized perl filename:
$file = "/var/www/other_scripts/perl/apps/perlscript.pl $var1 $var2 $var3 $var4";
ob_start();
passthru($file);
$perlreturn = ob_get_contents();
ob_end_clean();
My attempt to variablize the perl filename that doesn't seem to be working for me, you can see in the above how it is including even the $var(s) in the initial " ", which I find odd but this seems to be the only way that it works and I wasn't sure how to even replicate this with a variablized perl filename:
$perlscript_file = "/var/www/other_scripts/perl/apps/" . $perlscript .".pl";
$file = $perlscript_file . $var1 . $var2 .$var3 . $var4;
ob_start();
passthru($file);
$perlreturn = ob_get_contents();
ob_end_clean();
Your way is not working because you are concatenating all the parameters without spaces, effectively making them one parameter.
Try
$perlscript_file = "/var/www/other_scripts/perl/apps/$perlscript.pl $var1 $var2 $var3 $var4";
By the way, if the parameters are coming from an external source, you MUST sanitize them using escapeshellarg(). The same goes for $perlscript - if it comes from an external source or even user input, do a escapeshellcmd() on it.
On a sidenote, there is a CPAN package that aims to provide a bridge between PHP and Perl, which would allow you to do something like the following in PHP:
$perl = Perl::getInstance();
$instance = $perl->new('perlclass', #args);
Not sure how stable this is though. See
PHP::Interpreter
Integrating PHP and Perl
If you are using Apache, you can also use
// PHP
apache_note('foo', 'bar');
virtual("/perl/some_script.pl");
$result = apache_note("resultdata");
# Perl
my $r = Apache->request()->main();
my $foo = $r->notes('foo');
$r->notes('resultdata', somethingWithFoo($foo));
See http://php.net/manual/en/function.apache-note.php
In your second code, you're concatenating the variables without spaces between them. You should consider using sprintf to format this nicely:
$script = sprintf('/var/www/other_scripts/perl/apps/%s.pl %s %s %s %s', $perlscript, $var1, $var2, $var3, $var4);