Skip to content

Instantly share code, notes, and snippets.

@ethaniel
Last active March 1, 2024 12:46
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save ethaniel/bfebaaf8b65390bb3020e92f7534ee63 to your computer and use it in GitHub Desktop.
Save ethaniel/bfebaaf8b65390bb3020e92f7534ee63 to your computer and use it in GitHub Desktop.
Simple FTP Server written in PHP to receive images from Hikvision cameras
<?php
require __DIR__ . '/vendor/autoload.php';
use Amp\Loop;
use Amp\Socket\Socket;
use function Amp\asyncCall;
$port1 = 1021; // Primary FTP port (you list it in Hikvision), it receives FTP commands
$port2 = 1022; // Secondary FTP port (for receiving binary data - images)
$sockets = 0;
// this script will automatically exit if you update it
$mymtime = filemtime(__FILE__);
Loop::repeat(5000, static function () {
asyncCall(function () {
if ($GLOBALS["sockets"] == 0) {
clearstatcache();
if (filemtime(__FILE__) != $GLOBALS["mymtime"]) {
echo "version changed, exiting" . PHP_EOL;
Loop::stop();
}
}
});
});
// Start main loop
Loop::run(static function () {
// First port to receive FTP commands
asyncCall(function () {
$clientHandler = function (Socket $socket) {
$GLOBALS["sockets"]++;
$address = $socket->getRemoteAddress();
$socket->write("220 Hello" . PHP_EOL); //yield
echo "starting waiting for data from " . $address->getPort() . PHP_EOL;
while (null !== $chunk = yield $socket->read()) {
$response = "";
if (preg_match('#^USER#', $chunk)) {
$response = "331 Please specify the password.";
} elseif (preg_match('#^PASS#', $chunk)) {
$response = "230 Login successful.";
} elseif (preg_match('#^PWD#', $chunk)) {
$response = '257 "root" is cwd.';
} elseif (preg_match('#^NOOP#', $chunk)) {
$response = '421 OK.';
} elseif (preg_match('#^TYPE#', $chunk)) {
$response = "200 Switching to Binary mode.";
} elseif (preg_match('#^CWD#', $chunk)) {
$response = "250 Directory successfully changed.";
} elseif (preg_match('#^PASV#', $chunk)) {
$floor = floor($GLOBALS["port2"] / 256);
$remainder = $GLOBALS["port2"] - 256 * $floor;
$response = "227 Entering Passive Mode (172,17,0,2,$floor,$remainder).";
} elseif (preg_match('#^PORT#', $chunk)) {
$response = "500 Illegal PORT command.";
} elseif (preg_match('#^STOR#', $chunk)) {
//$response = "425 Use PORT or PASV first.";
$response = "150 Accepted, please start" . PHP_EOL . "226 Successfully transferred";
} elseif (preg_match('#^QUIT#', $chunk)) {
$response = "221 Goodbye.";
}
if (empty($response)) {
echo $address->getPort() . " < " . strlen($chunk) . " bytes";
if (strlen($chunk) < 50) {
echo ": " . substr($chunk, 0, 10);
}
echo PHP_EOL;
} else {
echo $address->getPort() . " < " . $chunk;
echo $address->getPort() . " > " . $response . PHP_EOL;
echo PHP_EOL;
yield $socket->write($response . PHP_EOL);
}
}
$address = $socket->getRemoteAddress();
echo "connection closed with " . $address->getPort() . PHP_EOL;
$GLOBALS["sockets"]--;
};
$server = Amp\Socket\Server::listen('0.0.0.0:' . $GLOBALS["port1"]);
echo 'Listening for new connections on ' . $server->getAddress() . ' ...' . PHP_EOL;
while ($socket = yield $server->accept()) {
$address = $socket->getRemoteAddress();
echo "got connection from " . $address->getPort() . PHP_EOL;
asyncCall($clientHandler, $socket);
}
});
// The second port for receiving images
asyncCall(function () {
$uploadHandler = function (Socket $socket) {
$GLOBALS["sockets"]++;
$address = $socket->getRemoteAddress();
$data = "";
while (null !== $chunk = yield $socket->read()) {
$data .= $chunk;
}
$bytes = strlen($data);
$address = $socket->getRemoteAddress();
echo "upload connection closed with " . $address->getPort() . " (" . $bytes . " bytes received)" . PHP_EOL;
if ($bytes > 1000) {
// bytes is your image
}
$GLOBALS["sockets"]--;
};
$server = Amp\Socket\Server::listen('0.0.0.0:' . $GLOBALS["port2"]);
echo 'Listening for new connections on ' . $server->getAddress() . ' ...' . PHP_EOL;
while ($socket = yield $server->accept()) {
$address = $socket->getRemoteAddress();
echo "got upload connection from " . $address->getPort() . PHP_EOL;
asyncCall($uploadHandler, $socket);
}
});
});
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment