Create Directory List by FTP & PHP then move files between servers using FTP
I was doing a project where I had to scan a directory on a server and list the files in there, I would then need to compare these to the imported files to see if there was any new entries. If a new entry appeared I would copy it to another server. I also had no control over the two servers, I couldn't find much help online so thought this class may benefit someone someday.Create Table For Comparison
Safest way for comparison is to create a MySQL table to stores the file names, as files can be deleted causing issues with comparisons.CREATE TABLE ftp_import (
id INT(6) UNSIGNED AUTO_INCREMENT PRIMARY KEY,
file_name VARCHAR(128) NOT NULL,
successful int(1) DEFAULT 0,
import_date TIMESTAMP
)
The Class
* @license No License
* @link /cron_jobs/runCron/GetAndMoveReport
* @since Class available since 09/12/2017
*/
Class GetAndMoveReport
{
protected $ch;
//Server Details of the server where the file you will be retreiving is
protected $exportFtpHost = '012.345.678.901';
protected $exportPort = '22';
protected $exportFtpUserName = 'Username';
protected $exportFtpPassword = 'password';
protected $exportFtpRemoteFolder = '/Root/SubFolder/';
protected $exportFtpRemoteFile = '';
protected $exportConnection;
//Server Details of the file you will be pushing up to
protected $chImport;
protected $importFtpHost = '098.765.432.109';
protected $importPort = '22';
protected $importFtpUserName = 'username';
protected $importFtpPassword = 'password';
protected $importFtpRemoteFolder = '';
protected $importFtpRemoteFile = '';
protected $filesOnServerForExport = array();
protected $dbCSVImportFiles = array();
/**
* A Cron Job to build Import CSVs.
*
* A *description*,
*/
public function __construct()
{
$this->importFilesFromCsvTable();
$this->attemptLoginAndScanServer();
}
/**
* Create the Curl Host
*
* @return void
*/
public function createCurlHostExport()
{
$this->ch = curl_init('sftp://' . $this->exportFtpHost . ':' . $this->exportPort . $this->exportFtpRemoteFolder . '/' . $this->exportFtpRemoteFile);
curl_setopt($this->ch, CURLOPT_USERPWD, $this->exportFtpUserName . ':' . $this->exportFtpPassword);
}
/**
* Create the Curl Host
*
* @return void
*/
public function createCurlHostImport()
{
$this->chImport = curl_init('ftp://' . $this->importFtpHost . ':' . $this->importPort . $this->importFtpRemoteFolder. '/' . $this->importFtpRemoteFile);
curl_setopt($this->chImport, CURLOPT_USERPWD, $this->importFtpUserName . ':' . $this->importFtpPassword);
}
/**
* Create the Curl Login
*
* @return void
*/
public function attemptLoginAndScanServer()
{
$this->createCurlHostExport();
//Tell Curl just to scan Directory and return the values
curl_setopt($this->ch, CURLOPT_FTPLISTONLY, true);
curl_setopt($this->ch, CURLOPT_RETURNTRANSFER, 1);
//This assigns the folder contents as a string to $response
$response = curl_exec($this->ch);
//This removes the fodler structure from the beginning . ..
$response = substr($response, 5);
//This removes the white space from the start and end
$response = trim($response);
//Changes the spaces between the file names into /n
$response = json_encode($response);
//Create an array of the file names
$response = explode('\n', $response);
curl_close($this->ch);
if ($response) {
//Assign all the files to a global array
$this->filesOnServerForExport = $response;
//Run the checks to see if its been imported
$this->checkIfFilehasNotBeenExported();
} else {
echo "Failure";
}
}
/**
* Get the files from the CSV Imports Table
*
* @return void
*/
public function importFilesFromCsvTable()
{
$query = mysql_query("SELECT file_name FROM csv_import");
$numRows= mysql_num_rows($query);
if ($numRows > 0) {
while ($row = mysql_fetch_assoc($query)) {
array_push($this->dbCSVImportFiles, $row['file_name']);
}
}
}
/**
* Check if the file already exists in the DB
*
* @return void
*/
public function checkIfFilehasNotBeenExported()
{
//Get the difference between the two arrays, if any left over then we need to import them
$result=array_diff($this->filesOnServerForExport, $this->dbCSVImportFiles);
if (count($result) > 0) {
foreach ($result as $fileName) {
//Insert into table so it cannot be run again
$this->sortFileInCsvTable($fileName, 0);
$this->getFileFromServer($fileName);
$this->sendFileToServer($fileName);
}
}
}
/**
* Insert into csvimport if importing set as 0 successful until import is done
*
* @param string $fileName Filename to Insert.
* @param int $status Status of import to Insert.
*
* @return void
*/
public function sortFileInCsvTable($fileName, $status)
{
if ($status == 0) {
$query = mysql_query("INSERT INTO csv_import (file_name, successful) VALUES ('$fileName', 0)");
} else if ($status == 1) {
$query = mysql_query("UPDATE csv_import SET successful = 1 WHERE file_name = '$fileName'");
}
}
/**
* Get File From Server
*
* @param string $fileName Filename to Get
*
* @return void
*/
public function getFileFromServer($fileName)
{
//Here is the file we are downloading, replace spaces with %20
$this->exportFtpRemoteFile = str_replace(" ", "%20", $fileName);
$this->createCurlHostExport();
//Allows Large File Downloads
set_time_limit(0);
//This is the file where we save the temp file
$fp = fopen(dirname(__FILE__) . '/tempFiles/'.$fileName.'.csv', 'w+');
curl_setopt($this->ch, CURLOPT_TIMEOUT, 50);
// write curl response to file
curl_setopt($this->ch, CURLOPT_FILE, $fp);
curl_setopt($this->ch, CURLOPT_FOLLOWLOCATION, true);
// get curl response
curl_exec($this->ch);
curl_close($this->ch);
fclose($fp);
}
/**
* Get File From Server
*
* @param string $fileName Filename to Send.
*
* @return void
*/
public function sendFileToServer($fileName)
{
$this->createCurlHostImport();
//Change the .csv to represent whatever file you are using
$dataFile = dirname(__FILE__) . '/tempFiles/'.$fileName.'.csv';
//Allows Large File Uploads
set_time_limit(0);
$fh = fopen($dataFile, 'r');
if ($fh) {
curl_setopt($this->chImport, CURLOPT_UPLOAD, true);
curl_setopt($this->chImport, CURLOPT_PROTOCOLS, CURLPROTO_SFTP);
curl_setopt($this->chImport, CURLOPT_INFILE, $fh);
curl_setopt($this->chImport, CURLOPT_INFILESIZE, filesize($dataFile));
curl_setopt($this->chImport, CURLOPT_VERBOSE, true);
$verbose = fopen('php://temp', 'w+');
curl_setopt($this->chImport, CURLOPT_STDERR, $verbose);
$response = curl_exec($this->chImport);
$error = curl_error($this->chImport);
curl_close($this->chImport);
if ($response) {
$this->sortFileInCsvTable($fileName, 1);
unlink($dataFile);
echo "Success";
} else {
echo "Failure
";
rewind($verbose);
$verboseLog = stream_get_contents($verbose);
echo "Verbose information:
" . $verboseLog . "\n";
}
}
}
}
new GetAndMoveReport();
Issues & Resolutions
I was trying to try on another server which wasn't working and I was receiving the following error.Remembering we are in dir "" * Uploaded unaligned file size (0 out of 5 bytes) * Connection #0 to host 1.2.3.4 left intact
I managed to resolve this by using FTP with file_get_contents and file_put_contents as shown here./**
* Send File File To Server
*
* @param string $fileName Filename to Send.
*
* @return void
*/
public function sendFileToServer($fileName)
{
//Allows Large File Downloads
set_time_limit(0);
$this->importFtpRemoteFile = $fileName;
$remote_file = 'ftp://' . $this->importFtpUserName.':'.$this->importFtpPassword.'@'.$this->importFtpHost . ':' . $this->importPort . $this->importFtpRemoteFolder. '/' . $this->importFtpRemoteFile;
$file_contents = file_get_contents(dirname(__FILE__) . '/tempFiles/'.$fileName);
file_put_contents($remote_file, $file_contents);
unlink(dirname(__FILE__) . '/tempFiles/'.$fileName);
}
Categories: Posts