Different Output Characters on VBScript and PHP in Windows Command Prompt [duplicate] - php

I'm trying to generate mail configurations and personalized signatures through a batch file that reads a list of users, a template, and creates a personalized output. That's done and works:
#ECHO OFF
SETLOCAL ENABLEEXTENSIONS
GOTO begin
:writesignature
cscript //NoLogo replacetext.vbs "[NAME]" %1 signature.html stdout | cscript //NoLogo replacetext.vbs "[JOB]" %3 stdin stdout | cscript //NoLogo replacetext.vbs "[EMAIL]" %2 stdin signature-%4.html
GOTO :end
:begin
FOR /F "tokens=1,2,3,4 delims=;" %%A IN ('TYPE people.lst') DO CALL :writesignature "%%A" "%%B" "%%C" %%D
:end
To do the text replacing, I created replacetext.vbs, that allows me to replace a string for oter, and can be piped if stdin and stdout are indicated as the source and target files:
CONST ForReading = 1
CONST ForWritting = 2
CONST ForAppending = 8
CONST OpenAsASCII = false
CONST OpenAsUnicode = true
CONST OpenAsDefault = -2
Const OverwriteIfExist = true
Const FailIfExist = false
Const CreateIfNotExist = true
Const FailIfNotExist = false
SET objFSO = CreateObject("Scripting.FileSystemObject")
SET objFILEINPUT = Wscript.StdIn
SET objFILEOUTPUT = Wscript.StdOut
IF (Wscript.Arguments.Count < 2) OR (Wscript.Arguments.Count > 4) THEN
Wscript.Echo "Not enought arguments"
Wscript.Echo "replacetext ""<original>"" ""<replacement>"" "
Wscript.Quit(1 MOD 255)
END IF
IF Wscript.Arguments.Count > 2 THEN
IF Wscript.Arguments(2) = "stdin" THEN
' Wscript.Echo "Input: StdIn"
ELSE
' Wscript.Echo "Input: " + Wscript.Arguments(2)
SET objFILEINPUT = objFSO.OpenTextFile(Wscript.Arguments(2), ForReading, OpenAsASCII)
END IF
IF Wscript.Arguments.Count = 4 THEN
IF Wscript.Arguments(3) = "stdout" THEN
' Wscript.Echo "Output: StdOut"
ELSE
' Wscript.Echo "Output: " + Wscript.Arguments(3)
IF objFSO.FileExists(Wscript.Arguments(3)) THEN
SET objFILEOUTPUT = objFSO.OpenTextFile(Wscript.Arguments(3), ForWritting, CreateIfNotExist, OpenAsASCII)
ELSE
SET objFILEOUTPUT = objFSO.CreateTextFile(Wscript.Arguments(3), OverwriteIfExist, OpenAsASCII)
END IF
END IF
END IF
END IF
strText = objFILEINPUT.ReadAll()
strNewText = Replace(strText, Wscript.Arguments(0), Wscript.Arguments(1))
objFILEOUTPUT.Write(strNewText)
objFILEOUTPUT.Close
objFILEINPUT.Close
Wscript.Quit(0 MOD 255)
The problem is that when I put non-ASCII characters in ANSI/Windows-1250 in the people.lst (Comunicación), while it works and reads them in console, showing them (not converting them) as OEM characters (Comunicaci¾n) when I write the output files, somehow it does convert them transparently, so the output file in Windows shows Comunicaci¾n instead of Comunicación.
After much debugging, I've localized the problem in ONLY the arguments (no automatic conversion on the template file).
How can I disable said transparent conversion, or convert back the input from ANSI to OEM so the conversion works as intended?

The problem is that the cmd.exe works with different code page than cscript.exe/wscript.exe. I have similiar problem in Poland, where cmd.exe works with codepage 852 (I believe this is for compatibility with older MS-DOS programs) and wscript.exe works in Windows' native codepage 1250.
To solve the problem, put the following line on the beginning of the batch file:
mode con cp select=1250

Related

Adding numbers and getting a percentage

I have a PHP script that runs a few du commands to extract the kB size of 3 specific directories. That works, and I have $dir1size as 521046477, dir2size as 521043911 and $dir3size as 67167152. These pop out fine (ie no dodgy characters in the strings) if I echo the results into a JSON format.
I then want to add them up to get $tot and divide by the disk size which is $disksize to get $pctused.
The code I have is...
$rtn = array();
# Get disk size
$cmd = "df | sed -n '/DataVolume/s/ \+/ /gp' | cut -d' ' -f 2";
exec($cmd, $disksize, $int);
$rtn["disk"]["kB"]["total"] = $disksize[0];
# Get dir1 size
$cmd = "du --apparent-size .. | sed -n 's/[\ ]*\.\.\/TNFrontCam1$/ TNFront/p' | cut -d' ' -f 1";
exec($cmd, $dir1size, $int);
$rtn["disk"]["kB"]["TNFront"] = $dir1size[0];
# 2 more blocks like that for the other 2 directories
# Do the calulations
$tot = $dir1size + $dir2size + $dir3size;
$rtn["disk"]["kB"]["used"] = $tot;
$pctused = ($tot / $disksize) * 100;
$rtn["disk"]["percent"]["used"] = $pctused;
$rtn["disk"]["percent"]["free"] = 100 - $pctused;
echo json_encode($rtn, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES | JSON_NUMERIC_CHECK);
When I run this get Fatal Error: Unsupported operand types in the line calculating the percentage used.
If I comment out the 3 percentage lines I get the JSON string but instead of showing me the sum of the 3, I just get $dir1size but in square brackets! (hence the fatal error when it tries to do the percent calcs).
I've also tried intval($dirxsize) but then I get a null in the JSON output.
(I should add I am running this on a WD NAS drive that I've SSHed into in the hope that I can report usage info to my Home Assistant)
Edit - When I use PHP Sandbox, the maths all works out fine!
The second parameter of the exec function is an array (one element for each line of output), so if the size is on the first line you have to access the element at index zero, like:
$disksize[0]
For every variable used as the second argument of exec:
$tot = $dir1size[0] + $dir2size[0] + $dir3size[0];
$rtn["disk"]["kB"]["used"] = $tot;
$pctused = ($tot / $disksize[0]) * 100;

CLI multibyte input

I have a problem receiving multibyte character through PHP CLI.
I have a little script that reads from STDIN:
<?php
while(true) {
# also not working, but is similar to fgets anyway, except you can specify the ending char, so no surprise
#$strInput = trim(stream_get_line(STDIN, 1024, PHP_EOL));
$strInput = trim(fgets(STDIN, 1024));
var_dump($strInput);
}
Basically this works, but I have a problem if I type in any non ASCI character,
then using backspace.
e.g. input = 'ß' // string(2) "ß"
e.g. input = 'ß' and backspace // string(1) "�"
e.g. input = 'ß' and backspace twice // string(0) ""
I don't know whether this a PHP or terminal problem. I tend to think it is a PHP problem.
It works on my terminal:
e.g. % ß // ß: Command not found
e.g. % ßß and backspace // ß: Command not found
Unfortunatelly there is no mb_* function to read from STDIN.
Here are my terminal settings:
% locale
LANG=de_DE.UTF-8
LC_CTYPE="de_DE.UTF-8"
LC_COLLATE=C
LC_TIME="de_DE.UTF-8"
LC_NUMERIC="de_DE.UTF-8"
LC_MONETARY="de_DE.UTF-8"
LC_MESSAGES="de_DE.UTF-8"
LC_ALL=
% stty -a
speed 38400 baud; 58 rows; 212 columns;
lflags: icanon isig iexten echo echoe echok echoke -echonl echoctl
-echoprt -altwerase -noflsh -tostop -flusho -pendin -nokerninfo
-extproc
iflags: -istrip icrnl -inlcr -igncr ixon -ixoff ixany imaxbel -ignbrk
brkint -inpck -ignpar -parmrk
oflags: opost onlcr -ocrnl tab0 -onocr -onlret
cflags: cread cs8 -parenb -parodd hupcl -clocal -cstopb -crtscts -dsrflow
-dtrflow -mdmbuf
cchars: discard = ^O; dsusp = ^Y; eof = ^D; eol = <undef>;
eol2 = <undef>; erase = ^H; erase2 = ^H; intr = ^C; kill = ^U;
lnext = ^V; min = 1; quit = ^\; reprint = ^R; start = ^Q;
status = ^T; stop = ^S; susp = ^Z; time = 0; werase = ^W;
% cat /home/foobar/.login_conf
# $FreeBSD: releng/10.2/share/skel/dot.login_conf 77995 2001-06-10 17:08:53Z ache $
#
# see login.conf(5)
#
me:\
:charset=UTF-8:\
:lang=de_DE.UTF-8:\
:setenv=LC_COLLATE=C:
I am using FreeBSD 10.3 with the latest PHP 7.1.9.
I also tried different shells like bash, but the output remains the same.
Also tried starting xterm with -u8 option, no success.
Does anybody have an idea how to fix this? What am I missing?

php runs terminal app with system()/shell_exec()/exec() but only half of the output shows up

so I have a php script:
<?php
error_reporting(E_ALL);
//print_r($_GET);
$command = '../../build/program_name ' . $_GET['arg_id'];
$command .= ' -test '.$_GET['arg1'].' '.$_GET['arg2'];
//echo $command . "\n";
//system('pwd');
//system('ls -la ../../build');
//system('../../build/program_name 17 -test 125 1500 2>&1');
//passthru('../../build/program_name 17 -test 125 1500');
system('../../build/program_name 17 -test 125 1500');
//system($command);
//$data = exec($command);
//var_dump($data);
//echo $data;
//echo "\n";
?>
simple version:
<?php
error_reporting(E_ALL);
system('../../build/program_name 17 -test 125 1500');
?>
The output from this is:
argv[0] = ../../build/program_name
argv[1] = 17
argv[2] = -test
argv[3] = 125
argv[4] = 1500
argc = 5 so appears to be test request.
TEST(125, 1500) test requested.
If I run the command in the terminal however the output is:
argv[0] = ../../build/program_name
argv[1] = 17
argv[2] = -test
argv[3] = 125
argv[4] = 1500
argc = 5 so appears to be test request.
TEST(125, 1500) test requested.
{ "function": "test" , "inputs": [125.000000, 1500.000000], "output": 999.000000}
the last bit of output (the important part) isn't showing up when php runs the exact same command... I've printed the working directory and the command just to verify that I'm in fact running the command correctly, the results are consistently the same across exec, shell_exec, and system.... I'm just at a loss for what is happening here...
Edit: additional info about 'program_name' heres an extremely simplified version. its c++:
float arg1;
float arg2;
if(argc == 5){
arg1 = atof(argv[3]);
arg2 = atof(argv[4]);
} else {
cout << "please supply appropriate args" << endl;
return -1;
}
#ifdef DEBUG
cout << "TEST(" << arg1 << ", " << arg2 << ") test requested." << endl;
#endif
float output = test(arg1, arg2);
string jsonOut = "{ ";
jsonOut.append(
"\"function\": \"test\" , ").append(
"\"inputs\": [").append(to_string(arg1)).append(", ").append(to_string(arg2)).append("], ").append(
"\"output\": ").append(to_string(output)).append("}");
cout << jsonOut << endl;
return 0;
Use passthru() instead of system(). The difference is that passthru() passes the command's output through to PHP's output, while system() captures the output and returns the last line.
The other output you're seeing is presumably written to stderr, which system() doesn't capture.
Okay this is insane, but fixed it. the program 'program_name' was saving a little log file using fprintf(). php would ignore all output from the program after the first call to fprintf()... commenting out fprintf() and recompiling program_name fixed the problem and now php doesn't bail in the middle, apparently php is incompatible to calls to fprintf() on OS X???

Run Node.js script from PHP - output is truncated to 512 characters

We run node.js CLI script from PHP with Symfony Process.
The script always print whole response as JSON in one line.
The response is somehow truncated on 512 characters.
I only found that xdebug.var_display_max_data => 512 => 512 in php.ini but don't see how this is related.
Adapter > Symfony Process > node script.js
A) Test Node script
from terminal node script $ node user-update.js parameters returns full result in all cases - like 629 chars.
from Symfony Process node script response is truncated to 512 chars.
B) Test Symfony Process
$process = new Process($cmd);
try {
$process->mustRun();
$response = $process->getOutput();
} catch (ProcessFailedException $e) {
$response = $e->getMessage();
}
echo $response;
echo PHP_EOL;
echo strlen($response);
$cmd = 'node user-update.js parameters'; - truncated to 512.
$cmd = 'php -r \'for($i=0; $i<520; $i++){ echo "."; }\''; - does not truncate.
$cmd = 'cat long_one_line.txt'; - print full file. 1650 chars in one line.
C) Try with PHP shell functions
$response = shell_exec($cmd); // response is truncated to 512
system($cmd, $returnVal); // print directly to STDOut, truncated to 512
What could be the cause and solution?
node v7.6.0
PHP 7.1.2
I suspect your process is ending before the buffer can be read by PHP.
As a work-around you can add something like this:
// The `| cat` at the end of this line means we wait for
// cat's process to end instead of node's process.
$process = new Process('node user-update.js parameters | cat');

Encoding puzzles with sockets in different languages

I have this below code written in PHP responsible for the server socket, specifically by writing messages to certain sockets:
header('Content-Type: text/html; charset=utf-8');
const PAYLOAD_LENGTH_16 = 126;
const PAYLOAD_LENGTH_63 = 127;
const OPCODE_CONTINUATION = 0;
for ($i = 0; $i < $frameCount; $i++) {
// fetch fin, opcode and buffer length for frame
$fin = $i != $maxFrame ? 0 : self::FIN;
$opcode = $i != 0 ? self::OPCODE_CONTINUATION : $opcode;
$bufferLength = $i != $maxFrame ? $bufferSize : $lastFrameBufferLength;
// set payload length variables for frame
if ($bufferLength <= 125) {
$payloadLength = $bufferLength;
$payloadLengthExtended = '';
$payloadLengthExtendedLength = 0;
}
elseif($bufferLength <= 65535) {
$payloadLength = self::PAYLOAD_LENGTH_16;
$payloadLengthExtended = pack('n', $bufferLength);
$payloadLengthExtendedLength = 2;
} else {
$payloadLength = self::PAYLOAD_LENGTH_63;
$payloadLengthExtended = pack('xxxxN', $bufferLength); // pack 32 bit int, should really be 64 bit int
$payloadLengthExtendedLength = 8;
}
// set frame bytes
$buffer = pack('n', (($fin | $opcode) << 8) | $payloadLength).$payloadLengthExtended.substr($message, $i * $bufferSize, $bufferLength);
And below I have the code in Objective-C responsible for receiving these messages from the socket server:
NSInteger len = 0;
uint8_t buffer[4096];
while ([inputStream hasBytesAvailable]) {
len = [inputStream read:buffer maxLength:sizeof(buffer)];
if (len > 0) {
[self.data appendBytes:buffer length:len];
[self.log insertText:[NSString stringWithFormat:#"Log: Received a message from server:\n\n"]];
NSLog(#"Received a message from server...");
}
}
when all bytes are received I run the following command to turn the data into a file:
[self.data writeToFile:#"dataComes.txt" options:NSDataWritingAtomic error:nil]
The Problem
We will send a large file in JSON format for objective-c, with that he will receive that information and will generate a file called dataComes.txt, I can see the JSON file normally but except for some strange characters such as:
~ or ~Â or â-Û
These strange characters always shows at the beginning of each block messages that Objective-C receives (Yes, the socket server and TCP divide large messages into blocks of messages).
What is the cause of this problem and how it could solve this?
SOLUTION 1: Filtering
I can filter out unwanted characters that may come, but it will also filter out some words that have accentuation:
NSCharacterSet *notAllowedChars = [[NSCharacterSet characterSetWithCharactersInString:#"0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ[]{}:,'"] invertedSet];
NSString *resultString = [[total componentsSeparatedByCharactersInSet:notAllowedChars] componentsJoinedByString:#" "];
SOLUTION 2: Stop using sockets
I have tried many ways to send data to my app, the only one that worked was to send the data separately (a loop of one JSON), but to works I had to put my code (PHP) to sleep using sleep(1) (and I believe this is not good) because if not Objective-C recognizes that this data is a single package.
In this case, or my code have problems, or the programming of socket in objective-c was not very well done and has inconsistencies (bug). What remains for me to do with my connections through normal requests via web server (which I do not think it's a good idea, since I have to do this every 3 seconds in a 5 minute time interval).
SOLUTION 3: FILTERING + UNICODE
On the server side I can filter all special characters and create a specific combination for it example:
Hello é world to Hello /e001/ world
And in my app I can filter this combination and change to the real format....

Categories