![]() Server : Apache System : Linux server2.corals.io 4.18.0-348.2.1.el8_5.x86_64 #1 SMP Mon Nov 15 09:17:08 EST 2021 x86_64 User : corals ( 1002) PHP Version : 7.4.33 Disable Function : exec,passthru,shell_exec,system Directory : /home/corals/mautic.corals.io/vendor/knplabs/gaufrette/src/Gaufrette/Adapter/ |
<?php namespace Gaufrette\Adapter; use Gaufrette\Adapter; use Gaufrette\File; use Gaufrette\Filesystem; /** * Ftp adapter. * * @author Antoine Hérault <[email protected]> */ class Ftp implements Adapter, FileFactory, ListKeysAware, SizeCalculator { protected $connection = null; protected $directory; protected $host; protected $port; protected $username; protected $password; protected $passive; protected $create; protected $mode; protected $ssl; protected $timeout; protected $fileData = []; protected $utf8; /** * @param string $directory The directory to use in the ftp server * @param string $host The host of the ftp server * @param array $options The options like port, username, password, passive, create, mode */ public function __construct($directory, $host, $options = []) { if (!extension_loaded('ftp')) { throw new \RuntimeException('Unable to use Gaufrette\Adapter\Ftp as the FTP extension is not available.'); } $this->directory = (string) $directory; $this->host = $host; $this->port = $options['port'] ?? 21; $this->username = $options['username'] ?? null; $this->password = $options['password'] ?? null; $this->passive = $options['passive'] ?? false; $this->create = $options['create'] ?? false; $this->mode = $options['mode'] ?? FTP_BINARY; $this->ssl = $options['ssl'] ?? false; $this->timeout = $options['timeout'] ?? 90; $this->utf8 = $options['utf8'] ?? false; } /** * {@inheritdoc} */ public function read($key) { $this->ensureDirectoryExists($this->directory, $this->create); $temp = fopen('php://temp', 'r+'); if (!ftp_fget($this->getConnection(), $temp, $this->computePath($key), $this->mode)) { return false; } rewind($temp); $contents = stream_get_contents($temp); fclose($temp); return $contents; } /** * {@inheritdoc} */ public function write($key, $content) { $this->ensureDirectoryExists($this->directory, $this->create); $path = $this->computePath($key); $directory = \Gaufrette\Util\Path::dirname($path); $this->ensureDirectoryExists($directory, true); $temp = fopen('php://temp', 'r+'); $size = fwrite($temp, $content); rewind($temp); if (!ftp_fput($this->getConnection(), $path, $temp, $this->mode)) { fclose($temp); return false; } fclose($temp); return $size; } /** * {@inheritdoc} */ public function rename($sourceKey, $targetKey) { $this->ensureDirectoryExists($this->directory, $this->create); $sourcePath = $this->computePath($sourceKey); $targetPath = $this->computePath($targetKey); $this->ensureDirectoryExists(\Gaufrette\Util\Path::dirname($targetPath), true); return ftp_rename($this->getConnection(), $sourcePath, $targetPath); } /** * {@inheritdoc} */ public function exists($key) { $this->ensureDirectoryExists($this->directory, $this->create); $file = $this->computePath($key); $lines = ftp_rawlist($this->getConnection(), '-al ' . \Gaufrette\Util\Path::dirname($file)); if (false === $lines) { return false; } $pattern = '{(?<!->) ' . preg_quote(basename($file)) . '( -> |$)}m'; foreach ($lines as $line) { if (preg_match($pattern, $line)) { return true; } } return false; } /** * {@inheritdoc} */ public function keys() { $this->ensureDirectoryExists($this->directory, $this->create); $keys = $this->fetchKeys(); return $keys['keys']; } /** * {@inheritdoc} */ public function listKeys($prefix = '') { $this->ensureDirectoryExists($this->directory, $this->create); preg_match('/(.*?)[^\/]*$/', $prefix, $match); $directory = rtrim($match[1], '/'); $keys = $this->fetchKeys($directory, false); if ($directory === $prefix) { return $keys; } $filteredKeys = []; foreach (['keys', 'dirs'] as $hash) { $filteredKeys[$hash] = []; foreach ($keys[$hash] as $key) { if (0 === strpos($key, $prefix)) { $filteredKeys[$hash][] = $key; } } } return $filteredKeys; } /** * {@inheritdoc} */ public function mtime($key) { $this->ensureDirectoryExists($this->directory, $this->create); $mtime = ftp_mdtm($this->getConnection(), $this->computePath($key)); // the server does not support this function if (-1 === $mtime) { throw new \RuntimeException('Server does not support ftp_mdtm function.'); } return $mtime; } /** * {@inheritdoc} */ public function delete($key) { $this->ensureDirectoryExists($this->directory, $this->create); if ($this->isDirectory($key)) { return ftp_rmdir($this->getConnection(), $this->computePath($key)); } return ftp_delete($this->getConnection(), $this->computePath($key)); } /** * {@inheritdoc} */ public function isDirectory($key) { $this->ensureDirectoryExists($this->directory, $this->create); return $this->isDir($this->computePath($key)); } /** * Lists files from the specified directory. If a pattern is * specified, it only returns files matching it. * * @param string $directory The path of the directory to list from * * @return array An array of keys and dirs */ public function listDirectory($directory = '') { $this->ensureDirectoryExists($this->directory, $this->create); $directory = preg_replace('/^[\/]*([^\/].*)$/', '/$1', $directory); $items = $this->parseRawlist( ftp_rawlist($this->getConnection(), '-al ' . $this->directory . $directory) ?: [] ); $fileData = $dirs = []; foreach ($items as $itemData) { if ('..' === $itemData['name'] || '.' === $itemData['name']) { continue; } $item = [ 'name' => $itemData['name'], 'path' => trim(($directory ? $directory . '/' : '') . $itemData['name'], '/'), 'time' => $itemData['time'], 'size' => $itemData['size'], ]; if ('-' === substr($itemData['perms'], 0, 1)) { $fileData[$item['path']] = $item; } elseif ('d' === substr($itemData['perms'], 0, 1)) { $dirs[] = $item['path']; } } $this->fileData = array_merge($fileData, $this->fileData); return [ 'keys' => array_keys($fileData), 'dirs' => $dirs, ]; } /** * {@inheritdoc} */ public function createFile($key, Filesystem $filesystem) { $this->ensureDirectoryExists($this->directory, $this->create); $file = new File($key, $filesystem); if (!array_key_exists($key, $this->fileData)) { $dirname = \Gaufrette\Util\Path::dirname($key); $directory = $dirname == '.' ? '' : $dirname; $this->listDirectory($directory); } if (isset($this->fileData[$key])) { $fileData = $this->fileData[$key]; $file->setName($fileData['name']); $file->setSize($fileData['size']); } return $file; } /** * @param string $key * * @return int * * @throws \RuntimeException */ public function size($key) { $this->ensureDirectoryExists($this->directory, $this->create); if (-1 === $size = ftp_size($this->connection, $key)) { throw new \RuntimeException(sprintf('Unable to fetch the size of "%s".', $key)); } return $size; } /** * Ensures the specified directory exists. If it does not, and the create * parameter is set to TRUE, it tries to create it. * * @param string $directory * @param bool $create Whether to create the directory if it does not * exist * * @throws RuntimeException if the directory does not exist and could not * be created */ protected function ensureDirectoryExists($directory, $create = false) { if (!$this->isDir($directory)) { if (!$create) { throw new \RuntimeException(sprintf('The directory \'%s\' does not exist.', $directory)); } $this->createDirectory($directory); } } /** * Creates the specified directory and its parent directories. * * @param string $directory Directory to create * * @throws RuntimeException if the directory could not be created */ protected function createDirectory($directory) { // create parent directory if needed $parent = \Gaufrette\Util\Path::dirname($directory); if (!$this->isDir($parent)) { $this->createDirectory($parent); } // create the specified directory $created = ftp_mkdir($this->getConnection(), $directory); if (false === $created) { throw new \RuntimeException(sprintf('Could not create the \'%s\' directory.', $directory)); } } /** * @param string $directory - full directory path * * @return bool */ private function isDir($directory) { if ('/' === $directory) { return true; } if (!@ftp_chdir($this->getConnection(), $directory)) { return false; } // change directory again to return in the base directory ftp_chdir($this->getConnection(), $this->directory); return true; } private function fetchKeys($directory = '', $onlyKeys = true) { $directory = preg_replace('/^[\/]*([^\/].*)$/', '/$1', $directory); $lines = ftp_rawlist($this->getConnection(), '-alR ' . $this->directory . $directory); if (false === $lines) { return ['keys' => [], 'dirs' => []]; } $regexDir = '/' . preg_quote($this->directory . $directory, '/') . '\/?(.+):$/u'; $regexItem = '/^(?:([d\-\d])\S+)\s+\S+(?:(?:\s+\S+){5})?\s+(\S+)\s+(.+?)$/'; $prevLine = null; $directories = []; $keys = ['keys' => [], 'dirs' => []]; foreach ((array) $lines as $line) { if ('' === $prevLine && preg_match($regexDir, $line, $match)) { $directory = $match[1]; unset($directories[$directory]); if ($onlyKeys) { $keys = [ 'keys' => array_merge($keys['keys'], $keys['dirs']), 'dirs' => [], ]; } } elseif (preg_match($regexItem, $line, $tokens)) { $name = $tokens[3]; if ('.' === $name || '..' === $name) { continue; } $path = ltrim($directory . '/' . $name, '/'); if ('d' === $tokens[1] || '<dir>' === $tokens[2]) { $keys['dirs'][] = $path; $directories[$path] = true; } else { $keys['keys'][] = $path; } } $prevLine = $line; } if ($onlyKeys) { $keys = [ 'keys' => array_merge($keys['keys'], $keys['dirs']), 'dirs' => [], ]; } foreach (array_keys($directories) as $directory) { $keys = array_merge_recursive($keys, $this->fetchKeys($directory, $onlyKeys)); } return $keys; } /** * Parses the given raw list. * * @param array $rawlist * * @return array */ private function parseRawlist(array $rawlist) { $parsed = []; foreach ($rawlist as $line) { $infos = preg_split("/[\s]+/", $line, 9); if ($this->isLinuxListing($infos)) { $infos[7] = (strrpos($infos[7], ':') != 2) ? ($infos[7] . ' 00:00') : (date('Y') . ' ' . $infos[7]); if ('total' !== $infos[0]) { $parsed[] = [ 'perms' => $infos[0], 'num' => $infos[1], 'size' => $infos[4], 'time' => strtotime($infos[5] . ' ' . $infos[6] . '. ' . $infos[7]), 'name' => $infos[8], ]; } } elseif (count($infos) >= 4) { $isDir = (boolean) ('<dir>' === $infos[2]); $parsed[] = [ 'perms' => $isDir ? 'd' : '-', 'num' => '', 'size' => $isDir ? '' : $infos[2], 'time' => strtotime($infos[0] . ' ' . $infos[1]), 'name' => $infos[3], ]; } } return $parsed; } /** * Computes the path for the given key. * * @param string $key */ private function computePath($key) { return rtrim($this->directory, '/') . '/' . $key; } /** * Indicates whether the adapter has an open ftp connection. * * @return bool */ private function isConnected() { return is_resource($this->connection); } /** * Returns an opened ftp connection resource. If the connection is not * already opened, it open it before. * * @return resource The ftp connection */ private function getConnection() { if (!$this->isConnected()) { $this->connect(); } return $this->connection; } /** * Opens the adapter's ftp connection. * * @throws RuntimeException if could not connect */ private function connect() { if ($this->ssl && !function_exists('ftp_ssl_connect')) { throw new \RuntimeException('This Server Has No SSL-FTP Available.'); } // open ftp connection if (!$this->ssl) { $this->connection = ftp_connect($this->host, $this->port, $this->timeout); } else { $this->connection = ftp_ssl_connect($this->host, $this->port, $this->timeout); } if (!$this->connection) { throw new \RuntimeException(sprintf('Could not connect to \'%s\' (port: %s).', $this->host, $this->port)); } if (defined('FTP_USEPASVADDRESS')) { ftp_set_option($this->connection, FTP_USEPASVADDRESS, false); } $username = $this->username ?: 'anonymous'; $password = $this->password ?: ''; // login ftp user if (!@ftp_login($this->connection, $username, $password)) { $this->close(); throw new \RuntimeException(sprintf('Could not login as %s.', $username)); } // switch to passive mode if needed if ($this->passive && !ftp_pasv($this->connection, true)) { $this->close(); throw new \RuntimeException('Could not turn passive mode on.'); } // enable utf8 mode if configured if ($this->utf8 == true) { ftp_raw($this->connection, 'OPTS UTF8 ON'); } // ensure the adapter's directory exists if ('/' !== $this->directory) { try { $this->ensureDirectoryExists($this->directory, $this->create); } catch (\RuntimeException $e) { $this->close(); throw $e; } // change the current directory for the adapter's directory if (!ftp_chdir($this->connection, $this->directory)) { $this->close(); throw new \RuntimeException(sprintf('Could not change current directory for the \'%s\' directory.', $this->directory)); } } } /** * Closes the adapter's ftp connection. */ public function close() { if ($this->isConnected()) { ftp_close($this->connection); } } private function isLinuxListing($info) { return count($info) >= 9; } }