Skip to content

Commit 118f0c6

Browse files
initital commit allowing sync folder to remote via SCP
1 parent 06053b9 commit 118f0c6

File tree

9 files changed

+192
-1
lines changed

9 files changed

+192
-1
lines changed

Docs/Examples/Linux.php

+12
Original file line numberDiff line numberDiff line change
@@ -41,4 +41,16 @@ public function getConnection()
4141
}
4242
return $this->_ctrlObj;
4343
}
44+
public function copyFolderWithScp()
45+
{
46+
$srcDir = "/tmp/myFiles";
47+
$dstDir = "/tmp/remoteFiles";
48+
$remoteHost = "10.20.30.40";
49+
$username = "myUser";
50+
$password = "secret";
51+
$port = 22;
52+
53+
return $this->getConnection()->scpFolderByPassword($srcDir, $dstDir, $remoteHost, $username, $password, $port);
54+
}
55+
4456
}

Factories.php

+7
Original file line numberDiff line numberDiff line change
@@ -15,4 +15,11 @@ public static function getShells()
1515
}
1616
return self::$_cStore[__FUNCTION__];
1717
}
18+
public static function getFiles()
19+
{
20+
if (array_key_exists(__FUNCTION__, self::$_cStore) === false) {
21+
self::$_cStore[__FUNCTION__] = new \MTM\SSH\Factories\Files();
22+
}
23+
return self::$_cStore[__FUNCTION__];
24+
}
1825
}

Factories/Files.php

+14
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
<?php
2+
//© 2019 Martin Peter Madsen
3+
namespace MTM\SSH\Factories;
4+
5+
class Files extends Base
6+
{
7+
public function getScpTool()
8+
{
9+
if (array_key_exists(__FUNCTION__, $this->_s) === false) {
10+
$this->_s[__FUNCTION__] = new \MTM\SSH\Tools\Files\SCP\Zstance();
11+
}
12+
return $this->_s[__FUNCTION__];
13+
}
14+
}

Factories/Shells.php

+1
Original file line numberDiff line numberDiff line change
@@ -97,6 +97,7 @@ protected function getBaseShell()
9797
$strCmd = "trap \"trap - SIGCHLD; echo mtm-forced-exit; exit\" SIGCHLD";
9898
$ctrlObj->getCmd($strCmd)->get();
9999
return $ctrlObj;
100+
100101
} else {
101102
throw new \Exception("Not handled");
102103
}

Models/Shells/Bash/Actions.php

+14-1
Original file line numberDiff line numberDiff line change
@@ -4,5 +4,18 @@
44

55
class Actions extends \MTM\Shells\Models\Shells\Bash\Actions
66
{
7-
7+
public function scpFolderByPassword($srcDir, $dstDir, $ip, $userName, $password, $port=22, $timeout=30000)
8+
{
9+
if (is_object($srcDir) === false) {
10+
$srcDir = \MTM\FS\Factories::getDirectories()->getDirectory($srcDir);
11+
}
12+
if (is_object($dstDir) === false) {
13+
$dstDir = \MTM\FS\Factories::getDirectories()->getDirectory($dstDir);
14+
}
15+
if (is_object($ip) === false) {
16+
$ip = \MTM\Network\Factories::getIp()->getIpFromString($ip);
17+
}
18+
$scpTool = \MTM\SSH\Factories::getFiles()->getScpTool();
19+
return $scpTool->passwordCopy($this, $srcDir, $dstDir, $ip, $userName, $password, $port, $timeout);
20+
}
821
}

Tools/Files/Base.php

+8
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
<?php
2+
//© 2022 Martin Peter Madsen
3+
namespace MTM\SSH\Tools\Files;
4+
5+
abstract class Base
6+
{
7+
8+
}

Tools/Files/SCP/Base.php

+16
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
<?php
2+
//© 2022 Martin Peter Madsen
3+
namespace MTM\SSH\Tools\Files\SCP;
4+
5+
abstract class Base extends \MTM\SSH\Tools\Files\Base
6+
{
7+
public function passwordCopy($ctrlObj, $srcDir, $dstDir, $ip, $userName, $password, $port=22, $timeout=30000)
8+
{
9+
if ($ctrlObj instanceof \MTM\SSH\Models\Shells\Bash\Actions === true) {
10+
return $this->bashPasswordCopy($ctrlObj, $srcDir, $dstDir, $ip, $userName, $password, $port, $timeout);
11+
} else {
12+
throw new \Exception("Not handled for ctrl class");
13+
}
14+
}
15+
16+
}

Tools/Files/SCP/PasswordCopy.php

+112
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,112 @@
1+
<?php
2+
//© 2022 Martin Peter Madsen
3+
namespace MTM\SSH\Tools\Files\SCP;
4+
5+
abstract class PasswordCopy extends Base
6+
{
7+
protected function bashPasswordCopy($ctrlObj, $srcDir, $dstDir, $ipObj, $userName, $password, $port, $timeout)
8+
{
9+
//NOTES:
10+
//the -T option is needed to correct an issue when connecting to Windows OPENSSH
11+
//but we cannot set it or connections to linux/routeros etc have issues
12+
//https://github.com/PowerShell/Win32-OpenSSH/issues/712
13+
14+
$strCmd = "scp";
15+
$strCmd .= " -o NumberOfPasswordPrompts=1";
16+
$strCmd .= " -o ConnectTimeout=" .ceil($timeout / 1000). "";
17+
$strCmd .= " -o UserKnownHostsFile='/dev/null'";
18+
$strCmd .= " -o StrictHostKeyChecking=no";
19+
$strCmd .= " -o GSSAPIAuthentication=no";
20+
$strCmd .= " -P " . $port;
21+
$strCmd .= " -r '" . $srcDir->getPathAsString()."'";
22+
$strCmd .= " ".$userName."@".$ipObj->getAsString("std", false);
23+
$strCmd .= ":'" . $dstDir->getPathAsString()."'";
24+
25+
$regExs = array(
26+
$ipObj->getAsString("std", false) . "'s password:" => "pwAuth",
27+
"No route to host" => "error", //not tested
28+
"Could not resolve hostname" => "error", //not tested
29+
"Connection reset by peer" => "error", //not tested
30+
"Connection timed out" => "error", //ssh: connect to host xx.xx.xx.xx port 22: Connection timed out\nlost connection
31+
"Permission denied" => "error", //tested: Permission denied (password).
32+
"Connection closed by remote host" => "error", //not tested
33+
"Connection refused" => "error", //not tested
34+
);
35+
$regEx = "(" . implode("|", array_keys($regExs)) . ")";
36+
try {
37+
38+
$pad = 5000; //we want the connect error
39+
$cmdObj = $ctrlObj->getCmd($strCmd, $regEx, ($timeout + $pad));
40+
$data = $cmdObj->get();
41+
42+
} catch (\Exception $e) {
43+
//can always peak in $cmdObj->getData() to see what was returned
44+
//this connect is special because bash forms the base for most connects
45+
throw $e;
46+
}
47+
48+
$rValue = null;
49+
$rType = null;
50+
foreach ($regExs as $regEx => $type) {
51+
if (preg_match("/".$regEx."/", $data) == 1) {
52+
$rValue = $regEx;
53+
$rType = $type;
54+
break;
55+
}
56+
}
57+
if ($rType == "pwAuth") {
58+
//login, add more regex options
59+
//cannot include this one above as it will match before the pwAuth
60+
$regExs[preg_quote($ctrlObj->getRegEx())] = "completed";
61+
62+
$strCmd = $password;
63+
$regEx = "(" . implode("|", array_keys($regExs)) . ")";
64+
$cmdObj = $ctrlObj->getCmd($strCmd, $regEx, $timeout)->setTimeout(2592000000); //30 day timeout enough?
65+
66+
$rValue = null;
67+
$rType = null;
68+
$lastHash = "";
69+
$staticCount = 0; //how many times in the loop have we received no change in the return
70+
$maxStatic = 10; //how many time can the output hash to the same thing before we consider the transfer stalled?
71+
$mSleep = 250000; //how many micro secs to sleep each time we are "not done" this + maxStatic makes this more or less responsive (and more or less CPU intensive)
72+
73+
$cmdObj->exec();
74+
while(true) {
75+
$ctrlObj->read($cmdObj);
76+
if ($cmdObj->getIsDone() === false) {
77+
78+
usleep($mSleep); //dont redline the CPU
79+
$curHash = hash("sha256", $cmdObj->getData()); //file name, transfer rate lots can change
80+
if ($curHash != $lastHash) {
81+
$lastHash = $curHash;
82+
$staticCount = 0;
83+
} elseif ($maxStatic > $staticCount) {
84+
$staticCount++;
85+
} else {
86+
$rValue = "Transfer stalled, no change in output. Count: ".$staticCount;
87+
$rType = "error";
88+
break;
89+
}
90+
} else {
91+
//completed
92+
$data = $cmdObj->getData();
93+
foreach ($regExs as $regEx => $type) {
94+
if (preg_match("/".$regEx."/", $data) == 1) {
95+
$rValue = $regEx;
96+
$rType = $type;
97+
break;
98+
}
99+
}
100+
break;
101+
}
102+
}
103+
}
104+
if ($rType == "completed") {
105+
return true;
106+
} elseif ($rType == "error") {
107+
throw new \Exception("Connect error: " . $rValue);
108+
} else {
109+
throw new \Exception("Not Handled: " . $rType);
110+
}
111+
}
112+
}

Tools/Files/SCP/Zstance.php

+8
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
<?php
2+
//© 2022 Martin Peter Madsen
3+
namespace MTM\SSH\Tools\Files\SCP;
4+
5+
class Zstance extends PasswordCopy
6+
{
7+
8+
}

0 commit comments

Comments
 (0)