I have a php code which will ssh to a remote machine and execute a shell script to get list of folders. The remote machine contain more than 300 folders in the specified path in the shell script.Shell script executes well and return the list of all folders.But while I retrieve this output in php, I'am getting only around 150, 200 number of folders.
Here is my php code,
<?php
if (!function_exists("ssh2_connect")) die("function ssh2_connect doesn't exist");
if(!($con = ssh2_connect("ip.add.re.ss", "port")))
{
echo "fail: unable to establish connection";
}
else
{
if(!ssh2_auth_password($con, "username", "password"))
{
echo "fail: unable to authenticate";
}
else
{
$stream = ssh2_exec($con, "/usr/local/listdomain/listproject.sh");
stream_set_blocking($stream, true);
$item = fread($stream,4096);
$items = explode(" ", $item);
print_r($items);
}
}
?>
And this is my shell script.
#!/bin/bash
var=$(ls /home);
echo $var;
What is the issue with php here. Is there any limit in array size in php while getting data dynamically like here.Please advise as I am very beginner to PHP.
Thanks.
You're only reading one block of 4096 characters from your stream. if your folder list is longer than this you'll lose the rest. You need something like this:
stream_set_blocking($stream, true);
$item = "";
// continue reading while there's more data
while ($input = fread($stream,4096)) {
$item .= $input;
}
$items = explode(" ", $item);
print_r($items);
You asked fread() to only read 4096 bytes. In the examples portion of fread()’s documentation, it is suggested that stream_get_contents() be used for reading a file handle out to its end. Otherwise, you have to use a loop and keep on reading data until feof($stream) returns FALSE.
Related
I am trying to do remote tailing using phpseclib. I manged to do this using the following code:
<?php
include('Net/SSH2.php');
include('Crypt/RSA.php');
$server = $_POST['server'];
$ssh = new Net_SSH2($server);
$key = new Crypt_RSA();
$key->loadKey(file_get_contents('/home/{username}/.ssh/id_rsa'));
if (!$ssh->login('{username}', $key)) {
exit('Login Failed');
}
$tail="tail -n 1 {some lof file}";
while ($ssh->isConnected()) {
$ssh->exec(
$tail, function ($str) {
echo $str;
echo "<br>";
flush();
ob_flush();
}
);
}
?>
The problem with the code above is that it logs duplicate entries and I was told that it will not read the log file fast enough if we had to change our log file debug level. It was recommended that I look at ssh2_fetch_stream. I tried this but am honestly very confused. This is my code at the moment:
<?php
include('Net/SSH2.php');
include('Crypt/RSA.php');
$host = $_POST['server'];
$username = "{username}";
$publicKey = "/home/{username}/.ssh/id_rsa.pub";
$privateKey = "/home/{username}/.ssh/id_rsa";
$log = "{some log file}";
$conn = ssh2_connect($host);
if (ssh2_auth_pubkey_file($conn, $username, $publicKey, $privateKey)){
$stream = ssh2_exec($conn, 'tail -n 1 {some log file}');
$stream_out = ssh2_fetch_stream($stream, SSH2_STREAM_STDIO);
if (ob_get_level() == 0)
ob_start();
while ($stream_out) {
$line = fgets($stream_out);
echo $line.'<br />';
ob_flush();
flush();
sleep(1);
}
fclose($stream_out);
ob_end_flush();
}
?>
The above code only prints one line since I am not sure how to do the loop since I can't use "while ($ssh->isConnected())" anymore. I think it is looping but not looping what it is supposed to. Unfortunately because of this I can't test if this would read the log file fast enough.
Any help or pointers will be very much appreciated. I hope this solution will work because I am not allowed to install anything on the remote server who's log file I am supposed to tail.
I was told that it will not read the log file fast enough if we had to
change our log file debug level
Whoever told you that is wrong. phpseclib reads what the SSH server sends, which is exactly what libssh2 (or any SSH client for that matter) does.
The problem with the code above is that it logs duplicate entries
That would make sense. tail -n 1 filename shows you the last entry in the log file. If there's a ten minute gap between entries being made and, in that ten minute, you run that command 100 times then you'll see 100 duplicate entries.
My recommendation: do this (with phpseclib):
$ssh->setTimeout(0);
$tail = 'tail -f /path/to/logfile';
$ssh->exec(
$tail, function ($str) {
echo $str;
echo "<br>";
flush();
ob_flush();
}
);
ie. no while loop, no running the same command a zillion times, etc. Just one command, ran once and into perpetuity.
I am using the output of a php file on a remote server, to show content on my own web-site. I do not have access to modify files on the remote server.
The remote php file outputs java script like this:
document.write('<p>some text</p>');
If I enter the url in a browser I get the correct output. E.g:
https://www.remote_server.com/files/the.php?param1=12
I can show the output of the remote file on my website like this:
<script type="text/javascript" src="https://www.remote_server.com/files/the.php?param1=12"></script>
But I would like to filter the output a bit before showing it.
Therefore I implemented a php file with this code:
function getRemoteOutput(){
$file = fopen("https://www.remote_server.com/files/the.php?param1=12","r");
$output = fread($file,1024);
fclose($file);
return $output;
}
When I call this function fopen() returns a valid handle, but fread() returns an empty string.
I have tried using file_get_contents() instead, but get the same result.
Is what I am trying to do possible?
Is it possible for the remote server to allow me to read the file via the browser, but block access from a php file?
Your variable $output is only holding the 1st 1024 bytes of the url... (headers maybe?).
You will need to add a while not the "end of file" loop to concatenate the entire remote file.
PHP reference: feof
You can learn a lot more in the PHP description for the fread function.
PHP reference: fread.
<?php
echo getRemoteOutput();
function getRemoteOutput(){
$file = fopen("http://php.net/manual/en/function.fread.php","r");
$output = "";
while (!feof($file)){ // while not the End Of File
$output.= fread($file,1024); //reads 1024 bytes at a time and appends to the variable as a string.
}
return $output;
fclose($file);
}
?>
In regards to your questions:
Is what I am trying to do possible?
Yes this is possible.
Is it possible for the remote server to allow me to read the file via
the browser, but block access from a php file?
I doubt it.
I contacted the support team for the site I was trying to connect to. They told me that they do prevent access from php files.
So that seems to be the reason for my problems, and apparently I just cannot do what I tried to do.
For what it's worth, here is the code I used to test the various methods to read file output:
<?php
//$remotefile = 'http://www.xencomsoftware.net/configurator/tracker/ip.php';
$remotefile = "http://php.net/manual/en/function.fread.php";
function getList1(){
global $remotefile;
$output = file_get_contents($remotefile);
return htmlentities($output);
}
function getList2(){
global $remotefile;
$file = fopen($remotefile,"r");
$output = "";
while (!feof($file)){ // while not the End Of File
$output.= fread($file,1024); //reads 1024 bytes at a time and appends to the variable as a string.
}
fclose($file);
return htmlentities($output);
}
function getList3(){
global $remotefile;
$ch = curl_init(); // create curl resource
curl_setopt($ch, CURLOPT_URL, $remotefile); // set url
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); //return the transfer as a string
$output = curl_exec($ch); // $output contains the output string
curl_close($ch); // close curl resource to free up system resources
return htmlentities($output);
}
function getList4(){
global $remotefile;
$r = new HttpRequest($remotefile, HttpRequest::METH_GET);
try {
$r->send();
if ($r->getResponseCode() == 200) {
$output = $r->getResponseBody();
}
} catch (Exception $e) {
echo 'Caught exception: ', $e->getMessage(), "\n";
}
return htmlentities($output);
}
function dumpList($ix, $list){
$len = strlen($list);
echo "<p><b>--- getList$ix() ---</b></p>";
echo "<div>Length: $len</div>";
for ($i = 0 ; $i < 10 ; $i++) {
echo "$i: $list[$i] <br>";
}
// echo "<p>$list</p>";
}
dumpList(1, getList1()); // doesn't work! You cannot include/requre a remote file.
dumpList(2, getList2());
dumpList(3, getList3());
dumpList(4, getList4());
?>
I am writing a program in php to check ip's , now I know that are easier ways to do so, but i want to do it my way. This is what i have written so far
<?php
if($_POST) {
$file=fopen("names.txt","a") or exit("Unable to open file!");
$ipadres=fopen("ip.txt","a") or exit("Unable to open file!");
$name = $_POST['username'];
$file_content = $name. "|";
$ipadres_content = $_SERVER["REMOTE_ADDR"] . "|";
$iparray = array();
$i=0;
fputs($file,$file_content);
fputs($ipadres,$ipadres_content);
while(!feof($ipadres))
{
$iparray = explode("|", fgets($file));
}
fclose($file);
fclose($ipadres);
}
?>
As you can see i tried using a while loop to put the ip-adresses in to an array to check. but when I try to run it it just keeps running until it finally crashes in to this error= Fatal error: Maximum execution time of 30 seconds exceeded.Oh and yes i tried to put the max crash limit up a bit but still no sign of succes.
Your while loop is faulty:
while(!feof($ipadres))
{
$iparray = explode("|", fgets($file));
}
You're checking for feof($ipadres) and using fgets($file)
i.e. you keep checking end of file with file pointer $ipadres but reading from file pointer $file which will cause infinite loop and program will crash eventually.
Probably you meant:
while(!feof($ipadres)) {
$iparray = explode("|", fgets($ipadres));
}
OR else use file function which returns all the lines of a file in an array.
I've been struggling with writing a single string into a file.
I'm using just a simple code under Slackware 13:
$fp = fopen('/my/absolute/path/data.txt', 'w');
fwrite($fp, 'just a testing string...');
fclose($fp);
The file gets created (if it's not already created) but it's empty ?!
The directory in which this file is written is owned by apache's user & group (daemon.daemon) and has 0777 permissions.
This has never happened to me before. I'm curious what's the reason I'm not able to write inside the file ?
Thanks in advance.
Try $ df -h
It probably means your disk is full.
In my opinion you could check the return values:
$fp = fopen('/my/absolute/path/data.txt', 'w');
// $fp -> manual: "Returns a file pointer resource on success, or FALSE on error."
if ($fp) {
$bytes_written = fwrite($fp, 'just a testing string...');
if ($bytes_written) {
echo "$bytes_written bytes written!\n";
} else {
echo "Error while writing!\n"
}
$success = fclose($fp);
if ($success) {
echo "File successfully closed!\n";
} else {
echo "Error on closing!\n";
}
} else {
echo "No filepointer ressource!\n";
}
I suggest using file_put_conents($file_name, $file_cotents);
And to retrieve content: file_get_contents($file_name);
Code looks cleaner too.
http://php.net/manual/en/function.file-put-contents.php and
http://www.php.net/manual/en/function.file-get-contents.php
Could be something is happening to the script/file before the file is closed. Check if there are any other processes that try to access the file (you can use lsof). Also try writing to a new file to see if the same thing occurs.
Also, check the return value on fclose() to make sure the file is being closed successfully.
I am working on a tool that reads an iptables configuration from a remote host over SSH2 using the PECL SSH2 extension. I am able to successfully make the connection to the host, authenticate, and execute commands. The trouble I am having is sometimes the stream doesn't contain any data.
/**
* Load the current firewall configuration
* #return bool
*/
public function loadRules() {
$stream = ssh2_exec($this->connection,"~/iptsave;");
stream_set_blocking($stream,true);
$iptablesSave = stream_get_contents($stream);
if(empty($iptablesSave)) {
return false;
}
parent::restore($iptablesSave);
return true;
}
About 25% of the time, loadRules() returns false, even when connecting to locahost instead of the remote system. I was able to work around the problem by changing the ssh2_exec call to
$stream = ssh2_exec($this->connection,"~/iptsave; sleep .5");
but I am concerned that something is wrong.
phpSecLib may be able to help:
According to this post, it always returns the output, unlike ssh2.so.
I've got the same issue here. Somehow you need to set a delay for getting the result of the stream.
The way you've done it is possible, but you could also set a sleep(1) after the stream_set_block($stream, true) function.
You could try the usleep() function. Haven't tried it yet
May be this will solve the issue:
$stream = ssh2_exec($this->connection,"~/iptsave;");
stream_set_blocking($stream,true);
$stream_out = ssh2_fetch_stream($stream, SSH2_STREAM_STDIO);
$iptablesSave = stream_get_contents($stream);
With some severs you have to use 'interactive shell'. And sometimes you have to set the delay / sleep manually. A working example:
$connection = ssh2_connect($IP, 22);
$auth = ssh2_auth_password($connection, $User, $Pass);
$cmd = "help" . PHP_EOL;
if (!$auth) {
echo "Login Failed;
exit(1);
}
$shell = ssh2_shell($connection);
stream_set_blocking($shell, false); // we will use manual sleep
sleep(1); // This sleep to make sure that you get the prompt back
fwrite ($shell, $cmd . ";" . PHP_EOL);
sleep(1); // This to make sure that the command executes and we get the prompt back again!
while($output = fgets($shell)){
echo $output;
}
fwrite ($shell, "exit;" . PHP_EOL); // If needed
sleep(1);
ssh2_disconnect($connection);
unset($shell);
unset($connection);