I'm running PHP5 on Windows XP Professional. I'm trying to write a telnet php script which simply connects, sends a text string and grabs the response buffer and outputs it. I'm using the telnet class file from here:
http://cvs.adfinis.ch/cvs.php/phpStreamcast/telnet.class.php
which i found in another thread.
<?php
error_reporting(255);
ini_set('display_errors', true);
echo "1<br>";
require_once("telnet_class.php");
$telnet = new Telnet();
$telnet->set_host("10.10.5.7");
$telnet->set_port("2002");
$telnet->connect();
//$telnet->wait_prompt();
$telnet->write('SNRD 1%0d');
echo "3<br>";
$result = $telnet->get_buffer();
echo $result;
print_r($result);
// flush_now();
echo "4<br>";
$telnet->disconnect();
?>
I'm not receiving any kind of errors or response. If I send an invalid string, I should get an 'ERR' response in the least however I don't even get that. Any ideas what i could be doing wrong? If I do the same thing from the command prompt, I receive the string output I need. Could this is because the write function is sending
After some reading in the source code and on the original (french) site referred to in the header....
<?php
error_reporting(255);
ini_set('display_errors', true);
echo "1<br>";
require_once("telnet_class.php");
$telnet = new Telnet();
$telnet->set_host("10.10.5.7");
$telnet->set_port("2002");
if ($telnet->connect() != TELNET_OK) {
printf("Telnet error on connect, %s\n",$telnet->get_last_error());
}
//$telnet->wait_prompt();
if ($telnet->write('SNRD 1' . "\xd") != TELNET_OK) {
printf("Telnet error on write, %s\n",$telnet->get_last_error());
}
// read to \n or whatever terminates the string you need to read
if ($telnet->read_to("\n") != TELNET_OK) {
printf("Telnet error on read_to, %s\n",$telnet->get_last_error());
}
echo "3<br>";
$result = $telnet->get_buffer();
echo $result;
print_r($result);
// flush_now();
echo "4<br>";
$telnet->disconnect();
?>
Okay, explanation: get_buffer() does just that, read what's in the buffer. To get something in the buffer you have to execute read_to($match) who will read into buffer up to $match. After that, get_buffer should give you the desired string.
EDIT:
if you cannot find some string that follows the string you are interested in read_to will end in an error due to this part of the read_to method (translation of original french comment is mine):
if ($c === false){
// plus de caracteres a lire sur la socket
// --> no more characters to read on the socket
if ($this->contientErreur($buf)){
return TELNET_ERROR;
}
$this->error = " Couldn't find the requested : '" . $chaine . "', it was not in the data returned from server : '" . $buf . "'" ;
$this->logger($this->error);
return TELNET_ERROR;
}
Meaning that when the socket is closed without a match of the requested string, TELNET_ERROR will be returned. However, the string you're looking for should at that point be in the buffer.... What did you put in read_to's argument? "\n" like what I did or just "" ?
EDIT2 :
there's also a problem with get_buffer. IMO this class is not really a timesaver ;-)
//------------------------------------------------------------------------
function get_buffer(){
$buf = $this->buffer;
// cut last line (is always prompt)
$buf = explode("\n", $buf);
unset($buf[count($buf)-1]);
$buf = join("\n",$buf);
return trim($buf);
}
It will throw away the last line of the response, in your case the one that contains the
answer.
I suggest to add a "light" version of get_buffer to the class, like this
//------------------------------------------------------------------------
function get_raw_buffer(){
return $this->buffer;
}
and do the necessary trimming/searching in the result yourself.
You might also want to add the following constant
define ("TELNET_EOF", 3);
and change read_to like this
...
if ($c === false){
// plus de caracteres a lire sur la socket
if ($this->contientErreur($buf)){
return TELNET_EOF;
}
$this->error = " Couldn't find the requested : '" . $chaine . "', it was not in the data returned from server : '" . $buf . "'" ;
$this->logger($this->error);
return TELNET_EOF;
}
...
in order to treat that special case yourself (a result code TELNET_EOF doesn't have to be treated as an error in your case). So finally your code should look more or less like this:
// read to \n or whatever terminates the string you need to read
if ($telnet->read_to("\n") == TELNET_ERROR) {
printf("Telnet error on read_to, %s\n",$telnet->get_last_error()); } echo "3<br>";
} else {
$result = $telnet->get_raw_buffer();
echo $result;
print_r($result);
}
Have you checked how the telnet class works? Maybe it wasn't designed to run under windows. If it's a simple socket that you're speaking to, maybe consider using a regular socket-connection instead.
http://se2.php.net/sockets
If you open up a socket which you don't close, you should se an entry in netstat as long as your script is running.
netstat -na|find ":2002"
You can't insert hex values like that. The remote process just sees
SRND 1%0d
and now it's waiting for the line to be terminated. Try this
$telnet->write('SNRD 1' . "\r");
or
$telnet->write("SNRD 1\xd");
The double quotes are quite critical, see here
EDIT:
you might try adding some error reporting as right now you don't really check much (error_reporting won't show anything on the errors in the telnet class).... For example:
<?php
error_reporting(255);
ini_set('display_errors', true);
echo "1<br>";
require_once("telnet_class.php");
$telnet = new Telnet();
$telnet->set_host("10.10.5.7");
$telnet->set_port("2002");
if ($telnet->connect() != TELNET_OK) {
printf("Telnet error on connect, %s\n",$telnet->get_last_error());
}
//$telnet->wait_prompt();
if ($telnet->write('SNRD 1' . "\xd") != TELNET_OK) {
printf("Telnet error on write, %s\n",$telnet->get_last_error());
}
echo "3<br>";
$result = $telnet->get_buffer();
echo $result;
print_r($result);
// flush_now();
echo "4<br>";
$telnet->disconnect();
?>
also, are you sure you need \r\n line termination? write is defined as
function write($buffer, $valeurLoggee = "", $ajouterfinLigne = true){
and does
if ($ajouterfinLigne){
$buffer .= "\n";
}
?
Also, did you test the host and port with the command line telnet client? Like
telnet 10.10.5.7 2002
?
Related
I've been looking up how I can debug PHP code in Chrome or Firefox but I can;t really find a solution. This is my PHP:
<?php
if(isset($_POST["data"]))
{
$var = $_POST["data"];
print "your message: " . $_POST["data"];
if(!empty($_POST['ip.data'])){
$data = $_POST['ip.data'];
$fname = mktime() . ".txt";//generates random name
$file = fopen("upload/" .$fname, 'w');//creates new file
fwrite($file, $data);
fclose($file);
}
}
?>
I want to be able to see the output of print "your message: " . $_POST["data"]; or any errors in Chrome or Firefox. I've tried Firefox Quantum that should be able to debug php? Anyways, how can I console log this?
The first step is to recognize that PHP, which is generally a server side language is a completely different context than the browser's console, which is fundamentally Javascript. Thus, to show messages to the browser's console from the server, you will need to find some way to communicate those messages (e.g., errors) to the browser.
At that point, you might consider something as simple as embedding a script tag with your PHP:
function debugToBrowserConsole ( $msg ) {
$msg = str_replace('"', "''", $msg); # weak attempt to make sure there's not JS breakage
echo "<script>console.debug( \"PHP DEBUG: $msg\" );</script>";
}
function errorToBrowserConsole ( $msg ) {
$msg = str_replace('"', "''", $msg); # weak attempt to make sure there's not JS breakage
echo "<script>console.error( \"PHP ERROR: $msg\" );</script>";
}
function warnToBrowserConsole ( $msg ) {
$msg = str_replace('"', "''", $msg); # weak attempt to make sure there's not JS breakage
echo "<script>console.warn( \"PHP WARNING: $msg\" );</script>";
}
function logToBrowserConsole ( $msg ) {
$msg = str_replace('"', "''", $msg); # weak attempt to make sure there's not JS breakage
echo "<script>console.log( \"PHP LOG: $msg\" );</script>";
}
# Convenience functions
function d2c ( $msg ) { debugToBrowserConsole( $msg ); }
function e2c ( $msg ) { errorToBrowserConsole( $msg ); }
function w2c ( $msg ) { warnToBrowserConsole( $msg ); }
function l2c ( $msg ) { logToBrowserConsole( $msg ); }
if ( 'POST' === $_SERVER['REQUEST_METHOD'] ) {
if ( isset( $_POST['data'] ) ) {
d2c( "Your message: {$_POST['data']}"
e2c( "This is an error from PHP" );
w2c( "This is a warning from PHP" );
l2c( "This is a log message from PHP" );
...
}
}
But this will be a fundamentally weak and brittle approach. I would suggest instead tailing your log files on the server directly. If you are after some color, consider using clog, lwatch, or grc:
$ grc tail -f /var/log/syslog
echo "console.log( 'Debug Objects: " . $output . "' );";
I ran through the same problem recently, just couldn't find a simple enough way without installing some large external package.
I first tried the obvious way:
<?php echo "<script>console.log(".$myVar.")<script>" ?>
but it only works with scalar types. For example:
<?php
$arr = [ 'x' => 42 ];
echo "<script>console.log(".$arr.")</script>";
?>
will output to the html
<script>console.log(Array)</script>
a solution to this is to use json_encode on the variable in the php side, then JSON.parse it in the javascript and finally console.log.
However this approach fails to capture non public properties of objects:
<?php
class Test {
private $x = 42;
public $y = 13;
}
$obj = json_encode(new Test());
echo "<script>console.log(JSON.parse('".$obj."'))</script>";
?>
will output to the browser console:
{y: 13}
Because private/protected fields can't be accessed by json_encode.
The solution here is either to add a __toString method to your class where you properly expose those fields as strings, or use some hack like calling var_export then process the output string to make it json_encode-able.
I ended up writing a small helper using the latter approach, and an output prettifier in the javascript side
Leaving the link here if anyone wants to use it.
If you want to see errors on an Ubuntu machine and you run an Apache server, you can constantly monitor and output changes to the error.log file in the apache folder with this command:
tail -f /var/log/apache2/error.log
If you have a server running on apache then this will output any errors occurred.
The tail command simply outputs the last 10 lines of a file and updates when new data is piped into the file.
I hope will help:
ini_set('display_errors', 1);
ini_set('display_startup_errors', 1);
error_reporting(E_ALL);
Try this
<?php
function temp()
{
if(isset($_POST["data"]))
{
$var = $_POST["data"];
print "your message: " . $_POST["data"];
if(!empty($_POST['ip.data'])){
$data = $_POST['ip.data'];
$fname = mktime() . ".txt";//generates random name
$file = fopen("upload/" .$fname, 'w');//creates new file
fwrite($file, $data);
fclose($file);
}
}
}//function
?>
<script>
console.log(".<?php temp(); ?>.");
</script>
On Chrome, you can use phpconsole which works quite well.
If anybody knows of something similar for Firefox Quantum please comment.
How can you mimic a command line run of a script with arguements inside a PHP script? Or is that not possible?
In other words, let's say you have the following script:
#!/usr/bin/php
<?php
require "../src/php/whatsprot.class.php";
function fgets_u($pStdn) {
$pArr = array($pStdn);
if (false === ($num_changed_streams = stream_select($pArr, $write = NULL, $except = NULL, 0))) {
print("\$ 001 Socket Error : UNABLE TO WATCH STDIN.\n");
return FALSE;
} elseif ($num_changed_streams > 0) {
return trim(fgets($pStdn, 1024));
}
}
$nickname = "WhatsAPI Test";
$sender = ""; // Mobile number with country code (but without + or 00)
$imei = ""; // MAC Address for iOS IMEI for other platform (Android/etc)
$countrycode = substr($sender, 0, 2);
$phonenumber=substr($sender, 2);
if ($argc < 2) {
echo "USAGE: ".$_SERVER['argv'][0]." [-l] [-s <phone> <message>] [-i <phone>]\n";
echo "\tphone: full number including country code, without '+' or '00'\n";
echo "\t-s: send message\n";
echo "\t-l: listen for new messages\n";
echo "\t-i: interactive conversation with <phone>\n";
exit(1);
}
$dst=$_SERVER['argv'][2];
$msg = "";
for ($i=3; $i<$argc; $i++) {
$msg .= $_SERVER['argv'][$i]." ";
}
echo "[] Logging in as '$nickname' ($sender)\n";
$wa = new WhatsProt($sender, $imei, $nickname, true);
$url = "https://r.whatsapp.net/v1/exist.php?cc=".$countrycode."&in=".$phonenumber."&udid=".$wa->encryptPassword();
$content = file_get_contents($url);
if(stristr($content,'status="ok"') === false){
echo "Wrong Password\n";
exit(0);
}
$wa->Connect();
$wa->Login();
if ($_SERVER['argv'][1] == "-i") {
echo "\n[] Interactive conversation with $dst:\n";
stream_set_timeout(STDIN,1);
while(TRUE) {
$wa->PollMessages();
$buff = $wa->GetMessages();
if(!empty($buff)){
print_r($buff);
}
$line = fgets_u(STDIN);
if ($line != "") {
if (strrchr($line, " ")) {
// needs PHP >= 5.3.0
$command = trim(strstr($line, ' ', TRUE));
} else {
$command = $line;
}
switch ($command) {
case "/query":
$dst = trim(strstr($line, ' ', FALSE));
echo "[] Interactive conversation with $dst:\n";
break;
case "/accountinfo":
echo "[] Account Info: ";
$wa->accountInfo();
break;
case "/lastseen":
echo "[] Request last seen $dst: ";
$wa->RequestLastSeen("$dst");
break;
default:
echo "[] Send message to $dst: $line\n";
$wa->Message(time()."-1", $dst , $line);
break;
}
}
}
exit(0);
}
if ($_SERVER['argv'][1] == "-l") {
echo "\n[] Listen mode:\n";
while (TRUE) {
$wa->PollMessages();
$data = $wa->GetMessages();
if(!empty($data)) print_r($data);
sleep(1);
}
exit(0);
}
echo "\n[] Request last seen $dst: ";
$wa->RequestLastSeen($dst);
echo "\n[] Send message to $dst: $msg\n";
$wa->Message(time()."-1", $dst , $msg);
echo "\n";
?>
To run this script, you are meant to go to the Command Line, down to the directory the file is in, and then type in something like php -s "whatsapp.php" "Number" "Message".
But what if I wanted to bypass the Command Line altogether and do that directly inside the script so that I can run it at any time from my Web Server, how would I do that?
First off, you should be using getopt.
In PHP it supports both short and long formats.
Usage demos are documented at the page I've linked to. In your case, I suspect you'll have difficulty detecting whether a <message> was included as your -s tag's second parameter. It will probably be easier to make the message a parameter for its own option.
$options = getopt("ls:m:i:");
if (isset($options["s"] && !isset($options["m"])) {
die("-s needs -m");
}
As for running things from a web server ... well, you pass variables to a command line PHP script using getopt() and $argv, but you pass variables from a web server using $_GET and $_POST. If you can figure out a sensible way to map $_GET variables your command line options, you should be good to go.
Note that a variety of other considerations exist when taking a command line script and running it through a web server. Permission and security go hand in hand, usually as inverse functions of each other. That is, if you open up permissions so that it's allowed to do what it needs, you may expose or even create vulnerabilities on your server. I don't recommend you do this unless you'll more experienced, or you don't mind if things break or get attacked by script kiddies out to 0wn your server.
You're looking for backticks, see
http://php.net/manual/en/language.operators.execution.php
Or you can use shell_exec()
http://www.php.net/manual/en/function.shell-exec.php
I cannot seem to get even vaguely the same data from the Python (Which I would prefer to use) and PHP (Which works fine, coded by the host of the website) scripts.
PHP connects to the same location as the Python script.
And before anyone jumps the gun, I know the python script only retrieves a part of the data. But I can't get even vaguely the same data from the server.
Python:
import socket, struct
host,port = 'baystation12.net', 8000
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.connect((host, port))
s.send('status\r\n')
data = s.recv(1024)
s.close()
print 'Received:', repr(data) # >>> Received: '\x00\xc7\x00\x07\x02\xadj\x00\x00\x1c\xf6'
cache,form,listy = "",">H",[]
for i in data:
if cache != "":
listy.append(struct.unpack(form,cache+i))
else:
cache = i
print "Unpacked:",listy # >>> Unpacked: [(199,), (0,), (7,), (2,), (173,), (106,), (0,), (0,), (28,), (246,)]
text = ""
for i in listy:
text += chr(i[0])
print "Text:",text # >>> Text: Ç
#Shows up incorrectly when I try to copy it.
PHP:
#!/usr/bin/php
<?php
function export($addr,$port,$str)
{
if($str{0} != "?") $str = ("?" . $str);
$query = "\x00\x83" . pack("n",strlen($str)+6) . "\x00\x00\x00\x00\x00" . $str . "\x00";
$server = socket_create(AF_INET,SOCK_STREAM,SOL_TCP) or exit('Unable to create export socket; ' . socket_strerror(socket_last_error()));
socket_connect($server,$addr,$port) or exit('Unable to establish socket connection; ' . socket_strerror(socket_last_error()));
$bytessent = 0;
while($bytessent < strlen($query))
{
$result = socket_write($server,substr($query,$bytessent),strlen($query)-$bytessent);
if($result === FALSE) return('Unable to transfer requested data; ' . socket_strerror(socket_last_error()));
$bytessent += $result;
}
$resbuf = '';
while( socket_recv($server, $message,1,0 )){
$resbuf .= $message;
if(strpos($resbuf,"&end")!=FALSE)
{
echo $resbuf;
socket_close($server);
return($resbuf);
}
echo $message;
};
echo $resbuf."\n";
socket_close($server);
}
export("localhost","8000","status");
?>
PHP's output:
version=Baystation+12&mode=extended&respawn=0&enter=1&vote=1&ai=1&host&players=5&player0=CompactNinja&player1=Sick+trigger&player2=SweetJealousy&player3=Cacophony&player4=Anchorshag&end
Any idea why Python gives out nonsensical characters when unpacking the data, while PHP gives out the above.
You're not sending the same query to your server in python.
In python you're sending status
In PHP you're sending something like \x00\x83\x00\x0d\x00\x00\x00\x00\x00\x00?status\x00
If you change your python to more closely imitate the PHP then it works a lot better:
import socket, struct
host,port = 'baystation12.net', 8000
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.connect((host, port))
senddata = "?status"
query = '\x00\x83' + struct.pack(">H", len(senddata)+6) + '\x00'*5 + senddata + '\x00'
s.send(query)
data = s.recv(1024)
print `data`
When I tried that, it printed
'\x00\x83\x00\xe9\x06version=Baystation+12&mode=traitor&respawn=0&enter=1&vote=1&ai=1&host&players=7&player0=Kosherman&player1=Ghazkull&player2=Doug+H.+Nuts&player3=Lord+Braindead&player4=KirbyElder&player5=Master+of+Apples&player6=Cacophony&end=%23end\x00'
Which looks pretty similar to what the PHP was getting.
Try listy.append(struct.unpack(form,cache+i)[0])
You're ending up with a list of 1-element tuples rather than the a list of numbers.
From the docs: http://docs.python.org/library/struct.html#struct.unpack
struct.unpack(fmt, string)
Unpack the string (presumably packed by
pack(fmt, ...)) according to the given format. The result is a tuple
even if it contains exactly one item. The string must contain exactly
the amount of data required by the format (len(string) must equal
calcsize(fmt)).
I'm trying to print the host/ip to the screen. But, it's printing: "Resource id #2" instead. I'm using SSH2_connection(). I read the doc page and know the the function parameters are host, port, methods ... but when I try fread($host), the host/ip is still not printing can someone give me some direction on this? Thanks!
Code:
<?php
if (!function_exists("ssh2_connect")) die("function ssh2_connect doesn't exist");
if(!($ssh = ssh2_connect('10.5.32.12', 22))) {
echo "fail: unable to establish connection\n";
} else {
if(!ssh2_auth_password($ssh, 'root', '********')) {
echo "fail: unable to authenticate\n";
} else {
echo "Okay: Logged in ... ";
$content = fread($ssh); //Line in question (want ip address to show here)
echo "$content <br>"; //Line in quesion
$stream = ssh2_exec($ssh, 'find / -name *.log -o -name *.txt');
stream_set_blocking($stream, true);
$data = '';
while($buffer = fread($stream, 4096)) {
$data .= $buffer;
}
fclose($stream);
echo $data; // user
}
}
?>
I believe you need the parenthesis around the variabls as well when using double quotes. "{$content} <br>"
Have you tested with your own debug methods whether the $content variable contains information? You can set a value for the variable to test whether your echo statement is correct syntax.
$content = fread($ssh);
fread() reads from a file and puts the info into a resource handler for use later. I don't think you are using this in the right way currently.
I don't see where $ssh is being defined, but I assume it holds the IP you are wanting to output? If that is the case, just replace
$content = fread($ssh);
With:
echo $ssh;
I am having problem with my IRC Bot script, I have implemented it into my Curl transfer method.
I have a problem, once the IRC bot sends a message to the IRC channel, all of the "echo" at the end of the script does not show and the page hangs. The whole Apache hangs.
<?php
$ircServer = "///";
$ircPort = "6667";
$ircChannel = "#bots";
set_time_limit(0);
$msg = $_POST['msg'];
$paper = $_POST['paper'];
$sizzor = $_POST['sizzor'];
$hand = $_POST['hand'];
$ircSocket = fsockopen($ircServer, $ircPort, $eN, $eS);
if ($ircSocket)
{
fwrite($ircSocket, "USER Lost rawr.test lol :code\n");
fwrite($ircSocket, "NICK Rawr" . rand() . "\n");
fwrite($ircSocket, "JOIN " . $ircChannel . "\n");
ignore_user_abort(TRUE); // Noob Close down page
fwrite($ircSocket, "PRIVMSG " . $ircChannel . " :" . $msg . "\n");
while(1)
{
while($data = fgets($ircSocket, 128))
{
echo nl2br($data);
flush();
// Separate all data
$exData = explode(' ', $data);
// Send PONG back to the server
if($exData[0] == "PING")
{
fwrite($ircSocket, "PONG ".$exData[1]."\n");
}
}
echo $eS . ": " . $eN;
}
}
?>
if ($bootcontents == 'success') {
echo '<center><marquee behavior="alternate" direction="left">Spinning xxx at ' . $power . '% power.</marquee></center>';
This part does not show during the script:
if ($bootcontents == 'success') {
echo '<center><marquee behavior="alternate" direction="left">Spinning xxx at ' . $power . '% power.</marquee></center>';
The page just hangs, if I add the exit(); function onto near the top the whole "echo" info does not show.
Please can someone help.
You are creating an infinite loop:
while (1)
// ...
This loop can never finish, since you did not use an exit statement (like break). Therefore the code after the infinite loop is never executed.
Furthermore is it a busy loop (using a lot of CPU resources), so the whole apache (and computer) will hang.
You're leaving some lines out of the <?php ?> tags, so whatever is outside them will be treated as plain text. You fix it moving the closing ?> tags further down:
[this is the while(1) closing bracket]
}
// code past this line will never run, see below for details
echo $eS . ": " . $eN;
}
}
if ($bootcontents == 'success') {
echo '<center><marquee behavior="alternate" direction="left">Spinning xxx at ' . $power . '% power.</marquee></center>';
}
?> <!-- closing tag goes here -->
The page would anyway not work properly because the while(1) loop is missing an exit condition:
while(1) {
while($data = fgets($ircSocket, 128)) {
// ...
}
}
After the inner while finishes, your script keeps looping, ending up trapped in an empty, infinite loop (which would hang the server up, if it's not configured to detect and kill this kind of loophole).
On a final notice, PHP isn't probably the best tool for the job: you would be much better off with a stand-alone application.
while($data = fgets($ircSocket, 128))
This part blocks the script running until it receives data, and if somehow you're not getting data through that socket... well you're stuck there... forever... lol ok, stuck until the PHP script times out.
If that part doesn't catch, you're still stuck inside the while loop and so there is no way of ever running the part of your code that echos stuff out... so both apfelbox and Alex are correct, just not explained fully...
In order to have a infinite loop but also be able to run code outside, you would need to catch the "event" in which you want to capture and run code. All the events you want to capture would need to sit inside the while loop, or at least dispatched from the while loop to a function that would parse the input from server and respond correctly.
An even better way to do this is to utilise the observer pattern.
I really wouldn't make an IRC bot with PHP, even if you run it via commandline... PHP isn't meant to run as a long-running application.