HEX
Server: Apache
System: Linux ns308404 4.15.0-213-generic #224-Ubuntu SMP Mon Jun 19 13:30:12 UTC 2023 x86_64
User: root (0)
PHP: 8.3.31
Disabled: opcache_get_status
Upload Files
File: /var/www/vhosts/onlinedev.com/httpdocs/odv/wp-content/plugins/ssh-sftp-updater-support/sftp.php
<?php
/*
Plugin Name: SSH SFTP Updater Support
Description: Update your WordPress blog / plugins via SFTP without libssh2
Version: 1.0.0
Author: TerraFrost, David Anderson + Team Updraft
Author URI: https://updraftplus.com
License: MIT
*/

if (!defined('ABSPATH')) die('No direct access allowed');

define('SSH_SFTP_UPDATER_SUPPORT_MAIN_PATH', plugin_dir_path(__FILE__));
define('SSH_SFTP_UPDATER_SUPPORT_BASENAME', plugin_basename(__FILE__));
define('SSH_SFTP_UPDATER_SUPPORT_VERSION', '1.0.0');
define('SSH_SFTP_UPDATER_SUPPORT_URL', plugin_dir_url(__FILE__));
// see http://adambrown.info/p/wp_hooks/hook/<filter name>
add_filter('filesystem_method', 'phpseclib_filesystem_method', 10, 2); // since 2.6 - WordPress will ignore the ssh option if the php ssh extension is not loaded
add_filter('request_filesystem_credentials', 'phpseclib_request_filesystem_credentials', 10, 1024); // since 2.5 - Alter some strings and don't ask for the public key
add_filter('fs_ftp_connection_types', 'phpseclib_fs_ftp_connection_types'); // since 2.9 - Add the SSH2 option to the connection options
add_filter('filesystem_method_file', 'phpseclib_filesystem_method_file', 10, 2); // since 2.6 - Direct WordPress to use our ssh2 class

// disable the modal dialog on WordPress >= 4.2
if (version_compare(get_bloginfo('version'), '4.2.0', '>=')) add_action('admin_head-plugins.php', 'phpseclib_disable_update_link_onclick');

function phpseclib_disable_update_link_onclick() {
	?>
<script>
	jQuery(function($) {
		$(".plugin-update-tr").off("click", ".update-link");
	});
</script>
	<?php
}

function phpseclib_filesystem_method_file($path, $method) {
	return $method == 'ssh2' ?
		dirname(__FILE__) . '/class-wp-filesystem-ssh2.php' :
		$path;
}

/**
 * Used by the WP filter phpseclib_filesystem_method
 */
function phpseclib_filesystem_method($method, $args) {
	return (isset($args['connection_type']) && 'ssh' == $args['connection_type']) ? 'ssh2' : $method;
}

/**
 * Runs upon the WP filter fs_ftp_connection_types
 *
 * @param Array $types
 *
 * @return Array
 */
function phpseclib_fs_ftp_connection_types($types) {
	$types['ssh'] = 'SSH2';
	return $types;
}

// See wp-admin/includes/file.php
function phpseclib_request_filesystem_credentials($value, $form_post, $type = '', $error = false, $context = false, $extra_fields = null, $allow_relaxed_file_ownership = false) {
	
	// phpcs:disable WordPress.Security.NonceVerification.Missing -- handled by WP core
	
	if ( empty($type) )
		$type = get_filesystem_method(array(), $context, $allow_relaxed_file_ownership);

	if ( 'direct' == $type )
		return $value;

	if ( is_null( $extra_fields ) )
		$extra_fields = array( 'version', 'locale' );

	$credentials = get_option('ftp_credentials', array( 'hostname' => '', 'username' => ''));

	// If defined, set it to that, Else, If POST'd, set it to that, If not, Set it to whatever it previously was(saved details in option)
	$credentials['hostname'] = defined('FTP_HOST') ? FTP_HOST : (!empty($_POST['hostname']) ? stripslashes($_POST['hostname']) : $credentials['hostname']); // phpcs:ignore  WordPress.Security.ValidatedSanitizedInput.InputNotSanitized,WordPress.Security.ValidatedSanitizedInput.MissingUnslash -- false positive
	$credentials['username'] = defined('FTP_USER') ? FTP_USER : (!empty($_POST['username']) ? stripslashes($_POST['username']) : $credentials['username']); // phpcs:ignore  WordPress.Security.ValidatedSanitizedInput.InputNotSanitized,WordPress.Security.ValidatedSanitizedInput.MissingUnslash -- Handled in WP core, false positive
	$credentials['password'] = defined('FTP_PASS') ? FTP_PASS : (!empty($_POST['password']) ? stripslashes($_POST['password']) : ''); // phpcs:ignore  WordPress.Security.ValidatedSanitizedInput.InputNotSanitized,WordPress.Security.ValidatedSanitizedInput.MissingUnslash -- Handled in WP core, false positive

	// Check to see if we are setting the private key for ssh
	if (defined('FTP_PRIKEY') && file_exists(FTP_PRIKEY)) {
		$credentials['private_key'] = file_get_contents(FTP_PRIKEY); // phpcs:ignore WordPress.WP.AlternativeFunctions.file_get_contents_file_get_contents -- user supplied constant
	} else {
		$credentials['private_key'] = empty($_POST['private_key']) ? '' : stripslashes($_POST['private_key']); // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotSanitized,WordPress.Security.ValidatedSanitizedInput.MissingUnslash -- false positive
		if (isset($_FILES['private_key_file']['tmp_name']) && file_exists($_FILES['private_key_file']['tmp_name'])) {
			$credentials['private_key'] = file_get_contents($_FILES['private_key_file']['tmp_name']); // phpcs:ignore WordPress.WP.AlternativeFunctions.file_get_contents_file_get_contents -- it's a file
		}
	}

	//sanitize the hostname, Some people might pass in odd-data:
	$credentials['hostname'] = preg_replace('|\w+://|', '', $credentials['hostname']); //Strip any schemes off

	if ( strpos($credentials['hostname'], ':') ) {
		list( $credentials['hostname'], $credentials['port'] ) = explode(':', $credentials['hostname'], 2);
		if ( ! is_numeric($credentials['port']) )
			unset($credentials['port']);
	} else {
		unset($credentials['port']);
	}

	if ( (defined('FTP_SSH') && FTP_SSH) || (defined('FS_METHOD') && 'ssh' == FS_METHOD) )
		$credentials['connection_type'] = 'ssh';
	else if ( (defined('FTP_SSL') && FTP_SSL) && 'ftpext' == $type ) //Only the FTP Extension understands SSL
		$credentials['connection_type'] = 'ftps';
	else if ( !empty($_POST['connection_type']) )
		$credentials['connection_type'] = stripslashes($_POST['connection_type']);
	else if ( !isset($credentials['connection_type']) ) //All else fails (And its not defaulted to something else saved), Default to FTP
		$credentials['connection_type'] = 'ftp';

	if ( ! $error &&
			(
				( !empty($credentials['password']) && !empty($credentials['username']) && !empty($credentials['hostname']) ) ||
				( 'ssh' == $credentials['connection_type'] && !empty($credentials['private_key']) )
			) ) {
		$stored_credentials = $credentials;
		if ( !empty($stored_credentials['port']) ) //save port as part of hostname to simplify above code.
			$stored_credentials['hostname'] .= ':' . $stored_credentials['port'];

		unset($stored_credentials['password'], $stored_credentials['port'], $stored_credentials['private_key'], $stored_credentials['public_key']);
		if ( ! defined( 'WP_INSTALLING' ) ) {
			update_option( 'ftp_credentials', $stored_credentials );
		}
		return $credentials;
	}
	$hostname = isset( $credentials['hostname'] ) ? $credentials['hostname'] : '';
	$username = isset( $credentials['username'] ) ? $credentials['username'] : '';
	$public_key = isset( $credentials['public_key'] ) ? $credentials['public_key'] : '';
	$private_key = isset( $credentials['private_key'] ) ? $credentials['private_key'] : '';
	$port = isset( $credentials['port'] ) ? $credentials['port'] : '';
	$connection_type = isset( $credentials['connection_type'] ) ? $credentials['connection_type'] : '';

	if ( $error ) {
		$error_string = '<strong>'.__('ERROR', 'ssh-sftp-updater-support').':</strong>'.__('There was an error connecting to the server; please verify the settings are correct and that network connectivity exists between the two servers.', 'ssh-sftp-updater-support');
		if ( is_wp_error($error) ) {
			$error_strings = $error->get_error_messages();
			$error_string = implode('<br>', $error_strings);
		}
		echo '<div id="message" class="error"><p>' . esc_html($error_string) . '</p></div>';
	}

	$types = array();
	if ( extension_loaded('ftp') || extension_loaded('sockets') || function_exists('fsockopen') )
		$types[ 'ftp' ] = 'FTP';
	if ( extension_loaded('ftp') ) //Only this supports FTPS
		$types[ 'ftps' ] = 'FTPS (SSL)';

	$types = apply_filters('fs_ftp_connection_types', $types, $credentials, $type, $error, $context);

?>
<script type="text/javascript">
<!--
jQuery(function($){
	jQuery("#ssh").on('click', function () {
		jQuery(".ssh_keys").show();
	});
	jQuery("#ftp, #ftps").on('click', function () {
		jQuery(".ssh_keys").hide();
	});
	jQuery("#private_key_file").on('change', function (event) {
		if (window.File && window.FileReader) {
			var reader = new FileReader();
			reader.onload = function(file) {
				jQuery("#private_key").val(file.target.result);
			};
			reader.readAsBinaryString(event.target.files[0]);
		}
	});
	jQuery("form").on('submit', function () {
		if(typeof(Storage)!=="undefined") {
			localStorage.privateKeyFile = jQuery("#private_key").val();
		}
		jQuery("#private_key_file").prop('disabled', true);
	});
	if(typeof(Storage)!=="undefined" && localStorage.privateKeyFile) {
		jQuery("#private_key").val(localStorage.privateKeyFile);
	}
	jQuery('form input[value=""]:first').trigger('focus');
});
-->
</script>
<form action="<?php echo esc_url($form_post); ?>" method="post" enctype="multipart/form-data">
<div class="wrap">
<h2><?php
	esc_html_e('Connection Information');  // phpcs:ignore WordPress.WP.I18n.MissingArgDomain -- String is part of WordPress core
?></h2>
<p><?php
	$label_user = __('Username'); // phpcs:ignore WordPress.WP.I18n.MissingArgDomain -- String is part of WordPress core
	$label_pass = __('Password'); // phpcs:ignore WordPress.WP.I18n.MissingArgDomain -- String is part of WordPress core
	esc_html_e('To perform the requested action, WordPress needs to access your web server.'); // phpcs:ignore WordPress.WP.I18n.MissingArgDomain -- String is part of WordPress core
	echo ' ';
	if ( ( isset( $types['ftp'] ) || isset( $types['ftps'] ) ) ) {
		if ( isset( $types['ssh'] ) ) {
			esc_html_e('Please enter your FTP or SSH credentials to proceed.');  // phpcs:ignore WordPress.WP.I18n.MissingArgDomain -- String is part of WordPress core
			$label_user = __('FTP/SSH Username'); // phpcs:ignore WordPress.WP.I18n.MissingArgDomain -- String is part of WordPress core
			$label_pass = __('FTP/SSH Password'); // phpcs:ignore WordPress.WP.I18n.MissingArgDomain -- String is part of WordPress core
		} else {
			esc_html_e('Please enter your FTP credentials to proceed.');  // phpcs:ignore WordPress.WP.I18n.MissingArgDomain -- String is part of WordPress core
			$label_user = __('FTP Username'); // phpcs:ignore WordPress.WP.I18n.MissingArgDomain -- String is part of WordPress core
			$label_pass = __('FTP Password'); // phpcs:ignore WordPress.WP.I18n.MissingArgDomain -- String is part of WordPress core
		}
		echo ' ';
	}
	esc_html_e('If you do not remember your credentials, you should contact your web host.'); // phpcs:ignore WordPress.WP.I18n.MissingArgDomain -- String is part of WordPress core
?></p>
<table class="form-table">
<tr valign="top">
	<th scope="row"><label for="hostname"><?php esc_html_e('Hostname'); // phpcs:ignore WordPress.WP.I18n.MissingArgDomain -- String is part of WordPress core ?></label></th>
	<td><input name="hostname" type="text" id="hostname" value="<?php echo esc_attr($hostname); if ( !empty($port) ) echo ":".esc_html($port); ?>"<?php disabled( defined('FTP_HOST') ); ?> size="40" /></td>
</tr>

<tr valign="top">
	<th scope="row"><label for="username"><?php echo esc_html($label_user); ?></label></th>
	<td><input name="username" type="text" id="username" value="<?php echo esc_attr($username) ?>"<?php disabled( defined('FTP_USER') ); ?> size="40" /></td>
</tr>

<tr valign="top">
	<th scope="row"><label for="password"><?php echo esc_html($label_pass); ?></label></th>
	<td><input name="password" type="password" id="password" value="<?php if ( defined('FTP_PASS') ) echo '*****'; ?>"<?php disabled( defined('FTP_PASS') ); ?> size="40" /></td>
</tr>

<?php if ( isset($types['ssh']) ) : ?>
<tr class="ssh_keys" valign="top" style="<?php if ( 'ssh' != $connection_type ) echo 'display:none' ?>">
	<th scope="row" colspan="2"><?php esc_html_e('SSH Authentication Keys', 'ssh-sftp-updater-support') ?>
	<div><?php esc_html_e('If a passphrase is needed, enter that in the password field above.', 'ssh-sftp-updater-support') ?></div></th>
</tr>
<tr class="ssh_keys" valign="top" style="<?php if ( 'ssh' != $connection_type ) echo 'display:none' ?>">
	<th scope="row">
		<div class="key-labels textright">
		<label for="private_key"><?php esc_html_e('Copy / Paste Private Key:', 'ssh-sftp-updater-support') ?></label>
		</div>
		</th>
	<td>
		<textarea name="private_key" id="private_key" cols="58" rows="10" <?php disabled( defined('FTP_PRIKEY') ); ?>><?php echo esc_textarea($private_key); ?></textarea>
	</td>
</tr>
<tr class="ssh_keys" valign="top" style="<?php if ( 'ssh' != $connection_type ) echo 'display:none' ?>">
	<th scope="row">
		<div class="key-labels textright">
			<label for="private_key_file"><?php esc_html_e('Upload Private Key:', 'ssh-sftp-updater-support') ?></label>
		</div>
	</th>
	<td><input name="private_key_file" id="private_key_file" type="file" <?php disabled( defined('FTP_PRIKEY') ); ?>> <?php esc_html_e('(The uploaded private key file will be inserted in the field above)', 'ssh-sftp-updater-support'); ?>
	</td>
</tr>
<?php endif; ?>

<tr valign="top">
	<th scope="row"><?php esc_html_e('Connection Type'); // phpcs:ignore WordPress.WP.I18n.MissingArgDomain -- String is part of WordPress core ?></th>
		<td>
		<fieldset><legend class="screen-reader-text"><span><?php esc_html_e('Connection Type'); // phpcs:ignore WordPress.WP.I18n.MissingArgDomain -- String is part of WordPress core ?></span></legend>
	<?php
		$disabled = disabled( (defined('FTP_SSL') && FTP_SSL) || (defined('FTP_SSH') && FTP_SSH), true, false );
		foreach ( $types as $name => $text ) : ?>
		<label for="<?php echo esc_attr($name) ?>">
			<input type="radio" name="connection_type" id="<?php echo esc_attr($name) ?>" value="<?php echo esc_attr($name) ?>"<?php checked($name, $connection_type); echo $disabled; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped -- HTML attribute ?> >
			<?php echo esc_html($text); ?>
		</label>
		<?php endforeach; ?>
		</fieldset>
	</td>
</tr>
</table>

<?php
foreach ( (array) $extra_fields as $field ) {
	if ( isset( $_POST[ $field ] ) )
		echo '<input type="hidden" name="' . esc_attr( $field ) . '" value="' . esc_attr( stripslashes( $_POST[ $field ] ) ) . '" />';
}
?>
<p class="submit">
	<input type="submit" name="upgrade" id="upgrade" class="button" value="<?php esc_attr_e( 'Proceed' ); // phpcs:ignore WordPress.WP.I18n.MissingArgDomain -- String is part of WordPress core ?>">
</p>
</div>
</form>
<?php
	return false;
	// phpcs:enable WordPress.Security.NonceVerification.Missing
}

// Check to make sure if SSH_SFTP_Updater_Support is already call and returns.
if (!class_exists('SSH_SFTP_Updater_Support')) :

class SSH_SFTP_Updater_Support {

	private $template_directories;

	protected static $_instance = null;
	
	protected static $_options_instance = null;

	protected static $_notices_instance = null;

	/**
	 * Constructor
	 */
	public function __construct() {
		add_action('plugins_loaded', array($this, 'plugins_loaded'), 1);
		add_action('admin_init', array($this, 'admin_init'));
		add_action('wp_ajax_ssh_sftp_updater_support_ajax', array($this, 'ssh_sftp_updater_support_ajax_handler'));
		add_filter('plugin_row_meta',  array($this, 'plugin_row_meta'), 10, 2);
	}

	/**
	 * Returns a singleton instance
	 *
	 * @return SSH_SFTP_Updater_Support
	 */
	public static function instance() {
		if (empty(self::$_instance)) {
			self::$_instance = new self();
		}
		return self::$_instance;
	}
	
	public static function get_notices() {
		if (empty(self::$_notices_instance)) {
			if (!class_exists('SSH_SFTP_Updater_Support_Notices')) include_once(SSH_SFTP_UPDATER_SUPPORT_MAIN_PATH.'/includes/ssh-sftp-updater-support-notices.php');
			self::$_notices_instance = new SSH_SFTP_Updater_Support_Notices();
		}
		return self::$_notices_instance;
	}
	
	/**
	 * Checks if this is the premium version and loads it. It also ensures that if the free version is installed then it is disabled with an appropriate error message.
	 */
	public function plugins_loaded() {
		// Loads the language file.
		load_plugin_textdomain('ssh-sftp-updater-support', false, dirname(plugin_basename(__FILE__)) . '/languages');
	}
	
	/**
	 * Gets an array of plugins active on either the current site, or site-wide
	 *
	 * @return Array - a list of plugin paths (relative to the plugin directory)
	 */
	private function get_active_plugins() {
	
		// Gets all active plugins on the current site
		$active_plugins = get_option('active_plugins');

		if (is_multisite()) {
			$network_active_plugins = get_site_option('active_sitewide_plugins');
			if (!empty($network_active_plugins)) {
				$network_active_plugins = array_keys($network_active_plugins);
				$active_plugins = array_merge($active_plugins, $network_active_plugins);
			}
		}
		
		return $active_plugins;
	}
	
	/**
	 * This function checks whether a specific plugin is installed, and returns information about it
	 *
	 * @param  string $name Specify "Plugin Name" to return details about it.
	 * @return array        Returns an array of details such as if installed, the name of the plugin and if it is active.
	 */
	public function is_installed($name) {

		// Needed to have the 'get_plugins()' function
		include_once(ABSPATH.'wp-admin/includes/plugin.php');

		// Gets all plugins available
		$get_plugins = get_plugins();
	
		$active_plugins = $this->get_active_plugins();
	
		$plugin_info['installed'] = false;
		$plugin_info['active'] = false;

		// Loops around each plugin available.
		foreach ($get_plugins as $key => $value) {
			// If the plugin name matches that of the specified name, it will gather details.
			if ($value['Name'] != $name) continue;
			$plugin_info['installed'] = true;
			$plugin_info['name'] = $key;
			$plugin_info['version'] = $value['Version'];
			if (in_array($key, $active_plugins)) {
				$plugin_info['active'] = true;
			}
			break;
		}
		return $plugin_info;
	}

	public function admin_init() {
		$pagenow = $GLOBALS['pagenow'];

		$this->register_template_directories();

		if (('index.php' == $pagenow && current_user_can('update_plugins')) || ('index.php' == $pagenow && defined('SSH_SFTP_UPDATER_SUPPORT_FORCE_DASHNOTICE') && SSH_SFTP_UPDATER_SUPPORT_FORCE_DASHNOTICE)) {
			
			$dismissed_until = get_site_option('ssh_sftp_updater_support_dismiss_dash_notice_until', 0);

			if (file_exists(SSH_SFTP_UPDATER_SUPPORT_MAIN_PATH . '/index.html')) {
				$installed = filemtime(SSH_SFTP_UPDATER_SUPPORT_MAIN_PATH . '/index.html');
				$installed_for = (time() - $installed);
			}
			if (($installed && time() > $dismissed_until && $installed_for < (14 * 86400) && !defined('SSH_SFTP_UPDATER_SUPPORT_NOADS_B')) || (defined('SSH_SFTP_UPDATER_SUPPORT_FORCE_DASHNOTICE') && SSH_SFTP_UPDATER_SUPPORT_FORCE_DASHNOTICE)) {
				add_action('all_admin_notices', array($this, 'show_admin_notice_upgradead'));
			} else {
				// These are not desired.
				// add_action('all_admin_notices', array($this->get_notices(), 'do_notice'));
			}
		}
	}

	public function show_admin_notice_upgradead() {
		$this->include_template('notices/thanks-for-using-main-dash.php');
	}
	
	public function capability_required() {
		return apply_filters('ssh_sftp_updater_support_capability_required', 'manage_options');
	}
	
	public function ssh_sftp_updater_support_ajax_handler() {
		$nonce = empty($_POST['nonce']) ? '' : stripslashes($_POST['nonce']);

		if (!wp_verify_nonce($nonce, 'ssh-sftp-updater-support-ajax-nonce') || empty($_POST['subaction'])) die('Security check');

		$subaction = stripslashes($_POST['subaction']);

		if (!current_user_can($this->capability_required())) die('Security check');

		$results = array();

		// Some commands that are available via AJAX only.
		if ('dismiss_dash_notice_until' == $subaction) {
			update_site_option('ssh_sftp_updater_support_dismiss_dash_notice_until', (time() + 366 * 86400));
		} elseif ('dismiss_page_notice_until' == $subaction) {
			update_site_option('ssh_sftp_updater_support_dismiss_page_notice_until', (time() + 84 * 86400));
		}

		echo json_encode($results);

		die;
	}
	
	private function wp_normalize_path($path) {
		// Wp_normalize_path is not present before WP 3.9.
		if (function_exists('wp_normalize_path')) return wp_normalize_path($path);
		// Taken from WP 4.6.
		$path = str_replace('\\', '/', $path);
		$path = preg_replace('|(?<=.)/+|', '/', $path);
		if (':' === substr($path, 1, 1)) {
			$path = ucfirst($path);
		}
		return $path;
	}
	
	public function get_templates_dir() {
		return apply_filters('ssh_sftp_updater_support_templates_dir', $this->wp_normalize_path(SSH_SFTP_UPDATER_SUPPORT_MAIN_PATH.'/templates'));
	}

	public function get_templates_url() {
		return apply_filters('ssh_sftp_updater_support_templates_url', SSH_SFTP_UPDATER_SUPPORT_URL.'/templates');
	}

	public function include_template($path, $return_instead_of_echo = false, $extract_these = array()) {
		if ($return_instead_of_echo) ob_start();

		if (preg_match('#^([^/]+)/(.*)$#', $path, $matches)) {
			$prefix = $matches[1];
			$suffix = $matches[2];
			if (isset($this->template_directories[$prefix])) {
				$template_file = $this->template_directories[$prefix].'/'.$suffix;
			}
		}

		if (!isset($template_file)) {
			$template_file = SSH_SFTP_UPDATER_SUPPORT_MAIN_PATH.'/templates/'.$path;
		}

		$template_file = apply_filters('ssh_sftp_updater_support_template', $template_file, $path);

		do_action('ssh_sftp_updater_support_before_template', $path, $template_file, $return_instead_of_echo, $extract_these);

		if (!file_exists($template_file)) {
			error_log("SSH SFTP Updater Support: template not found: ".$template_file); //  phpcs:ignore WordPress.PHP.DevelopmentFunctions.error_log_error_log -- invalid opinion
			echo esc_html__('Error:', 'ssh-sftp-updater-support').' '.esc_html__('template not found', 'ssh-sftp-updater-support')." (".esc_html($path).")";
		} else {
			extract($extract_these);
			$wpdb = $GLOBALS['wpdb'];
			$ssh_sftp_updater_support = $this;
			$ssh_sftp_updater_support_notices = $this->get_notices();
			include $template_file;
		}

		do_action('ssh_sftp_updater_support_after_template', $path, $template_file, $return_instead_of_echo, $extract_these);

		if ($return_instead_of_echo) return ob_get_clean();
	}

	/**
	 * Build a list of template directories (stored in self::$template_directories)
	 */
	private function register_template_directories() {

		$template_directories = array();

		$templates_dir = $this->get_templates_dir();

		if ($dh = opendir($templates_dir)) {
			while (($file = readdir($dh)) !== false) {
				if ('.' == $file || '..' == $file) continue;
				if (is_dir($templates_dir.'/'.$file)) {
					$template_directories[$file] = $templates_dir.'/'.$file;
				}
			}
			closedir($dh);
		}

		// Optimal hook for most extensions to hook into.
		$this->template_directories = apply_filters('ssh_sftp_updater_support_template_directories', $template_directories);

	}
	
	/**
	 * This will customize a URL with a correct Affiliate link
	 * This function can be update to suit any URL as longs as the URL is passed
	 *
	 * @param String  $url					  - URL to be check to see if it an updraftplus match.
	 * @param String  $text					  - Text to be entered within the href a tags.
	 * @param String  $html					  - Any specific HTML to be added.
	 * @param String  $classes				  - Space-separated list of classes for the href
	 * @param Boolean $return_instead_of_echo - if set, then the result will be returned, not echo-ed.
	 *
	 * @return String|void
	 */
	public function ssh_sftp_updater_support_url($url, $text, $html = '', $classes = '', $return_instead_of_echo = false) {
		// Check if the URL is UpdraftPlus.
		if (false !== strpos($url, '//updraftplus.com')) {
			// Set URL with Affiliate ID.
			$url = $url.'?ref='.$this->get_notices()->get_affiliate_id().'&source=sshsmtp';

			// Apply filters.
			$url = apply_filters('ssh_sftp_updater_support_updraftplus_com_link', $url);
		}
		// Return URL - check if there is HTML such as images.
		if ('' != $html) {
			$result = '<a '.($class ? 'class="'.esc_attr($classes).'"' : '').' href="'.esc_attr($url).'">'.$html.'</a>';
		} else {
			$result = '<a '.($class ? 'class="'.esc_attr($classes).'"' : '').' href="'.esc_attr($url).'">'.esc_html($text).'</a>';
		}
		if ($return_instead_of_echo) return $result;
		echo wp_kses_post($result);
	}
	
	/**
    * Add a "Other useful plugins" link in the links in the line for the plugin in the 'Plugin' page
    *
    * @param array  $plugin_meta An array of the plugin's metadata
	* @param string $plugin_file Path to the plugin file, relative to the plugins directory
    * @return array $links An array of plugin action links
    */
	public function plugin_row_meta($plugin_meta_links, $plugin_file) {
		if (SSH_SFTP_UPDATER_SUPPORT_BASENAME ==  $plugin_file) {
			$plugin_meta_links[] = '<a href="https://profiles.wordpress.org/davidanderson#content-plugins">'.__('Other useful plugins', 'ssh-sftp-updater-support').'</a>';
		}
		return $plugin_meta_links;
	}
}

function SSH_SFTP_Updater_Support() {
	return SSH_SFTP_Updater_Support::instance();
}

endif;

$GLOBALS['ssh_sftp_updater_support'] = SSH_SFTP_Updater_Support();