Sensibilium
Programmer
Hi,
Not sure if anyone can resolve this, but I've been scratching my head all day.
I am simply trying to upload a file to a remote server using 'ftp_put', I am running PHP 8.2 and using the Symfony 6.2 framework.
The error I received is not related to remote server permissions, as I have code that executes the FTP stuff inside the Controller class which works as expected, I feel this is something to do with the FtpHelper Service class, but I'm not sure how or why. I include both the non-working code (which includes a cut down FtpHelper class), and a follow up piece of code that works, but does not utilise the functions within the FtpHelper class.
Any thoughts on why this might be occuring would be amazing.
This is the failing class (FtpHelper) and calling class (CronDailyController):
Here is the working code from the Controller class:
When I output all the variables from the first example code, everything is as expected (variables, FTP Connection and login), when I call 'dump(error_get_last());' I get the error message as noted in the thread title, 'mkdir(): Permission denied'.
Very strange. I even tried FtpHelper as a class purely containing static functions, but changed it to instantiated in the hope it was related to that, it wasn't.
TIA
Sensibilium
Not sure if anyone can resolve this, but I've been scratching my head all day.
I am simply trying to upload a file to a remote server using 'ftp_put', I am running PHP 8.2 and using the Symfony 6.2 framework.
The error I received is not related to remote server permissions, as I have code that executes the FTP stuff inside the Controller class which works as expected, I feel this is something to do with the FtpHelper Service class, but I'm not sure how or why. I include both the non-working code (which includes a cut down FtpHelper class), and a follow up piece of code that works, but does not utilise the functions within the FtpHelper class.
Any thoughts on why this might be occuring would be amazing.
This is the failing class (FtpHelper) and calling class (CronDailyController):
PHP:
<?php
namespace App\Service;
/**
* FtpHelper
* Provides required information for FTP access
* to various scripts
*/
class FtpHelper {
const WEBSITE = 0;
const WEBSITE2 = 1;
private static array $websiteFTP = [
'remote_path' => '',
'remote_file' => 'thefile.csv',
'local_path' => '/var/[URL unfurl="true"]www/temp/',[/URL]
'local_file' => 'thefile2.csv',
'hostname' => 'somehost.local',
];
private static array $website2FTP = [
'remote_path' => '',
'remote_file' => 'thefile2.csv',
'local_path' => '/var/[URL unfurl="true"]www/temp/',[/URL]
'local_file' => 'thefile2.csv',
'hostname' => 'somehost2.local',
];
final public static function getWebsiteFTP()
{
return self::$websiteFTP;
}
final public static function getWebsite2FTP()
{
return self::$website2FTP;
}
final public function connectToServer(int $theServer, string &$theUser, string &$thePass): \FTP\Connection|false
{
$serverDetails = self::getServerDetails($theServer);
$ftpConnect = ftp_connect($serverDetails['hostname']);
unset($serverDetails);
if ($ftpConnect) {
if (ftp_login($ftpConnect, $theUser, $thePass)) {
return $ftpConnect;
}
}
return false;
}
final public function setPassiveMode(\FTP\Connection &$conn): bool
{
// Set FTP Passive mode
return ftp_pasv($conn, true);
}
final public function uploadToServer(int $theServer, \FTP\Connection &$conn): bool
{
$serverDetails = self::getServerDetails($theServer);
$filepath = $serverDetails['remote_path'].'/'.$serverDetails['remote_file'];
$localfile = $serverDetails['local_file'];
unset($serverDetails);
// Upload the temp csv file via FTP
// TODO Upload fails here with 'mkdir(): Permission denied'
return ftp_put($conn, $filepath, $localfile, FTP_ASCII);
}
final public function closeConnection(\FTP\Connection &$conn): bool
{
// Close the FTP connection
return ftp_close($conn);
}
private function getServerDetails(int &$theServer): array
{
return match($theServer) {
self::WEBSITE => self::$websiteFTP,
self::WEBSITE2 => self::$website2FTP,
};
}
}
class CronDailyController extends AbstractController
{
// See config/services.yaml when adding more secrets
private $websiteFtpPassword;
private $websiteFtpUsername;
private $website2FtpPassword;
private $website2FtpUsername;
public function __construct(
$websiteFtpPassword, $websiteFtpUsername,
$website2FtpPassword, $website2FtpUsername,
) {
$this->websiteFtpPassword = $websiteFtpPassword[0];
$this->websiteFtpUsername = $websiteFtpUsername[0];
$this->website2FtpPassword = $website2FtpPassword[0];
$this->website2FtpUsername = $website2FtpUsername[0];
}
#[Route(path: '/cron/update-stock', name: 'app_cron_update_stock', methods: ['GET'])]
public function updateStock(
try {
$ftpUser = $this->websiteFtpUsername;
$ftpPass = $this->websiteFtpPassword;
// Prepare to FTP file to server
$ftpResult = $ftpHelper->connectToServer(FtpHelper::WEBSITE, $ftpUser, $ftpPass);
if (!$ftpResult) {
$output .= '[ERROR] stocks failed ';
$output .= '(Could not connect to FTP server)'."\n";
return new Response($output);
}
$ftpPassive = $ftpHelper->setPassiveMode($ftpResult);
if (!$ftpPassive) {
$output .= '[ERROR] stocks failed ';
$output .= '(Could not enable FTP passive mode)'."\n";
return new Response($output);
}
$ftpUpload = $ftpHelper->uploadToServer(FtpHelper::WEBSITE, $ftpResult);
$ftpClosed = $ftpHelper->closeConnection($ftpResult);
} catch (\Exception) {
$output .= '[ERROR] stocks failed ';
$output .= '(General FTP Exception)'."\n";
return new Response($output);
}
}
}
Here is the working code from the Controller class:
PHP:
class CronDailyController extends AbstractController
{
#[Route(path: '/cron/update-stock', name: 'app_cron_update_stock', methods: ['GET'])]
public function updateStock(
try {
$ftpLogin = false;
$ftpConnect = ftp_connect($ftpHost);
if ($ftpConnect) {
$ftpLogin = ftp_login($ftpConnect, $ftpUser, $ftpPass);
}
// Set FTP Passive mode
ftp_pasv($ftpConnect, true);
// Upload the temp csv file via FTP
$ftpUpload = ftp_put($ftpConnect, $ftpRemoteDir.'/'.$ftpRemoteFile, $ftpLocalFile, FTP_ASCII);
if (!$ftpUpload) {
ftp_close($ftpConnect);
$output .= '[ERROR] stocks failed ';
$output .= '(Failed to upload file to FTP server)'."\n";
return new Response($output);
}
// Close our FTP connection
ftp_close($ftpConnect);
} catch (\Exception) {
$output .= '[ERROR] stocks failed ';
$output .= '(General FTP Exception)'."\n";
return new Response($output);
}
$output .= '[OK] stocks uploaded '."\n";
return new Response($output);
}
}
When I output all the variables from the first example code, everything is as expected (variables, FTP Connection and login), when I call 'dump(error_get_last());' I get the error message as noted in the thread title, 'mkdir(): Permission denied'.
Very strange. I even tried FtpHelper as a class purely containing static functions, but changed it to instantiated in the hope it was related to that, it wasn't.
TIA
Sensibilium