php sftp file or folder - php

i am attempting to create a web based sftp page, the only part i am having problems with is trying to determin the the listed file is a file or folder. i am sucessfully listing a directory using
$connection = ssh2_connect($_SESSION['Server'], $_SESSION['Port']);
if(ssh2_auth_password($connection, $_SESSION['Username'], $_SESSION['Password']))
{
$sftp = ssh2_sftp($connection);
$dir = "ssh2.sftp://$sftp/$directory";
$handle = opendir($dir);
while (false !== ($file = readdir($handle)))
{
if ($file != "." && $file != "..")
{
$temp=$file;
if(strlen($directory) > 0)
$Path=$directory."/".$file;
else
$Path=$file;
$statinfo = ssh2_sftp_stat($sftp, "/".$Path);
echo "$temp<br />";
}
}
closedir($handle);
}
i attempted to use the is_dir() and is_file() php function on $file which works sucessfully when working on local filesystem, but when using SFTP both come back FALSE, i attempted to use ssh2_sftp_stat() but this only gives uid, gid, size access and modified times and i dont think there is anyting that can be used to identify files of folders, if anyone has a way to resolve this i would appreaciate it greatly
Vip32

I would strongly suggest using phpseclib for SSH2 purposes. It greatly simplifies tasks like this.
Solution for your problem using phpseclib should go something like this:
include('Net/SFTP.php');
$sftp = new Net_SFTP($_SESSION['Server'] . ':' . $_SESSION['Port']);
if (!$sftp->login($_SESSION['Username'], $_SESSION['Password'])) {
exit('Login Failed');
}
foreach($sftp->rawlist($dir) as $filename => $attrs) {
if ($attr['type'] == NET_SFTP_TYPE_REGULAR) {
echo $filename . ' is a regular file!';
}
if ($attr['type'] == NET_SFTP_TYPE_DIRECTORY) {
echo $filename . ' is a directory!';
}
}
These are the file type constants phpseclib uses:
file_types = array(
1 => 'NET_SFTP_TYPE_REGULAR',
2 => 'NET_SFTP_TYPE_DIRECTORY',
3 => 'NET_SFTP_TYPE_SYMLINK',
4 => 'NET_SFTP_TYPE_SPECIAL'
);

Related

Complete list of files and folders in remote server via SFTP

How to list all files recursively in remote server via SFTP in PHP?
opendir or scandir only list in current folder.
phpseclib library has recursive listing built-in, just use Net_SFTP.nlist() with $recursive = true:
set_include_path(get_include_path() . PATH_SEPARATOR . 'phpseclib');
require_once("Net/SFTP.php");
$sftp = new Net_SFTP($hostname);
if (!$sftp->login($username, $password))
{
die("Cannot login to the server");
}
if (!($files = $sftp->nlist($path, true)))
{
die("Cannot read directory contents");
}
foreach ($files as $file)
{
echo "$file\n";
}
If you need to list even the folder names (so that you capture even empty folder), you have to re-implement, what nlist does:
function nlist_with_folders($sftp, $dir)
{
$files = $sftp->rawlist($dir);
if ($files === false)
{
$result = false;
}
else
{
$result = array();
foreach ($files as $name => $attrs)
{
if (($name != ".") && ($name != ".."))
{
$path = "$dir/$name";
$result[] = $path;
if ($attrs["type"] == NET_SFTP_TYPE_DIRECTORY)
{
$sub_files = nlist_with_folders($sftp, $path);
$result = array_merge($result, $sub_files);
}
}
}
}
return $result;
}
The following was/is true about phpseclib 1.0 branch, whose latest release 1.0.19 from 2020 is still usable, but it does not seem to be updated anymore. The phpseclib 2.0 and 3.0 use Composer, so their setup is somewhat more complicated.
phpseclib does not require any installation and does not have any mandatory dependencies. It's a "pure PHP" code. You just download an archive with the PHP code and extract it to your webserver (or extract it locally and upload the extracted code, if you do not have a shell access to the webserver). In my example, I have extracted it to phpseclib subfolder.

How do I copy or move remote files with phpseclib?

I've just discovered phpseclib for myself and would like to use it for my bit of code. Somehow I can't find out how I could copy files from one sftp directory into an other sftp directory. Would be great if you could help me out with this.
e.g.:
copy all files of
/jn/xml/
to
/jn/xml/backup/
$dir = "/jn/xml/";
$files = $sftp->nlist($dir, true);
foreach($files as $file)
{
if ($file == '.' || $file == '..') continue;
$sftp->put($dir."backup".'/'.$file, $sftp->get($dir.'/'.$file));
}
This code will copy contents from "/jn/xml/" directory to "/jn/xml/backup".
To be able to move a file correctly with PHPSeclib, you can use
$sftp->rename($old, $new);
Try this:
<?php
include('Net/SFTP.php');
$sftp = new Net_SFTP('website.com');
if (!$sftp->login('user', 'pass')) {
exit('bad login');
}
$sftp->chdir('/jn/xml/');
$files = $sftp->nlist('.', true);
foreach ($files as $file) {
if ($file == '.' || $file == '..') {
continue;
}
$dir = '/jn/xml/backup/' . dirname($file);
if (!file_exists($dir)) {
mkdir($dir, 0777, true);
}
file_put_contents($dir . '/' . $file, $sftp->get($file));
}
I think this should do what was asked.
I used composer to import phpseclib so this is not exactly the code I tested, but from the other answers, the syntax should be correct.
<?php
include('Net/SFTP.php');
// connection
$sftp = new Net_SFTP('website.com');
if (!$sftp->login('user', 'pass')) {
exit('bad login');
}
// Use sftp to make an mv
$sftp->exec('mv /jn/xml/* /jn/xml/backup/');
Notes:
if any of the directories do not exist, this will fail. do echo $sftp->exec(... to get the errormsg.
you will get a warning because /jn/xml/backup/ is inside /jn/xml/, I would advise moving the files to /jn/xml.bak/
you could use 'Net/SSH2' class, since you only do a mv, and do not transfer any files. In fact, the exec is a function from the SSH2 class, and SFTP inherits it from SSH2.

phpseclib producing strange output

I have code which generates a text file on my server. I then need this file uploaded to another server using sftp. To start things off, I do
if(performLdapOperations()) {
sleep(10);
performFtpOperation();
}
performLdapOperations produces the text file and places it on my server, performFtpOperation takes this text file and uploads to another server. This is my function
function performFtpOperation() {
global $config;
$local_directory = getcwd() .'/outputs/';
$remote_directory = '/home/newfolder/';
$sftp = new SFTP($config::FTP_SERVER, 22, 10);
if (!$sftp->login($config::FTP_USER, $config::FTP_PASSWORD)) {
exit('Login Failed');
}
$files_to_upload = array();
/* Open the local directory form where you want to upload the files */
if ($handle = opendir($local_directory))
{
/* This is the correct way to loop over the directory. */
while (false !== ($file = readdir($handle)))
{
if ($file != "." && $file != "..")
{
$files_to_upload[] = $file;
}
}
closedir($handle);
}
if(!empty($files_to_upload))
{
/* Now upload all the files to the remote server */
foreach($files_to_upload as $file)
{
$success = $sftp->put($remote_directory . $file,
$local_directory . $file,
NET_SFTP_LOCAL_FILE);
}
}
}
So the text file that is produces is in my outputs folder. I then want to take this file and upload to a new server to the location /home/newfolder/
Everything seems to work, and the file seems to get uploaded to the new server. However, when I open the file that has been uploaded, all it contains is the path of where the file is, nothing else. The file on my server which is in the outputs folder contains everything, for some reason something is going wrong when sending it over sftp?
Is there anything in my code that may be causing this?
Thanks
It looks like you're using the 2.0 version of phpseclib, which is namespaced. If that's the case then the problem is with this line:
$success = $sftp->put($remote_directory . $file,
$local_directory . $file,
NET_SFTP_LOCAL_FILE);
Try this:
$success = $sftp->put($remote_directory . $file,
$local_directory . $file,
SFTP::SOURCE_LOCAL_FILE);

Upload Entire Directory via PHP to a remote host via FTP

I'm using Codeigniter to create a web site, and I tried to create a function to upload the entire directory via FTP to a remote host, but nothing is working
I tried 2 functions I found, but also not working, only few files uploaded, and some files size is 0 bytes
Functions Used :
// 1St Function
public function ftp_copy($src_dir, $dst_dir) {
$d = dir($src_dir);
while($file = $d->read()) {
if ($file != "." && $file != "..") {
if (is_dir($src_dir."/".$file)) {
if (!#ftp_chdir($this->conn_id, $dst_dir."/".$file)) {
ftp_mkdir($this->conn_id, $dst_dir."/".$file);
}
ftp_copy($src_dir."/".$file, $dst_dir."/".$file);
}
else {
$upload = ftp_put($this->conn_id, $dst_dir."/".$file, $src_dir."/".$file, FTP_BINARY);
}
}
}
$d->close();
}
// 2nd Solution from Stackoverflow question
foreach (glob("/directory/to/upload/*.*") as $filename)
ftp_put($ftp_stream, basename($filename) , $filename, FTP_BINARY);
Any solution ??
If you are using codeigniter you can use $this->ftp->mirror() from their FTP Library.
http://codeigniter.com/user_guide/libraries/ftp.html
$this->load->library('ftp');
$config['hostname'] = 'ftp.example.com';
$config['username'] = 'your-username';
$config['password'] = 'your-password';
$config['debug'] = TRUE;
$this->ftp->connect($config);
$this->ftp->mirror('/path/to/myfolder/', '/public_html/myfolder/');
$this->ftp->close();

move all files in a folder to another?

when moving one file from one location to another i use
rename('path/filename', 'newpath/filename');
how do you move all files in a folder to another folder? tried this one without result:
rename('path/*', 'newpath/*');
A slightly verbose solution:
// Get array of all source files
$files = scandir("source");
// Identify directories
$source = "source/";
$destination = "destination/";
// Cycle through all source files
foreach ($files as $file) {
if (in_array($file, array(".",".."))) continue;
// If we copied this successfully, mark it for deletion
if (copy($source.$file, $destination.$file)) {
$delete[] = $source.$file;
}
}
// Delete all successfully-copied files
foreach ($delete as $file) {
unlink($file);
}
Please try this solution, it's tested successfully ::
<?php
$files = scandir("f1");
$oldfolder = "f1/";
$newfolder = "f2/";
foreach($files as $fname) {
if($fname != '.' && $fname != '..') {
rename($oldfolder.$fname, $newfolder.$fname);
}
}
?>
An alternate using rename() and with some error checking:
$srcDir = 'dir1';
$destDir = 'dir2';
if (file_exists($destDir)) {
if (is_dir($destDir)) {
if (is_writable($destDir)) {
if ($handle = opendir($srcDir)) {
while (false !== ($file = readdir($handle))) {
if (is_file($srcDir . '/' . $file)) {
rename($srcDir . '/' . $file, $destDir . '/' . $file);
}
}
closedir($handle);
} else {
echo "$srcDir could not be opened.\n";
}
} else {
echo "$destDir is not writable!\n";
}
} else {
echo "$destDir is not a directory!\n";
}
} else {
echo "$destDir does not exist\n";
}
tried this one?:
<?php
$oldfolderpath = "old/folder";
$newfolderpath = "new/folder";
rename($oldfolderpath,$newfolderpath);
?>
So I tried to use the rename() function as described and I kept getting the error back that there was no such file or directory. I placed the code within an if else statement in order to ensure that I really did have the directories created. It looked like this:
$tempDir = '/home/site/images/tmp/';
$permanentDir = '/home/site/images/' . $claimid; // this was stored above
mkdir($permanentDir,0775);
if(is_dir($permanentDir)){
echo $permanentDir . ' is a directory';
if(is_dir($tempDir)){
echo $tempDir . ' is a directory';
}else{
echo $tempDir . ' is not a directory';
}
}else{
echo $permanentDir . ' is not a directory';
}
rename($tempDir . "*", $permanentDir);
So when I ran the code again, it spit out that both paths were directories. I was stumped. I talked with a coworker and he suggested, "Why not just rename the temp directory to the new directory, since you want to move all the files anyway?"
Turns out, this is what I ended up doing. I gave up trying to use the wildcard with the rename() function and instead just use the rename() to rename the temp directory to the permanent one.
so it looks like this.
$tempDir = '/home/site/images/tmp/';
$permanentDir = '/home/site/images/' . $claimid; // this was stored above
mkdir($permanentDir,0775);
rename($tempDir, $permanentDir);
This worked beautifully for my purposes since I don't need the old tmp directory to remain there after the files have been uploaded and "moved".
Hope this helps. If anyone knows why the wildcard doesn't work in the rename() function and why I was getting the error stating above, please, let me know.
Move or copy the way I use it
function copyfiles($source_folder, $target_folder, $move=false) {
$source_folder=trim($source_folder, '/').'/';
$target_folder=trim($target_folder, '/').'/';
$files = scandir($source_folder);
foreach($files as $file) {
if($file != '.' && $file != '..') {
if ($move) {
rename($source_folder.$file, $target_folder.$file);
} else {
copy($source_folder.$file, $target_folder.$file);
}
}
}
}
function movefiles($source_folder, $target_folder) {
copyfiles($source_folder, $target_folder, $move=true);
}
try this:
rename('path/*', 'newpath/');
I do not see a point in having an asterisk in the destination
If the target directory doesn't exist, you'll need to create it first:
mkdir('newpath');
rename('path/*', 'newpath/');
As a side note; when you copy files to another folder, their last changed time becomes current timestamp. So you should touch() the new files.
... (some codes for directory looping) ...
if (copy($source.$file, $destination.$file)) {
$delete[] = $source.$file;
$filetimestamp = filemtime($source.$file);
touch($destination.$file,$filetimestamp);
}
... (some codes) ...
Not sure if this helps anyone or not, but thought I'd post anyway. Had a challenge where I has heaps of movies I'd purchased and downloaded through various online stores all stored in one folder, but all in their own subfolders and all with different naming conventions. I wanted to move all of them into the parent folder and rename them all to look pretty. all of the subfolders I'd managed to rename with a bulk renaming tool and conditional name formatting. the subfolders had other files in them i didn't want. so i wrote the following php script to, 1. rename/move all files with extension mp4 to their parent directory while giving them the same name as their containing folder, 2. delete contents of subfolders and look for directories inside them to empty and then rmdir, 3. rmdir the subfolders.
$handle = opendir("D:/Movies/");
while ($file = readdir($handle)) {
if ($file != "." && $file != ".." && is_dir($file)) {
$newhandle = opendir("D:/Movies/".$file);
while($newfile = readdir($newhandle)) {
if ($newfile != "." && $newfile != ".." && is_file("D:/Movies/".$file."/".$newfile)) {
$parts = explode(".",$newfile);
if (end($parts) == "mp4") {
if (!file_exists("D:/Movies/".$file.".mp4")) {
rename("D:/Movies/".$file."/".$newfile,"D:/Movies/".$file.".mp4");
}
else {
unlink("D:/Movies/".$file."/".$newfile);
}
}
else { unlink("D:/Movies/".$file."/".$newfile); }
}
else if ($newfile != "." && $newfile != ".." && is_dir("D:/Movies/".$file."/".$newfile)) {
$dirhandle = opendir("D:/Movies/".$file."/".$newfile);
while ($dirfile = readdir($dirhandle)){
if ($dirfile != "." && $dirfile != ".."){
unlink("D:/Movies/".$file."/".$newfile."/".$dirfile);
}
}
rmdir("D:/Movies/".$file."/".$newfile);
}
}
unlink("D:/Movies/".$file);
}
}
i move all my .json files from root folder to json folder with this
foreach (glob("*.json") as $filename) {
rename($filename,"json/".$filename);
}
pd: someone 2020?

Categories