How to use fgets as stream_get_line alternative? - php

I am using stream_get_line to store some php output in a variable, while I'm running a telnet session via fsockopen.
However, my second server does not run PHP5, which is disabled the ability to use stream_get_line. Is there any alternative for PHP 4.3?
I heard that fgets is almost the same, but I don't seem to get it to work exactly like stream_get_line.
Code:
...
# opening connection
$fp = #fsockopen($ip, 23, $errno, $errstr, 8);
# loggin in
fputs($fp, "$user\r");
usleep(250000);
fputs($fp, "$password\r");
# getting information
fputs($fp, "show info\n");
usleep(250000);
fputs($fp, "show info 2\n");
usleep(250000);
fputs($fp, "show info 3\n");
usleep(250000);
fputs($fp, "show info 4\n");
usleep(250000);
fputs($fp, "?\n");
$content = stream_get_line($fp, 0, "?");
$contentvalues = array(
1 => substr($content, 130, 3),
2 => substr($content, 180, 3)
);
fclose($fp);
...
(I am storing specific parts of my output in the $contentvalues variable.)

From the docs:
This function is nearly identical to fgets() except in that it allows
end of line delimiters other than the standard \n, \r, and \r\n, and
does not return the delimiter itself.
From the comments:
when fgets reads some bytes from socket, where EOF is reached, it
returns bool(false) same as stream_get_line
BUT if remote client drops connection, and server script will try to
read some data with function fgets, function will return bool(false),
and stream_get_line will return string(0) ""
so you can detect remote client disconnection with stream_get_line,
and cannot with fgets
There's also some dithering about which function is faster, but it seems to be dependant on the version of PHP, the day of the week, and what the commenter had for dinner the previous night.
edit
Judging by your response to Steffen's answer you're hung up on the fact that fgets() does not take a third parameter as a delimiter. Applying a basic input loop and checking the string will get you there. Also, in Steffen's defense, you were never quite clear on in your question, stating only that it doesn't "work exactly like stream_get_line".
<?php
$delim = '?';
$buf = 4096;
$fp = #fsockopen($ip, 23, $errno, $errstr, 8);
// ... yadda yadda yadda ... //
$content = '';
while( $part = fgets($fp, $buf) ) {
$ind = strpos($part, $delim);
if( $ind !== false ) {
$content .= substr($part, 0, $ind);
break;
}
$content .= $part;
}
Also, even with stream_get_line() you should be using a loop to get the input as a length parameter or 0 does not mean "unlimited", but rather will use one of PHP's defaults which is 8192 bytes.

You can use fgets() (string fgets ( resource $handle [, int $length ] )) instead.
http://www.php.net/manual/de/function.fgets.php

Related

How do i send a byte stream to a socket with PHP?

In GO i can do the following:
conn, _ := net.Dial("tcp", CONNECT) // Client
request := []byte{01, 00} // The request start with 0100
request = append(request, []byte(`09302020073014323720200730007402`)...) // The request
conn.Write(request)
This does work, however, i'm unable to translate this to PHP.
What i have so far:
$fp = stream_socket_client("tcp://x:x", $errno, $errstr, 5);
if (!$fp) {
echo "$errstr ($errno)<br />\n";
} else {
$queryString = '010009302020073014323720200730007402';
fwrite($fp, $queryString);
echo fgets($fp, $responseSize);
fclose($fp);
}
I tried using the described solutions here with no success, the server does not recognise my input.
In your Go example, your request begins with the bytes 0x01, and 0x00. In PHP, you're writing the byte encoding of the string '0100'. These aren't exactly the same, and you can view how they differ here: https://play.golang.org/p/0gidDZe4lZF
What you really want to be writing is the single byte 0x0, and 0x1 at the beginning of your string instead of these characters.
Using PHP's builtin chr function we can create a string using the single bytes 0x0 and 0x1 like so:
$queryString = chr(0) . chr(1);
$queryString .= '09302020073014323720200730007402'
Barring any additional encoding issues on the PHP side of things, that should match your query in your Go example.

encrypt decrypt a file: SVG or XML with PHP

I use these two functions to encrypt / decrypt files :
private function encrypt_file($source,$destination,$passphrase,$stream=NULL) {
// $source can be a local file...
if($stream) {
$contents = $source;
// OR $source can be a stream if the third argument ($stream flag) exists.
}else{
$handle = fopen($source, "rb");
$contents = #fread($handle, filesize($source));
fclose($handle);
}
$iv = substr(md5("\x1B\x3C\x58".$passphrase, true), 0, 8);
$key = substr(md5("\x2D\xFC\xD8".$passphrase, true) . md5("\x2D\xFC\xD9".$passphrase, true), 0, 24);
$opts = array('iv'=>$iv, 'key'=>$key);
$fp = fopen($destination, 'wb') or die("Could not open file for writing.");
stream_filter_append($fp, 'mcrypt.tripledes', STREAM_FILTER_WRITE, $opts);
fwrite($fp, $contents) or die("Could not write to file.");
fclose($fp);
}
private function decrypt_file($file,$passphrase) {
$iv = substr(md5("\x1B\x3C\x58".$passphrase, true), 0, 8);
$key = substr(md5("\x2D\xFC\xD8".$passphrase, true) .
md5("\x2D\xFC\xD9".$passphrase, true), 0, 24);
$opts = array('iv'=>$iv, 'key'=>$key);
$fp = fopen($file, 'rb');
stream_filter_append($fp, 'mdecrypt.tripledes', STREAM_FILTER_READ, $opts);
return $fp;
}
It works perfectly for most files. But there is a problem with SVG or XML files in general. Decryption of an SVG file for example gives characters "NUL NUL ..." in the last line. As you can see in this picture:
You may have copied the code straight from the PHP documentation. But: As it says on the same page, there are several issues with this code. Basically using md5 for key derivation is far from optimal. See http://www.cryptofails.com/post/70059608390/php-documentation-woes for full description. This and encryption filters are deprecated (see same link), I would recommend abandoning this style of cryptography.
I would also recommend using some tested PHP crypto library like libsodium-php. This will also be integrated into php7 itself. (Source)
Back to topic: What you are seeing is the encryption padding. For the block cipher (in your case DES) to work, each chunk has to have the size given by the algorithm. Since most data doesn't care about chunk size, the algorithm has to apply some kind of padding.
When decrypting, you also receive the padded value. To get to your output value, you need to remove the padding afterwards. In your case this would be to trim the tailing NUL charachters. Its already in the documentation (thanks to #James for pointing this out)
$data = rtrim(stream_get_contents($fp)); //trims off null padding

php compression filters and gzcompress not returning the same result

I get different output when I run my code through zlib compression filters
My code:
<?php
$data = 'zzzzzzzzzzzzzzzzzzzzzzzzzzz';
$params = array('level' => 6, 'window' => 15, 'memory' => 9);
//$params = 6;
$fp = fopen('php://memory', 'wb+');
stream_filter_append($fp, 'zlib.deflate', STREAM_FILTER_WRITE, $params);
fputs($fp, $data);
rewind($fp);
echo bin2hex(stream_get_contents($fp)) . "\n";
echo bin2hex(gzcompress($data)) . "\n";
The output:
789c
789cabaaa2260000bce3252d
It's my understanding that 789c is the header for normal compression. So I have no idea what's up. Do compression streams just not work in PHP?
Any ideas would be appreciated - thanks!
The problem is that your string is much too short to fill the DEFLATE working buffer. And because your stream is not explicitly closed, it doesn't get processed at all, nor flushed. Your data is still pending in the buffer when stream_get_contents() is called.
If we force a buffer flush by injecting a large enough block of random bytes, some data gets actually written to the stream:
$data = openssl_random_pseudo_bytes(65536);
$params = array('level' => 6, 'window' => 15, 'memory' => 9);
$fp = fopen('php://memory', 'wb+');
stream_filter_append($fp, 'zlib.deflate', STREAM_FILTER_WRITE, $params);
fputs($fp, $data);
rewind($fp);
echo substr(bin2hex(stream_get_contents($fp)), 0, 32) . "\n";
echo substr(bin2hex(gzcompress($data)), 0, 32) . "\n";
Example output (just displaying the 16 first bytes):
789c000b80f47f453c070e41c557acdb
789c000b80f47f453c070e41c557acdb
On the other hand, the ZLIB header (78 9C = default compression) can be safely written from the beginning because its content doesn't depend on the next coming bytes. There's no need for a buffer in that case.

not sending messages from script

I know i might gonna so many down vote but please help me through this as i nearly there. I have below code.
<?php
exec("mode COM1 BAUD=9600 PARITY=N data=8 stop=1 xon=off");
$fp = fopen ("\\.\com1", "r+");
//$fp = dio_open('COM5:', O_RDWR | O_NOCTTY | O_NONBLOCK);
if (!$fp)
{
echo "Uh-oh. Port not opened.";
}
else
{
$string = "AT+CMGF=1";
$string = $string."OK";
$string = $string."AT+CMGS='+44XXXXX'";
$string = $string."> Hello World?<Ctrl>+<Z>";
$string = $string."+CMGS: 44";
$string = $string."OK";
fputs ($fp, $string );
echo $string."\n";
fclose ($fp);
}
?>
above code is outputting AT+CMGF=1OKAT+CMGS='+44XXXX'> Hello World?++CMGS: 44OK but not actually sending any message to that number.
I have device is attached with PC which has SIM card in it.
How can I do this?
From what I know of AT commands, is that it is a dialogue. You have to send AT+CMGF=1 then wait for the modem to send OK, send the next command etcetera.
You are now sending everything, including the modem's responses in one string.
More information (as always) on Wikipedia: http://en.wikipedia.org/wiki/Hayes_command_set
The code should be along the lines of (off the top of my head, not tested):
$string = "AT+CMGF=1";
fputs($fp, $string);
$r = fgets($fp);
if ($r == "OK") {
$string = "AT+CMGS='+44XXXXX'";
fputs($fp, $string);
$r = $fgets($fp);
... etc ...
}

In PHP: OpenSSL Error messages: error: 1409F07F: SSL routines: SSL3_WRITE_PENDING: bad write retry

I'm trying to send a huge amount of data using SSL/TLS connection in PHP. It works pretty well if the data chunk isn't very big or if I don't use TLS, but what I need (near 2MiB), the fwrite function shows the warning:
Warning: fwrite(): SSL operation failed with code 1. OpenSSL Error messages: error: 1409F07F: SSL routines: SSL3_WRITE_PENDING: bad write retry
The relevant code I'm using to connect clients:
$cntxt = stream_context_create(array('ssl' => array('local_cert' => 'certificate.pem')));
$server = stream_socket_server('tls://127.0.0.1:8080', $errno, $errstr, STREAM_SERVER_BIND|STREAM_SERVER_LISTEN, $cntxt);
// Wait for client connection //
$client = stream_socket_accept($server);
// Use non-blocking socket to allow answering many clients at a time
stream_set_blocking($client, 0);
$clients[] = $client;
When sending data, it's append to a buffer and, from time to time, this function is called for each client and linked buffer:
function trySend($client, &$buffer) {
if (strlen($buffer)) {
$len = fwrite($client, $buffer);
$buffer = substr($buffer, $len);
}
}
As I said, my code works for small ammount of data or for normal (non-TLS) connections. I've searched for this error and found http://www.openssl.org/docs/ssl/SSL_write.html:
SSL_write() will only return with success, when the complete contents of buf of length num has been written. This default behaviour can be changed with the SSL_MODE_ENABLE_PARTIAL_WRITE option of SSL_CTX_set_mode(3). When this flag is set, SSL_write() will also return with success, when a partial write has been successfully completed. In this case the SSL_write() operation is considered completed. The bytes are sent and a new SSL_write() operation with a new buffer (with the already sent bytes removed) must be started. A partial write is performed with the size of a message block, which is 16kB for SSLv3/TLSv1.
But how can I do this in PHP?
Any help appreciated :)
I have found I can get around this problem by restricting the length of the string passed to fwrite() to 8192, which prevents fwrite() warning.
So for the code in your example I would try changing the substr() call to:
$buffer = substr($buffer, $len, 8192);
The solution is:
$msg = chr(0) . pack('n', 32) . pack('H*', $deviceToken) . pack('n', strlen($payload)) . $payload;
try {
$result = fwrite($fp, $msg, strlen($msg));
}
catch (Exception $ex) {
sleep(1); //sleep for 5 seconds
$result = fwrite($fp, $msg, strlen($msg));
}

Categories