Call a program via shell_exec with utf-8 text input - php

Perquisites: hunspell and php5.
Test code from bash:
user#host ~/ $ echo 'sagadījās' | hunspell -d lv_LV,en_US
Hunspell 1.2.14
+ sagadīties
- works properly.
Test code (test.php):
$encoding = "lv_LV.utf-8";
setlocale(LC_CTYPE, $encoding); // test
putenv('LANG='.$encoding); // and another test
$raw_response = shell_exec("LANG=$encoding; echo 'sagadījās' | hunspell -d lv_LV,en_US");
echo $raw_response;
returns
Hunspell 1.2.14
& sagad 5 0: tagad, sagad?ties, sagaudo, sagand?, sagar?o
*
*
Screenshot (could not post code with invalid characters):
It seems that shell_exec cannot handle utf-8 correctly, or maybe some additional encoding/decoding is needed?
EDIT: I had to use en_US.utf-8 to get valid data.

Try this code:
<?php
// The word we are checking
$subject = 'sagadījās';
// We want file pointers for all 3 std streams
$descriptors = array (
0 => array("pipe", "r"), // STDIN
1 => array("pipe", "w"), // STDOUT
2 => array("pipe", "w") // STDERR
);
// An environment variable
$env = array(
'LANG' => 'lv_LV.utf-8'
);
// Try and start the process
if (!is_resource($process = proc_open('hunspell -d lv_LV,en_US', $descriptors, $pipes, NULL, $env))) {
die("Could not start Hunspell!");
}
// Put pipes into sensibly named variables
$stdIn = &$pipes[0];
$stdOut = &$pipes[1];
$stdErr = &$pipes[2];
unset($pipes);
// Write the data to the process and close the pipe
fwrite($stdIn, $subject);
fclose($stdIn);
// Display raw output
echo "STDOUT:\n";
while (!feof($stdOut)) echo fgets($stdOut);
fclose($stdOut);
// Display raw errors
echo "\n\nSTDERR:\n";
while (!feof($stdErr)) echo fgets($stdErr);
fclose($stdErr);
// Close the process pointer
proc_close($process);
?>
Don't forget to verify that the encoding of the file (and therefore the encoding of the data you are passing) actually is UTF-8 ;-)

Related

PHP - `shell_exec` not working with NMap (Windows Server)

I've been trying to figure out why I can't get NMap to give me any sort of output nor even work for that matter via PHP.
Things I've tried so far:
// this doesn't return anything because it's wrong
$output = passthru('nmap -V');
echo $output;
// this returns a negated integer value
passthru('nmap -V', $output);
echo $output;
// this doesn't return anything either
$stream = popen('C:\nmap -V', 'r');
while (!feof($stream))
{
$buffer = fread($stream, 1024);
echo $buffer;
}
pclose($stream);
// this doesn't do anything as well
$output = system('C:\nmap -V');
echo $output;
// this does nothing also...
ob_start(); // start output buffering
fpassthru('C:\nmap -V'); // flush COMPLETE output of nmap
$output = ob_get_contents(); // capture output buffer contents
ob_end_clean(); // shutdown output buffers
echo $output; // echo it
.
// okay, how about we try a 'proc_open()'?
// nope, this doesn't work either. I just get a value of "command returned -1073741515"
$descriptorspec = array(
0 => array("pipe", "r"), // stdin is a pipe that the child will read from
1 => array("pipe", "w"), // stdout is a pipe that the child will write to
2 => array("file", "errors/errors.txt", "a") // stderr is a file to write to
);
$cwd = 'errors';
$env = array('some_option' => 'aeiou');
$process = proc_open('C:/nmap -V', $descriptorspec, $pipes, $cwd, $env);
if (is_resource($process))
{
// $pipes now looks like this:
// 0 => writeable handle connected to child stdin
// 1 => readable handle connected to child stdout
// Any error output will be appended to /errors/errors.txt
fwrite($pipes[0], '<?php print_r($_ENV); ?>');
fclose($pipes[0]);
echo stream_get_contents($pipes[1]);
fclose($pipes[1]);
// It is important that you close any pipes before calling
// proc_close in order to avoid a deadlock
$return_value = proc_close($process);
echo "command returned $return_value\n";
}
And many others, but I get absolutely NOTHING back from $output. I've done a lot of Google searching too, but I still can't figure it out. Many examples also seem to be for Linux which doesn't help.
Thanks.
Okay, I get an output using this code. I will continue coding and finish the rest of the program. Thanks to 'Chris Haas' for the suggestion in using proc_open
NOTE: The directory that contains the 'errors.txt' file must have 'IIS_IUSRS' write permissions. When in doubt, check your PHP error log.
$descriptorSpec = array(
0 => array("pipe", "r"), // stdin is a pipe that the child will read from
1 => array("pipe", "w"), // stdout is a pipe that the child will write to
2 => array("file", "errors/errors.txt", "a") // stderr is a file to write to
);
$env = array('bypass_shell' => true);
$process = proc_open("NMAP.EXE -V", $descriptorSpec, $pipes, "C:\\Program Files (x86)\\NMap", $env);
if (is_resource($process))
{
// '$pipes' now looks like this:
// 0 => writeable handle connected to child stdin
// 1 => readable handle connected to child stdout
fwrite($pipes[0], '<?php print_r($_ENV); ?>');
fclose($pipes[0]);
echo stream_get_contents($pipes[1]);
fclose($pipes[1]);
// it is important that you close any pipes before calling
// proc_close in order to avoid a deadlock
$return_value = proc_close($process);
echo "<br /><br />Command Returned: $return_value\n";
}
Nmap version 7.91 ( https://nmap.org ) Platform:
i686-pc-windows-windows Compiled with: nmap-liblua-5.3.5
openssl-1.1.1h nmap-libssh2-1.9.0 nmap-libz-1.2.11 nmap-libpcre-7.6
Npcap-1.00 nmap-libdnet-1.12 ipv6 Compiled without: Available nsock
engines: iocp poll select
Command Returned: 0

Generate ZPL code with PHP and print to zebra chrome addon for testing?

Ok I downloaded the Chrome ZPL addon for testing with zebra printers. But now I like to print the following:
$qrcode = "012039444";
$name = "Matthew Pitt";
$jobtitle = "CTO funny man";
$company = "Google light company";
$labelcode =<<<AAA
^XA
^FX Left section with QR code.this part doesn't seem to work in simulator
^FO100,100
^BQN,2,10
^FD$qrcode^FS
^FX Right section with name and job title.
^CF0,35,35^FO330,50
^FB300,7,,
^FD$name\&\&$jobtitle^FS
^FO50,500^GB700,1,3^FS
^FX Bottom section only company name
^CF0,35,35^FO30,350
^FB400,2,,
^FD$company^FS
^XZ
AAA;
print_example($labelcode);
//print_example('Hello world');
function print_example($data) {
// You'll need to change these according to your local names and options.
$server = '127.0.0.1:9100';
$printer_name = 'zpl'; // That's effectively the same thing as your GK420d
$options_flag = '-o position=top-left,ppi=203,landscape';
$process_name = 'LC_ALL=en_US.UTF-8 /usr/bin/lp -h %s -d %s %s';
$command = sprintf($process_name, $server, $printer_name, (string)$options_flag);
$pipes = array();
$descriptors = array(
0 => array("pipe", "r"), // STDIN
1 => array("pipe", "w"), // STDOUT
2 => array("pipe", "w") // STDERR
);
$process = proc_open($command, $descriptors, $pipes);
// Couldn't open the pipe -- shouldn't happen
if (!is_resource($process))
trigger_error('Printing failed, proc_open() did not return a valid resource handle', E_USER_FATAL);
// $pipes now looks like this:
// 0 => writeable handle connected to child stdin
// As we've been given data to write directly, let's kinda like do that.
fwrite($pipes[0], $data);
fclose($pipes[0]);
// 1 => readable handle connected to child stdout
$stdout = fgets($pipes[1]);
fclose($pipes[1]);
// 2 => readable handle connected to child stderr
$stderr = fgets($pipes[2]);
fclose($pipes[2]);
// It is important that you close any pipes before calling
// proc_close in order to avoid a deadlock
$return_value = proc_close($process);
// We've asked lp not to be quiet about submitting jobs so we can make
// sure that the print job was submitted.
$request_match = array();
if (!preg_match('/request id is\b(.+)/', $stdout, $request_match)) {
echo ("Print to '$printer_name' failed. Please check the printer status.");
return false;
}
echo ("Print to '$printer_name' succeeded. Job $request_match[1].");
return true;
}
[EDIT]
is this the right command to call the printer
LC_ALL=en_US.UTF-8 /usr/bin/lp -h zpl -d 127.0.0.1:9100 -o position=top-left,ppi=203,landscape
[EDIT 2]
I am trying with this php
$command = 'lp -h 127.0.0.1:9100 -d zpl ' . $labelcode . ' -o position=top-left,ppi=203,landscape';
$pipes = array();
$descriptors = array(
0 => array("pipe", "r"), // STDIN
1 => array("pipe", "w"), // STDOUT
2 => array("pipe", "w") // STDERR
);
$process = proc_open($command, $descriptors, $pipes);
echo 'test: ' . $process;

Non ASCII Characters in filename are skipped

The program youtube-dl by itself supports Non ASCII characters in filename, It works flawlessly on my webserver under root user as well as www-data user, but when I try downloading a video using youtube-dl with PHP, the Non ASCII characters are completely skipped.
Eg: Stromae - bâtard will be saved as Stromae - btard.mp4 or البث الحي as .mp4
I am using this code to run the CLI command
function cmd($string) {
$descriptorspec = array(
0 => array("pipe", "r"), // stdin
1 => array("pipe", "w"), // stdout
2 => array("pipe", "w"), // stderr
);
$process = proc_open($string, $descriptorspec, $pipes);
$stdout = stream_get_contents($pipes[1]);
fclose($pipes[1]);
$stderr = stream_get_contents($pipes[2]);
fclose($pipes[2]);
$ret = proc_close($process);
return $stdout;
}
$value = ('youtube-dl https://some.valid/link');
echo cmd($value);
Kindly advise what I should do to fix this issue.
Check your phpinfo(); output for LC_ALL or LC_LANG settings. I suspect it has nothing to do with PHP, but with the shell environment that you're using versus the shell environment your web server is using.
$value = ('LC_ALL=en_US.UTF-8 youtube-dl https://some.valid/link');
echo cmd($value);
By default PHP use ISO-8859-1 charset. Configure PHP to use UTF-8. You can to this by adding
mb_internal_encoding("UTF-8");
At the beggining of your script

PHP SVN update - TortoiseSVN

New code:
<?php
exec('"C:\Program Files\TortoiseSVN\bin\svn.exe" update "c:\wamp\www\project"');
This results in an infinite loop, no result is returned. What am I doing wrong?
== edit ==
On Windows, I'm trying to update a project by using PHP. I'm having problems using the commandline: I want visual feedback (important in case of conflicts), so I don't want to start as a background process. Is this possible?
The code I have so far is:
<?php
$todo = "cd \"C:\\Program Files\\TortoiseSVN\\bin\\\"";
$todo2 = "START TortoiseProc.exe /command:update /path:\"C:\\wamp\\www\\project\\\" /closeonend:0";
pclose(popen($todo, "r"));
pclose(popen($todo2, "r"));
I would drop exec and use proc_open (see http://php.net/manual/en/function.proc-open.php)
Here's an example I quickly whipped up and which should work for you:
<?php
// setup pipes that you'll use
$descriptorspec = array(
0 => array("pipe", "r"), // stdin
1 => array("pipe", "w"), // stdout
2 => array("pipe", "w") // stderr
);
// call your process
$process = proc_open('"C:\Program Files\TortoiseSVN\bin\svn.exe" update "c:\wamp\www\project"',
$descriptorspec,
$pipes);
// if process is called, pipe data to variables which can later be processed.
if(is_resource($process))
{
$stdin = stream_get_contents($pipes[0]);
$stdout = stream_get_contents($pipes[1]);
$stderr = stream_get_contents($pipes[2]);
fclose($pipes[0]);
fclose($pipes[1]);
fclose($pipes[2]);
$return_value = proc_close($process);
}
// Now it's up to you what you want to do with the data you've got.
// Remember that this is merely an example, you'll probably want to
// modify the output handling to your own likings...
header('Content-Type: text/plain; charset=UTF-8');
// check if there was an error, if not - dump the data
if($return_value === -1)
{
echo('The termination status of the process indicates an error.'."\r\n");
}
echo('---------------------------------'."\r\n".'STDIN contains:'."\r\n");
echo($stdin);
echo('---------------------------------'."\r\n".'STDOUTcontains:'."\r\n");
echo($stdout);
echo('---------------------------------'."\r\n".'STDERR contains:'."\r\n");
echo($stderr);
?>
Aside:
The line
// call your process
$process = proc_open('"C:\Program Files\TortoiseSVN\bin\svn.exe" update "c:\wamp\www\project"',
$descriptorspec,
$pipes);
could also be escaped like this
// call your process
$process = proc_open("\"C:\\Program Files\\TortoiseSVN\\bin\\svn.exe\" update \"c:\\wamp\\www\\project\"",
$descriptorspec,
$pipes);
which might or might not solve some problems on some systems that have hickups with the single brackets (') and spaces () in the notation.

Proc_open() c++/python

I'm trying to make a call for a c++ / python file with proc_open (bi-directional support needed).
After doing some on-line research I found created this code: (I first tried it with c++, after failure I tried python as well)
PHP:
<?php
$descriptorspec = array(
0 => array("pipe", "r"),
1 => array("pipe", "w"),
2 => array("file", "error-output.txt", "a")
);
$process = proc_open('new.exe', $descriptorspec, $pipes);
$input = 20;
$exp = 2;
if (is_resource($process)) {
print fgets($pipes[1]);
fwrite($pipes[0], $input);
print fgets($pipes[1]);
fwrite($pipes[0], $exp);
print fgets($pipes[1]);
fclose($pipes[1]);
fclose($pipes[0]);
$return_value = proc_close($process);
echo "command returned $return_value\n";
} else {
echo "No resource availeble";
}
?>
C++:
#include <iostream>
using namespace std;
int main () {
// Get variables from php
cout << "input" << endl;
cin << input
cout << "exponent" << endl;
cin << exp
// Process variables
int answer = input + exp;
// Return variables
cout << answer;
// End c++ script
return 0;
}
Python:
print 'enter input'
inp = raw_input()
print 'enter exponent'
exp = raw_input()
ant = inp + exp
print ant
But sadly enough it kept failing with the same error: file is not recognized as internal or external command, program or batch file.
Some extra information:
I used Wamp with PHP 5.3.0
The return value I get from proc_close() = 1
There are two problems in you code (at least for running your Python script). First, you're not flushing your Python output to it's STDOUT, so it never reaches PHP. This causes fgetc() to block infinitely. It's a simple fix, just add some flush() calls:
#!/usr/bin/env python
import sys
print 'enter input'
sys.stdout.flush()
inp = raw_input()
print 'enter exponent'
sys.stdout.flush()
exp = raw_input()
ant = inp + exp
print ant
sys.stdout.flush()
Then, in your PHP code you are not sending any newlines when you write to the Python script STDIN. So, Python's raw_input() waits indefinitely for a newline. Again, an easy fix. Just add "\n" to the fwrite() calls:
#!/usr/bin/php
<?php
$descriptorspec = array(
0 => array("pipe", "r"),
1 => array("pipe", "w"),
2 => array("file", "error-output.txt", "a")
);
$process = proc_open('/path/to/python/script.py', $descriptorspec, $pipes);
$input = 20;
$exp = 2;
if (is_resource($process)) {
print fgets($pipes[1]);
fwrite($pipes[0], $input . "\n");
print fgets($pipes[1]);
fwrite($pipes[0], $exp . "\n");
print fgets($pipes[1]);
fclose($pipes[1]);
fclose($pipes[0]);
$return_value = proc_close($process);
echo "command returned $return_value\n";
} else {
echo "No resource availeble";
}
And with those changes, I can make your code work as expected:
$ ./procopen.php
enter input
enter exponent
202
command returned 0
You're misunderstanding what proc_open() does. It opens a process like you would from the command line, e.g. (in Unix) diff file1.txt file2.txt. proc_open() does not run an executable.
According to the page I think you got your code from, http://php.net/manual/en/function.proc-open.php, to execute an external program you would use exec(). You can use this (provided the executable is in the right directory):
<?php
echo exec('someprogram.exe');
?>
Note: I am not certain that this will work with a Windows executable.
This is assuming that someprogram.exe is a compiled executable made from the C++ source you posted. If you wanted to run a Python program from PHP, first of all good luck using Windows, but you would want to use proc_open() to call python somescript.py, just like you would do from the command line.
Specify the absolute path of the executable file:
$process = proc_open('/path/to/new.exe', $descriptorspec, $pipes);
I can get PHP to talk to Perl with proc_open by calling the PHP script below via command line:
#!/usr/bin/php -q
$descriptorspec = array(
0 => array("pipe", "r"),
1 => array("pipe", "w"),
2 => array("file", "error.log", "a")
);
$process = proc_open('/path/to/procopen.pl ' . $argv[1],
$descriptorspec, $pipes);
if (is_resource($process)) {
// print pipe output
echo stream_get_contents($pipes[1]);
// close pipe
fclose($pipes[1]);
// close process
proc_close($process);
}
Here's my Perl script which is in same directory as the PHP script above:
#!/usr/bin/perl
print #ARGV;
But I can't get the PHP to run when calling your Python script. The command line just stalls forever. Why is this?

Categories