<?php /** * Plesk Module * * @package blesta * @subpackage blesta.components.modules.plesk * @copyright Copyright (c) 2013, Phillips Data, Inc. * @license http://www.blesta.com/license/ The Blesta License Agreement * @link http://www.blesta.com/ Blesta */ class Plesk extends Module { /** * @var string The version of this module */ private static $version = "2.1.0"; /** * @var string The authors of this module */ private static $authors = array(array('name'=>"Phillips Data, Inc.",'url'=>"http://www.blesta.com")); /** * @var array A list of Plesk panel versions */ private $panel_versions = array(); /** * Initializes the module */ public function __construct() { // Load components required by this module Loader::loadComponents($this, array("Input")); // Load the language required by this module Language::loadLang("plesk", null, dirname(__FILE__) . DS . "language" . DS); // Setup panel versions $this->init(); } /** * Initializes the panel versions */ private function init() { $windows = Language::_("Plesk.panel_version.windows", true); $linux = Language::_("Plesk.panel_version.linux", true); $versions = array( '7.5.4' => array('name' => Language::_("Plesk.panel_version.plesk_type", true, "7.5.4", $linux), 'api_version' => "1.3.5.1", 'supported' => false), '7.5.6' => array('name' => Language::_("Plesk.panel_version.plesk_type", true, "7.5.6", $windows), 'api_version' => "1.4.0.0", 'supported' => false), '7.6' => array('name' => Language::_("Plesk.panel_version.plesk_type", true, "7.6", $windows), 'api_version' => "1.4.0.0", 'supported' => false), '7.6.1' => array('name' => Language::_("Plesk.panel_version.plesk_type", true, "7.6.1", $windows), 'api_version' => "1.4.1.1", 'supported' => false), '8.0' => array('name' => Language::_("Plesk.panel_version.plesk_type", true, "8.0", $linux), 'api_version' => "1.4.0.0", 'supported' => false), '8.0.1' => array('name' => Language::_("Plesk.panel_version.plesk_type", true, "8.0.1", $linux), 'api_version' => "1.4.1.2", 'supported' => false), '8.1.0' => array('name' => Language::_("Plesk.panel_version.plesk", true, "8.1.0"), 'api_version' => "1.4.2.0", 'supported' => false), '8.1.1' => array('name' => Language::_("Plesk.panel_version.plesk", true, "8.1.1"), 'api_version' => "1.5.0.0", 'supported' => false), '8.2' => array('name' => Language::_("Plesk.panel_version.plesk", true, "8.2"), 'api_version' => "1.5.1.0", 'supported' => false), '8.3' => array('name' => Language::_("Plesk.panel_version.plesk", true, "8.3"), 'api_version' => "1.5.2.0", 'supported' => false), '8.4' => array('name' => Language::_("Plesk.panel_version.plesk", true, "8.4"), 'api_version' => "1.5.2.1", 'supported' => false), '8.6' => array('name' => Language::_("Plesk.panel_version.plesk", true, "8.6"), 'api_version' => "1.5.2.1", 'supported' => false), '9.0.0' => array('name' => Language::_("Plesk.panel_version.parallels", true, "9.0.0"), 'api_version' => "1.6.0.0", 'supported' => false), '9.0.1' => array('name' => Language::_("Plesk.panel_version.parallels", true, "9.0.1"), 'api_version' => "1.6.0.1", 'supported' => false), '9.0.2' => array('name' => Language::_("Plesk.panel_version.parallels", true, "9.0.2"), 'api_version' => "1.6.0.2", 'supported' => false), '10.0' => array('name' => Language::_("Plesk.panel_version.parallels", true, "10.0"), 'api_version' => "1.6.3.0", 'supported' => true), '10.1' => array('name' => Language::_("Plesk.panel_version.parallels", true, "10.1"), 'api_version' => "1.6.3.1", 'supported' => true), '10.2' => array('name' => Language::_("Plesk.panel_version.parallels", true, "10.2"), 'api_version' => "1.6.3.2", 'supported' => true), '10.3' => array('name' => Language::_("Plesk.panel_version.parallels", true, "10.3"), 'api_version' => "1.6.3.3", 'supported' => true), '10.4' => array('name' => Language::_("Plesk.panel_version.parallels", true, "10.4"), 'api_version' => "1.6.3.4", 'supported' => true), '11.0' => array('name' => Language::_("Plesk.panel_version.parallels", true, "11.0"), 'api_version' => "1.6.3.5", 'supported' => true), '11.1.0' => array('name' => Language::_("Plesk.panel_version.parallels", true, "11.1.0"), 'api_version' => "1.6.4.0", 'supported' => true), '11.5' => array('name' => Language::_("Plesk.panel_version.parallels", true, "11.5"), 'api_version' => "1.6.5.0", 'supported' => true), ); $this->panel_versions = array_reverse($versions); } /** * Retrieves the API version based on the panel version in use * * @param string $panel_version The version number of the panel * @return string The API version to use for this panel */ private function getApiVersion($panel_version) { return $this->panel_versions[$panel_version]['api_version']; } /** * Retrieves Plesk panel versions that are supported by this module * * @param boolean $format True to format the versions as name/value pairs, false for the entire array * @return array A list of supported versions */ private function getSupportedPanelVersions($format = false) { $versions = array(); foreach ($this->panel_versions as $panel_version => $panel) { if ($panel['supported']) { if ($format) $versions[$panel_version] = $panel['name']; else $versions[$panel_version] = $panel; } } return $versions; } /** * Returns the name of this module * * @return string The common name of this module */ public function getName() { return Language::_("Plesk.name", true); } /** * Returns the version of this module * * @return string The current version of this module */ public function getVersion() { return self::$version; } /** * Returns the name and URL for the authors of this module * * @return array A numerically indexed array that contains an array with key/value pairs for 'name' and 'url', representing the name and URL of the authors of this module */ public function getAuthors() { return self::$authors; } /** * Returns all tabs to display to an admin when managing a service whose * package uses this module * * @param stdClass $package A stdClass object representing the selected package * @return array An array of tabs in the format of method => title. Example: array('methodName' => "Title", 'methodName2' => "Title2") */ public function getAdminTabs($package) { return array( 'tabStats' => Language::_("Plesk.tab_stats", true) ); } /** * Returns all tabs to display to a client when managing a service whose * package uses this module * * @param stdClass $package A stdClass object representing the selected package * @return array An array of tabs in the format of method => title. Example: array('methodName' => "Title", 'methodName2' => "Title2") */ public function getClientTabs($package) { return array( 'tabClientStats' => Language::_("Plesk.tab_client_stats", true) ); } /** * Performs any necessary bootstraping actions. Sets Input errors on * failure, preventing the module from being added. * * @return array A numerically indexed array of meta data containing: * - key The key for this meta field * - value The value for this key * - encrypted Whether or not this field should be encrypted (default 0, not encrypted) */ public function install() { $errors = array(); // Ensure the the system meets the requirements for this module if (!extension_loaded("simplexml")) $errors['simplexml']['required'] = Language::_("Plesk.!error.simplexml_required", true); if (!empty($errors)) { $this->Input->setErrors($errors); return; } } /** * Returns the value used to identify a particular service * * @param stdClass $service A stdClass object representing the service * @return string A value used to identify this service amongst other similar services */ public function getServiceName($service) { foreach ($service->fields as $field) { if ($field->key == "plesk_domain") return $field->value; } return null; } /** * Returns a noun used to refer to a module row (e.g. "Server", "VPS", "Reseller Account", etc.) * * @return string The noun used to refer to a module row */ public function moduleRowName() { return Language::_("Plesk.module_row", true); } /** * Returns a noun used to refer to a module row in plural form (e.g. "Servers", "VPSs", "Reseller Accounts", etc.) * * @return string The noun used to refer to a module row in plural form */ public function moduleRowNamePlural() { return Language::_("Plesk.module_row_plural", true); } /** * Returns a noun used to refer to a module group (e.g. "Server Group", "Cloud", etc.) * * @return string The noun used to refer to a module group */ public function moduleGroupName() { return Language::_("Plesk.module_group", true); } /** * Returns the key used to identify the primary field from the set of module row meta fields. * This value can be any of the module row meta fields. * * @return string The key used to identify the primary field from the set of module row meta fields */ public function moduleRowMetaKey() { return "server_name"; } /** * Returns the value used to identify a particular package service which has * not yet been made into a service. This may be used to uniquely identify * an uncreated service of the same package (i.e. in an order form checkout) * * @param stdClass $package A stdClass object representing the selected package * @param array $vars An array of user supplied info to satisfy the request * @return string The value used to identify this package service * @see Module::getServiceName() */ public function getPackageServiceName($packages, array $vars=null) { if (isset($vars['plesk_domain'])) return $vars['plesk_domain']; return null; } /** * Checks whether the given webspace ID exists in Plesk * * @param int $webspace_id The subscription webspace ID to check * @param stdClass $package An stdClass object representing the package * @return boolean True if the webspace exists, false otherwise */ public function validateWebspaceExists($webspace_id, $package) { // Get module row and API $module_row = $this->getModuleRowByServer((isset($package->module_group) ? $package->module_group : 0), (isset($package->module_group) ? $package->module_group : "")); $api = $this->getApi($module_row->meta->ip_address, $module_row->meta->username, $module_row->meta->password, $module_row->meta->port); $api_version = $this->getApiVersion($module_row->meta->panel_version); // Fetch the webspace/domain try { $subscription = $api->loadCommand("plesk_subscriptions", array($api_version)); $data = array('id' => $webspace_id); $this->log($module_row->meta->ip_address . "|webspace:get", serialize($data), "input", true); $response = $this->parseResponse($subscription->get($data), $module_row, true); if ($response && $response->result->status == "ok") return true; } catch (Exception $e) { // API request failed $this->Input->setErrors(array('api' => array('internal' => Language::_("Plesk.!error.api.internal", true)))); } return false; } /** * Checks whether the given plan ID exists in Plesk * * @param int $plan_id The service plan ID * @param stdClass $package An stdClass object representing the package * @param boolean $reseller True if the plan is a reseller plan, false for a hosting plan (optional, default false) * @return boolean True if the plan exists, false otherwise */ public function validatePlanExists($plan_id, $package, $reseller=false) { // Get module row and API $module_row = $this->getModuleRowByServer((isset($package->module_group) ? $package->module_group : 0), (isset($package->module_group) ? $package->module_group : "")); // Fetch the plans $plans = $this->getPleskPlans($module_row, $reseller); return (isset($plans[$plan_id])); } /** * Attempts to validate service info. This is the top-level error checking method. Sets Input errors on failure. * * @param stdClass $package A stdClass object representing the selected package * @param array $vars An array of user supplied info to satisfy the request * @param boolean $edit True if editing the service, false otherwise * @return boolean True if the service validates, false otherwise. Sets Input errors when false. */ public function validateService($package, array $vars=null, $edit=false) { // Set rules $rules = array( 'plesk_domain' => array( 'format' => array( 'rule' => array(array($this, "validateHostName")), 'message' => Language::_("Plesk.!error.plesk_domain.format", true) ) ), 'plesk_username' => array( 'length' => array( 'if_set' => true, 'rule' => array("betweenLength", 1, 60), 'message' => Language::_("Plesk.!error.plesk_username.length", true) ) ), 'plesk_password' => array( 'length' => array( 'if_set' => true, 'rule' => array("betweenLength", 5, 14), 'message' => Language::_("Plesk.!error.plesk_password.length", true) ) ), 'plesk_confirm_password' => array( 'matches' => array( 'if_set' => true, 'rule' => array("compares", "==", (isset($vars['plesk_password']) ? $vars['plesk_password'] : "")), 'message' => Language::_("Plesk.!error.plesk_confirm_password.matches", true) ) ), 'plesk_webspace_id' => array( 'exists' => array( 'if_set' => true, 'rule' => array(array($this, "validateWebspaceExists"), $package), 'message' => Language::_("Plesk.!error.plesk_webspace_id.exists", true) ) ) ); // Set the values that may be empty $empty_values = array("plesk_username", "plesk_password", "plesk_confirm_password"); if (!$edit) $empty_values[] = "plesk_webspace_id"; else { // On edit, domain is optional $rules['plesk_domain']['format']['if_set'] = true; } // Remove rules on empty fields foreach ($empty_values as $value) { // Confirm password must be given if password is too if ($value == "plesk_confirm_password" && !empty($vars['plesk_password'])) continue; if (empty($vars[$value])) unset($rules[$value]); } $this->Input->setRules($rules); return $this->Input->validates($vars); } /** * Adds the service to the remote server. Sets Input errors on failure, * preventing the service from being added. * * @param stdClass $package A stdClass object representing the selected package * @param array $vars An array of user supplied info to satisfy the request * @param stdClass $parent_package A stdClass object representing the parent service's selected package (if the current service is an addon service) * @param stdClass $parent_service A stdClass object representing the parent service of the service being added (if the current service is an addon service service and parent service has already been provisioned) * @param string $status The status of the service being added. These include: * - active * - canceled * - pending * - suspended * @return array A numerically indexed array of meta fields to be stored for this service containing: * - key The key for this meta field * - value The value for this key * - encrypted Whether or not this field should be encrypted (default 0, not encrypted) * @see Module::getModule() * @see Module::getModuleRow() */ public function addService($package, array $vars=null, $parent_package=null, $parent_service=null, $status="pending") { // Get module row and API $module_row = $this->getModuleRow(); $api = $this->getApi($module_row->meta->ip_address, $module_row->meta->username, $module_row->meta->password, $module_row->meta->port); $client_id = $vars['client_id']; // If no username or password given, generate them if (empty($vars['plesk_username'])) $vars['plesk_username'] = $this->generateUsername((isset($vars['plesk_domain']) ? $vars['plesk_domain'] : ""), $client_id); if (empty($vars['plesk_password'])) { $vars['plesk_password'] = $this->generatePassword(); $vars['plesk_confirm_password'] = $vars['plesk_password']; } $params = $this->getFieldsFromInput((array)$vars, $package); $this->validateService($package, $vars); if ($this->Input->errors()) return; // Only provision the service if 'use_module' is true if ($vars['use_module'] == "true") { $api_version = $this->getApiVersion($module_row->meta->panel_version); // Create a reseller account if ($package->meta->type == "reseller") { $response = $this->createResellerAccount($module_row, $package, $client_id, $params); } else { // Create a user account $response = $this->createCustomerAccount($module_row, $package, $client_id, $params); } if ($this->Input->errors()) return; // Create the webspace/domain subscription service try { $subscription = $api->loadCommand("plesk_subscriptions", array($api_version)); $plan = array('id' => $package->meta->plan); $data = array( 'general' => array( 'name' => $params['domain'], 'ip_address' => $module_row->meta->ip_address, 'owner_login' => $params['username'], 'htype' => "vrt_hst", 'status' => "0" ), 'hosting' => array( 'properties' => array( 'ftp_login' => $params['username'], 'ftp_password' => $params['password'] ), 'ipv4' => $module_row->meta->ip_address ) ); // Set the plan on the subscription only for non-resellers; // The reseller has the plan associated with their account if ($package->meta->type != "reseller") $data['plan'] = $plan; $masked_data = $data; $masked_data['hosting']['properties']['ftp_password'] = "***"; $this->log($module_row->meta->ip_address . "|webspace:add", serialize($masked_data), "input", true); $response = $this->parseResponse($subscription->add($data), $module_row); // Set the webspace ID if (property_exists($response->result, "id")) $params['webspace_id'] = $response->result->id; } catch (Exception $e) { // API request failed $this->Input->setErrors(array('api' => array('internal' => Language::_("Plesk.!error.api.internal", true)))); return; } } // Return service fields return array( array( 'key' => "plesk_domain", 'value' => $params['domain'], 'encrypted' => 0 ), array( 'key' => "plesk_username", 'value' => $params['username'], 'encrypted' => 0 ), array( 'key' => "plesk_password", 'value' => $params['password'], 'encrypted' => 1 ), array( 'key' => "plesk_webspace_id", 'value' => (isset($response) && property_exists($response->result, "id") ? $response->result->id : null), 'encrypted' => 0 ) ); } /** * Edits the service on the remote server. Sets Input errors on failure, * preventing the service from being edited. * * @param stdClass $package A stdClass object representing the current package * @param stdClass $service A stdClass object representing the current service * @param array $vars An array of user supplied info to satisfy the request * @param stdClass $parent_package A stdClass object representing the parent service's selected package (if the current service is an addon service) * @param stdClass $parent_service A stdClass object representing the parent service of the service being edited (if the current service is an addon service) * @return array A numerically indexed array of meta fields to be stored for this service containing: * - key The key for this meta field * - value The value for this key * - encrypted Whether or not this field should be encrypted (default 0, not encrypted) * @see Module::getModule() * @see Module::getModuleRow() */ public function editService($package, $service, array $vars=null, $parent_package=null, $parent_service=null) { // Get module row and API $module_row = $this->getModuleRow(); $api = $this->getApi($module_row->meta->ip_address, $module_row->meta->username, $module_row->meta->password, $module_row->meta->port); $client_id = $service->client_id; // If no username or password given, generate them if (isset($vars['plesk_username']) && $vars['plesk_username'] == "") $vars['plesk_username'] = $this->generateUsername((isset($vars['plesk_domain']) ? $vars['plesk_domain'] : ""), $client_id); if (isset($vars['plesk_password']) && $vars['plesk_password'] == "") { $vars['plesk_password'] = $this->generatePassword(); $vars['plesk_confirm_password'] = $vars['plesk_password']; } $params = $this->getFieldsFromInput((array)$vars, $package); $this->validateService($package, $vars, true); if ($this->Input->errors()) return; // Get the service fields $service_fields = $this->serviceFieldsToObject($service->fields); // Only use the module to update the service if 'use_module' is true if ($vars['use_module'] == "true") { $api_version = $this->getApiVersion($module_row->meta->panel_version); // Update the reseller account if ($package->meta->type == "reseller") { $response = $this->updateResellerAccount($module_row, $service_fields, $params); } else { // Update the user account $response = $this->updateCustomerAccount($module_row, $service_fields, $params); } if ($this->Input->errors()) return; // Set updated fields if ($response && $response->result->status == "ok") { $service_fields->plesk_username = $params['username']; $service_fields->plesk_password = $params['password']; } // Update the webspace/domain try { $subscription = $api->loadCommand("plesk_subscriptions", array($api_version)); // Set the information to update $data = array( 'filter' => array(), 'general' => array('name' => $params['domain']) ); // Identify the subscription to change by name (domain), subscription ID, or by the customer login user if (!empty($service_fields->plesk_domain)) $data['filter']['name'] = $service_fields->plesk_domain; elseif (!empty($service_fields->plesk_webspace_id)) $data['filter']['id'] = $service_fields->plesk_webspace_id; elseif (!empty($service_fields->plesk_username)) $data['filter']['owner_login'] = $service_fields->plesk_username; $this->log($module_row->meta->ip_address . "|webspace:set", serialize($data), "input", true); $response = $this->parseResponse($subscription->set($data), $module_row); // Set updated fields if ($response && $response->result->status == "ok") { $service_fields->plesk_domain = $params['domain']; } } catch (Exception $e) { // API request failed $this->Input->setErrors(array('api' => array('internal' => Language::_("Plesk.!error.api.internal", true)))); } if ($this->Input->errors()) return; } // Set fields to update locally $fields = array("plesk_username", "plesk_password", "plesk_domain", "plesk_webspace_id"); foreach ($fields as $field) { if (property_exists($service_fields, $field) && isset($vars[$field])) $service_fields->{$field} = $vars[$field]; } // Return all the service fields $fields = array(); $encrypted_fields = array("plesk_password"); foreach ($service_fields as $key => $value) $fields[] = array('key' => $key, 'value' => $value, 'encrypted' => (in_array($key, $encrypted_fields) ? 1 : 0)); return $fields; } /** * Cancels the service on the remote server. Sets Input errors on failure, * preventing the service from being canceled. * * @param stdClass $package A stdClass object representing the current package * @param stdClass $service A stdClass object representing the current service * @param stdClass $parent_package A stdClass object representing the parent service's selected package (if the current service is an addon service) * @param stdClass $parent_service A stdClass object representing the parent service of the service being canceled (if the current service is an addon service) * @return mixed null to maintain the existing meta fields or a numerically indexed array of meta fields to be stored for this service containing: * - key The key for this meta field * - value The value for this key * - encrypted Whether or not this field should be encrypted (default 0, not encrypted) * @see Module::getModule() * @see Module::getModuleRow() */ public function cancelService($package, $service, $parent_package=null, $parent_service=null) { if (($module_row = $this->getModuleRow())) { $api = $this->getApi($module_row->meta->ip_address, $module_row->meta->username, $module_row->meta->password, $module_row->meta->port); $api_version = $this->getApiVersion($module_row->meta->panel_version); $service_fields = $this->serviceFieldsToObject($service->fields); // Cancel (delete) the service (webspace subscription) try { $subscription = $api->loadCommand("plesk_subscriptions", array($api_version)); // Identify the subscription by name (domain) or by the subscription webspace ID $data = array(); if (!empty($service_fields->plesk_domain)) $data['names'] = array($service_fields->plesk_domain); elseif (!empty($service_fields->plesk_webspace_id)) $data['ids'] = array($service_fields->plesk_webspace_id); // Some filter options must be set to avoid Plesk deleting everything if (empty($data['names']) && empty($data['ids'])) { $this->Input->setErrors(array('api' => array('filter-missing' => Language::_("Plesk.!error.api.webspace_delete_filter_missing", true)))); return; } $this->log($module_row->meta->ip_address . "|webspace:del", serialize($data), "input", true); $response = $this->parseResponse($subscription->delete($data), $module_row); } catch (Exception $e) { // API request failed $this->Input->setErrors(array('api' => array('internal' => Language::_("Plesk.!error.api.internal", true)))); } if ($this->Input->errors()) return; // Delete the customer/reseller account if ($package->meta->type == "reseller") $this->deleteResellerAccount($module_row, $service_fields); else $this->deleteCustomerAccount($module_row, $service_fields); } return null; } /** * Suspends the service on the remote server. Sets Input errors on failure, * preventing the service from being suspended. * * @param stdClass $package A stdClass object representing the current package * @param stdClass $service A stdClass object representing the current service * @param stdClass $parent_package A stdClass object representing the parent service's selected package (if the current service is an addon service) * @param stdClass $parent_service A stdClass object representing the parent service of the service being suspended (if the current service is an addon service) * @return mixed null to maintain the existing meta fields or a numerically indexed array of meta fields to be stored for this service containing: * - key The key for this meta field * - value The value for this key * - encrypted Whether or not this field should be encrypted (default 0, not encrypted) * @see Module::getModule() * @see Module::getModuleRow() */ public function suspendService($package, $service, $parent_package=null, $parent_service=null) { // Suspend the subscription $this->changeSubscriptionStatus($package, $service, $parent_package, $parent_service, true); if ($this->Input->errors()) return; // Suspend the customer/reseller account $this->changeAccountStatus($package, $service, $parent_package, $parent_service, true); return null; } /** * Unsuspends the service on the remote server. Sets Input errors on failure, * preventing the service from being unsuspended. * * @param stdClass $package A stdClass object representing the current package * @param stdClass $service A stdClass object representing the current service * @param stdClass $parent_package A stdClass object representing the parent service's selected package (if the current service is an addon service) * @param stdClass $parent_service A stdClass object representing the parent service of the service being unsuspended (if the current service is an addon service) * @return mixed null to maintain the existing meta fields or a numerically indexed array of meta fields to be stored for this service containing: * - key The key for this meta field * - value The value for this key * - encrypted Whether or not this field should be encrypted (default 0, not encrypted) * @see Module::getModule() * @see Module::getModuleRow() */ public function unsuspendService($package, $service, $parent_package=null, $parent_service=null) { // Unsuspend the subscription $this->changeSubscriptionStatus($package, $service, $parent_package, $parent_service, false); if ($this->Input->errors()) return; // Unsuspends the customer/reseller account $this->changeAccountStatus($package, $service, $parent_package, $parent_service, false); return null; } /** * Suspends or unsuspends a subscription. Sets Input errors on failure, * preventing the service from being (un)suspended. * * @param stdClass $package A stdClass object representing the current package * @param stdClass $service A stdClass object representing the current service * @param stdClass $parent_package A stdClass object representing the parent service's selected package (if the current service is an addon service) * @param stdClass $parent_service A stdClass object representing the parent service of the service being unsuspended (if the current service is an addon service) * @return mixed null to maintain the existing meta fields or a numerically indexed array of meta fields to be stored for this service containing: * - key The key for this meta field * - value The value for this key * - encrypted Whether or not this field should be encrypted (default 0, not encrypted) * @param $suspend True to suspend, false to unsuspend (optional, default true) * @see Plesk::suspendService(), Plesk::unsuspendService() */ private function changeSubscriptionStatus($package, $service, $parent_package=null, $parent_service=null, $suspend=true) { if (($module_row = $this->getModuleRow())) { $api = $this->getApi($module_row->meta->ip_address, $module_row->meta->username, $module_row->meta->password, $module_row->meta->port); $service_fields = $this->serviceFieldsToObject($service->fields); $reseller = (isset($module_row->meta->reseller) && $module_row->meta->reseller == "true"); // Suspend/unsuspend the service (webspace subscription) try { $subscription = $api->loadCommand("plesk_subscriptions", array($this->getApiVersion($module_row->meta->panel_version))); // Change the general information status $data = array('filter' => array(), 'general' => array('status' => ($suspend ? ($reseller ? "32" : "16") : "0"))); // Identify the subscription to update by name (domain), subscription ID, or by the customer login user if (!empty($service_fields->plesk_domain)) $data['filter']['name'] = $service_fields->plesk_domain; elseif (!empty($service_fields->plesk_webspace_id)) $data['filter']['id'] = $service_fields->plesk_webspace_id; elseif (!empty($service_fields->plesk_username)) $data['filter']['owner_login'] = $service_fields->plesk_username; $this->log($module_row->meta->ip_address . "|webspace:set", serialize($data), "input", true); $response = $this->parseResponse($subscription->set($data), $module_row); } catch (Exception $e) { // API request failed $this->Input->setErrors(array('api' => array('internal' => Language::_("Plesk.!error.api.internal", true)))); } } } /** * Suspends or unsuspends a customer. Sets Input errors on failure, * preventing the service from being (un)suspended. * * @param stdClass $package A stdClass object representing the current package * @param stdClass $service A stdClass object representing the current service * @param stdClass $parent_package A stdClass object representing the parent service's selected package (if the current service is an addon service) * @param stdClass $parent_service A stdClass object representing the parent service of the service being unsuspended (if the current service is an addon service) * @return mixed null to maintain the existing meta fields or a numerically indexed array of meta fields to be stored for this service containing: * - key The key for this meta field * - value The value for this key * - encrypted Whether or not this field should be encrypted (default 0, not encrypted) * @param $suspend True to suspend, false to unsuspend (optional, default true) * @see Plesk::suspendService(), Plesk::unsuspendService() */ private function changeAccountStatus($package, $service, $parent_package=null, $parent_service=null, $suspend=true) { if (($module_row = $this->getModuleRow())) { $api = $this->getApi($module_row->meta->ip_address, $module_row->meta->username, $module_row->meta->password, $module_row->meta->port); $service_fields = $this->serviceFieldsToObject($service->fields); $reseller_account = (isset($module_row->meta->reseller) && $module_row->meta->reseller == "true"); // Suspend/unsuspend the account try { if ($package->meta->type == "reseller") { // Update reseller account $reseller = $api->loadCommand("plesk_reseller_accounts", array($this->getApiVersion($module_row->meta->panel_version))); $data = array('filter' => array('login' => $service_fields->plesk_username), 'general' => array('status' => ($suspend ? ($reseller_account ? "32" : "16") : "0"))); $this->log($module_row->meta->ip_address . "|reseller:set", serialize($data), "input", true); $response = $this->parseResponse($reseller->set($data), $module_row, true); } else { // Update customer account $customer = $api->loadCommand("plesk_customer_accounts", array($this->getApiVersion($module_row->meta->panel_version))); $data = array('filter' => array('login' => $service_fields->plesk_username), 'general' => array('status' => ($suspend ? ($reseller_account ? "32" : "16") : "0"))); $this->log($module_row->meta->ip_address . "|customer:set", serialize($data), "input", true); $response = $this->parseResponse($customer->set($data), $module_row, true); } } catch (Exception $e) { // API request failed $this->Input->setErrors(array('api' => array('internal' => Language::_("Plesk.!error.api.internal", true)))); } } } /** * Allows the module to perform an action when the service is ready to renew. * Sets Input errors on failure, preventing the service from renewing. * * @param stdClass $package A stdClass object representing the current package * @param stdClass $service A stdClass object representing the current service * @param stdClass $parent_package A stdClass object representing the parent service's selected package (if the current service is an addon service) * @param stdClass $parent_service A stdClass object representing the parent service of the service being renewed (if the current service is an addon service) * @return mixed null to maintain the existing meta fields or a numerically indexed array of meta fields to be stored for this service containing: * - key The key for this meta field * - value The value for this key * - encrypted Whether or not this field should be encrypted (default 0, not encrypted) * @see Module::getModule() * @see Module::getModuleRow() */ public function renewService($package, $service, $parent_package=null, $parent_service=null) { // Nothing to do return null; } /** * Updates the package for the service on the remote server. Sets Input * errors on failure, preventing the service's package from being changed. * * @param stdClass $package_from A stdClass object representing the current package * @param stdClass $package_to A stdClass object representing the new package * @param stdClass $service A stdClass object representing the current service * @param stdClass $parent_package A stdClass object representing the parent service's selected package (if the current service is an addon service) * @param stdClass $parent_service A stdClass object representing the parent service of the service being changed (if the current service is an addon service) * @return mixed null to maintain the existing meta fields or a numerically indexed array of meta fields to be stored for this service containing: * - key The key for this meta field * - value The value for this key * - encrypted Whether or not this field should be encrypted (default 0, not encrypted) * @see Module::getModule() * @see Module::getModuleRow() */ public function changeServicePackage($package_from, $package_to, $service, $parent_package=null, $parent_service=null) { if (($module_row = $this->getModuleRow())) { if (!isset($this->DataStructure)) Loader::loadHelpers($this, array("DataStructure")); if (!isset($this->ArrayHelper)) $this->ArrayHelper = $this->DataStructure->create("Array"); $api = $this->getApi($module_row->meta->ip_address, $module_row->meta->username, $module_row->meta->password, $module_row->meta->port); // Set the plan/type to update $update_plan = array('reseller' => false, 'to_plan' => $package_to->meta->plan, 'from_plan' => $package_from->meta->plan); // Set whether a reseller plan is being changed $from_reseller_plan = (isset($package_from->meta->reseller_plan) ? $package_from->meta->reseller_plan : null); $to_reseller_plan = (isset($package_to->meta->reseller_plan) ? $package_to->meta->reseller_plan : null); // Reseller plan changed, upgrade the customer and set the reseller plan to update if ($from_reseller_plan != $to_reseller_plan) { // Changing reseller plans $update_plan['reseller'] = true; $update_plan['to_plan'] = $to_reseller_plan; $update_plan['from_plan'] = $from_reseller_plan; // Cannot downgrade from reseller account to customer account if (!empty($from_reseller_plan) && empty($to_reseller_plan)) { $this->Input->setErrors(array('downgrade' => array('unsupported' => Language::_("Plesk.!error.downgrade.unsupported", true)))); } elseif (empty($from_reseller_plan) && !empty($to_reseller_plan)) { // Upgrade the customer account to a reseller account $this->upgradeCustomerToReseller($module_row, $service); } } // Do not continue if there are errors if ($this->Input->errors()) return; // Only change a plan change if it has changed; a customer account plan or a reseller plan if ($update_plan['from_plan'] != $update_plan['to_plan']) { $service_fields = $this->serviceFieldsToObject($service->fields); // Fetch all of the plans $plans = $this->getPleskPlans($module_row, $update_plan['reseller'], false); // Determine the plan's GUID based on the plan ID we currently have $plans = $this->ArrayHelper->numericToKey($plans, "id", "guid"); $plan_guid = ""; if (isset($plans[$update_plan['to_plan']])) $plan_guid = $plans[$update_plan['to_plan']]; $api_version = $this->getApiVersion($module_row->meta->panel_version); // Switch reseller plan if ($update_plan['reseller']) { try { // Change customer account subscription plan $reseller = $api->loadCommand("plesk_reseller_accounts", array($api_version)); // Set the new plan to switch to using the plan's GUID $data = array('filter' => array('login' => $service_fields->plesk_username), 'plan' => array('guid' => $plan_guid)); $this->log($module_row->meta->ip_address . "|reseller:switch-subscription", serialize($data), "input", true); $response = $this->parseResponse($reseller->changePlan($data), $module_row); } catch (Exception $e) { // API request failed $this->Input->setErrors(array('api' => array('internal' => Language::_("Plesk.!error.api.internal", true)))); } } if ($this->Input->errors()) return; // Also switch the subscription plan if it has changed if ($package_from->meta->plan != $package_to->meta->plan) { // Since the reseller plan was update, we also now need to fetch the subscription plans if ($update_plan['reseller']) { // Fetch subscription plans $plans = $this->getPleskPlans($module_row, false, false); // Determine the plan's GUID based on the plan ID we currently have $plans = $this->ArrayHelper->numericToKey($plans, "id", "guid"); $plan_guid = ""; if (isset($plans[$update_plan['to_plan']])) $plan_guid = $plans[$update_plan['to_plan']]; } try { // Change customer account subscription plan $subscription = $api->loadCommand("plesk_subscriptions", array($api_version)); // Set the new plan to switch to using the plan's GUID $data = array('filter' => array(), 'plan' => array('guid' => $plan_guid)); // Identify the subscription to update by name (domain), subscription ID, or by the customer login user if (!empty($service_fields->plesk_domain)) $data['filter']['name'] = $service_fields->plesk_domain; elseif (!empty($service_fields->plesk_webspace_id)) $data['filter']['id'] = $service_fields->plesk_webspace_id; elseif (!empty($service_fields->plesk_username)) $data['filter']['owner_login'] = $service_fields->plesk_username; $this->log($module_row->meta->ip_address . "|webspace:switch-subscription", serialize($data), "input", true); $response = $this->parseResponse($subscription->changePlan($data), $module_row); } catch (Exception $e) { // API request failed $this->Input->setErrors(array('api' => array('internal' => Language::_("Plesk.!error.api.internal", true)))); } } } } // Nothing to do return null; } /** * Validates input data when attempting to add a package, returns the meta * data to save when adding a package. Performs any action required to add * the package on the remote server. Sets Input errors on failure, * preventing the package from being added. * * @param array An array of key/value pairs used to add the package * @return array A numerically indexed array of meta fields to be stored for this package containing: * - key The key for this meta field * - value The value for this key * - encrypted Whether or not this field should be encrypted (default 0, not encrypted) * @see Module::getModule() * @see Module::getModuleRow() */ public function addPackage(array $vars=null) { // Set rules to validate input data $this->Input->setRules($this->getPackageRules($vars)); // Build meta data to return $meta = array(); if ($this->Input->validates($vars)) { // Return all package meta fields foreach ($vars['meta'] as $key => $value) { $meta[] = array( 'key' => $key, 'value' => $value, 'encrypted' => 0 ); } } return $meta; } /** * Validates input data when attempting to edit a package, returns the meta * data to save when editing a package. Performs any action required to edit * the package on the remote server. Sets Input errors on failure, * preventing the package from being edited. * * @param stdClass $package A stdClass object representing the selected package * @param array An array of key/value pairs used to edit the package * @return array A numerically indexed array of meta fields to be stored for this package containing: * - key The key for this meta field * - value The value for this key * - encrypted Whether or not this field should be encrypted (default 0, not encrypted) * @see Module::getModule() * @see Module::getModuleRow() */ public function editPackage($package, array $vars=null) { // Set rules to validate input data $this->Input->setRules($this->getPackageRules($vars)); // Build meta data to return $meta = array(); if ($this->Input->validates($vars)) { // Return all package meta fields foreach ($vars['meta'] as $key => $value) { $meta[] = array( 'key' => $key, 'value' => $value, 'encrypted' => 0 ); } } return $meta; } /** * Returns the rendered view of the manage module page * * @param mixed $module A stdClass object representing the module and its rows * @param array $vars An array of post data submitted to or on the manage module page (used to repopulate fields after an error) * @return string HTML content containing information to display when viewing the manager module page */ public function manageModule($module, array &$vars) { // Load the view into this object, so helpers can be automatically added to the view $this->view = new View("manage", "default"); $this->view->base_uri = $this->base_uri; $this->view->setDefaultView("components" . DS . "modules" . DS . "plesk" . DS); // Load the helpers required for this view Loader::loadHelpers($this, array("Form", "Html", "Widget")); $this->view->set("module", $module); return $this->view->fetch(); } /** * Returns the rendered view of the add module row page * * @param array $vars An array of post data submitted to or on the add module row page (used to repopulate fields after an error) * @return string HTML content containing information to display when viewing the add module row page */ public function manageAddRow(array &$vars) { // Load the view into this object, so helpers can be automatically added to the view $this->view = new View("add_row", "default"); $this->view->base_uri = $this->base_uri; $this->view->setDefaultView("components" . DS . "modules" . DS . "plesk" . DS); // Load the helpers required for this view Loader::loadHelpers($this, array("Form", "Html", "Widget")); // Set default port if (empty($vars)) $vars['port'] = "8443"; $this->view->set("vars", (object)$vars); $this->view->set("panel_versions", $this->getSupportedPanelVersions(true)); return $this->view->fetch(); } /** * Returns the rendered view of the edit module row page * * @param stdClass $module_row The stdClass representation of the existing module row * @param array $vars An array of post data submitted to or on the edit module row page (used to repopulate fields after an error) * @return string HTML content containing information to display when viewing the edit module row page */ public function manageEditRow($module_row, array &$vars) { // Load the view into this object, so helpers can be automatically added to the view $this->view = new View("edit_row", "default"); $this->view->base_uri = $this->base_uri; $this->view->setDefaultView("components" . DS . "modules" . DS . "plesk" . DS); // Load the helpers required for this view Loader::loadHelpers($this, array("Form", "Html", "Widget")); if (empty($vars)) $vars = $module_row->meta; $this->view->set("vars", (object)$vars); $this->view->set("panel_versions", $this->getSupportedPanelVersions(true)); return $this->view->fetch(); } /** * Adds the module row on the remote server. Sets Input errors on failure, * preventing the row from being added. * * @param array $vars An array of module info to add * @return array A numerically indexed array of meta fields for the module row containing: * - key The key for this meta field * - value The value for this key * - encrypted Whether or not this field should be encrypted (default 0, not encrypted) */ public function addModuleRow(array &$vars) { $meta_fields = array("server_name", "host_name", "ip_address", "port", "username", "password", "panel_version", "reseller"); $encrypted_fields = array("username", "password"); // Set checkbox value for whether this user is a reseller $vars['reseller'] = (isset($vars['reseller']) && $vars['reseller'] == "true" ? "true" : "false"); $this->Input->setRules($this->getRowRules($vars)); // Validate module row if ($this->Input->validates($vars)) { // Build the meta data for this row $meta = array(); foreach ($vars as $key => $value) { if (in_array($key, $meta_fields)) { $meta[] = array( 'key' => $key, 'value' => $value, 'encrypted' => in_array($key, $encrypted_fields) ? 1 : 0 ); } } return $meta; } } /** * Edits the module row on the remote server. Sets Input errors on failure, * preventing the row from being updated. * * @param stdClass $module_row The stdClass representation of the existing module row * @param array $vars An array of module info to update * @return array A numerically indexed array of meta fields for the module row containing: * - key The key for this meta field * - value The value for this key * - encrypted Whether or not this field should be encrypted (default 0, not encrypted) */ public function editModuleRow($module_row, array &$vars) { // Same as adding return $this->addModuleRow($vars); } /** * Deletes the module row on the remote server. Sets Input errors on failure, * preventing the row from being deleted. * * @param stdClass $module_row The stdClass representation of the existing module row */ public function deleteModuleRow($module_row) { // Nothing to do return null; } /** * Returns an array of available service delegation order methods. The module * will determine how each method is defined. For example, the method "first" * may be implemented such that it returns the module row with the least number * of services assigned to it. * * @return array An array of order methods in key/value pairs where the key is the type to be stored for the group and value is the name for that option * @see Module::selectModuleRow() */ public function getGroupOrderOptions() { return array('first'=>Language::_("Plesk.order_options.first", true)); } /** * Determines which module row should be attempted when a service is provisioned * for the given group based upon the order method set for that group. * * @return int The module row ID to attempt to add the service with * @see Module::getGroupOrderOptions() */ public function selectModuleRow($module_group_id) { if (!isset($this->ModuleManager)) Loader::loadModels($this, array("ModuleManager")); $group = $this->ModuleManager->getGroup($module_group_id); if ($group) { switch ($group->add_order) { default: case "first": foreach ($group->rows as $row) { return $row->id; } break; } } return 0; } /** * Returns all fields used when adding/editing a package, including any * javascript to execute when the page is rendered with these fields. * * @param $vars stdClass A stdClass object representing a set of post fields * @return ModuleFields A ModuleFields object, containing the fields to render as well as any additional HTML markup to include */ public function getPackageFields($vars=null) { Loader::loadHelpers($this, array("Html")); $fields = new ModuleFields(); $fields->setHtml(" <script type=\"text/javascript\"> $(document).ready(function() { $('input[name=\"meta[type]\"]').change(function() { fetchModuleOptions(); }); }); </script> "); // Fetch all packages available for the given server or server group $module_row = null; if (isset($vars->module_group) && $vars->module_group == "") { if (isset($vars->module_row) && $vars->module_row > 0) { $module_row = $this->getModuleRow($vars->module_row); } else { $rows = $this->getModuleRows(); if (isset($rows[0])) $module_row = $rows[0]; unset($rows); } } else { // Fetch the 1st server from the list of servers in the selected group $rows = $this->getModuleRows($vars->module_group); if (isset($rows[0])) $module_row = $rows[0]; unset($rows); } // Fetch plans $plans = array('' => Language::_("Plesk.please_select", true)); if ($module_row) { $plans += $this->getPleskPlans($module_row); } // Set the type of account (standard or reseller) $type = $fields->label(Language::_("Plesk.package_fields.type", true), "plesk_type"); $type_standard = $fields->label(Language::_("Plesk.package_fields.type_standard", true), "plesk_type_standard"); $type_reseller = $fields->label(Language::_("Plesk.package_fields.type_reseller", true), "plesk_type_reseller"); $type->attach($fields->fieldRadio("meta[type]", "standard", $this->Html->ifSet($vars->meta['type'], "standard") == "standard", array('id'=>"plesk_type_standard"), $type_standard)); $type->attach($fields->fieldRadio("meta[type]", "reseller", $this->Html->ifSet($vars->meta['type']) == "reseller", array('id'=>"plesk_type_reseller"), $type_reseller)); $fields->setField($type); // Set the Plesk plans as selectable options $package = $fields->label(Language::_("Plesk.package_fields.plan", true), "plesk_plan"); $package->attach($fields->fieldSelect("meta[plan]", $plans, $this->Html->ifSet($vars->meta['plan']), array('id'=>"plesk_plan"))); $fields->setField($package); // Set the reseller account plan if (isset($vars->meta['type']) && $vars->meta['type'] == "reseller") { // Fetch the reseller plans $reseller_plans = array('' => Language::_("Plesk.please_select", true)); $reseller_plans += $this->getPleskPlans($module_row, true); // Set the Plesk reseller account plans as selectable options $package = $fields->label(Language::_("Plesk.package_fields.reseller_plan", true), "plesk_reseller_plan"); $package->attach($fields->fieldSelect("meta[reseller_plan]", $reseller_plans, $this->Html->ifSet($vars->meta['reseller_plan']), array('id'=>"plesk_reseller_plan"))); $fields->setField($package); } return $fields; } /** * Returns an array of key values for fields stored for a module, package, * and service under this module, used to substitute those keys with their * actual module, package, or service meta values in related emails. * * @return array A multi-dimensional array of key/value pairs where each key is one of 'module', 'package', or 'service' and each value is a numerically indexed array of key values that match meta fields under that category. * @see Modules::addModuleRow() * @see Modules::editModuleRow() * @see Modules::addPackage() * @see Modules::editPackage() * @see Modules::addService() * @see Modules::editService() */ public function getEmailTags() { return array( 'module' => array("host_name", "ip_address", "port"), 'package' => array("type", "plan", "reseller_plan"), 'service' => array("plesk_domain", "plesk_username", "plesk_password", "plesk_webspace_id") ); } /** * Returns all fields to display to an admin attempting to add a service with the module * * @param stdClass $package A stdClass object representing the selected package * @param $vars stdClass A stdClass object representing a set of post fields * @return ModuleFields A ModuleFields object, containg the fields to render as well as any additional HTML markup to include */ public function getAdminAddFields($package, $vars=null) { Loader::loadHelpers($this, array("Html")); $fields = new ModuleFields(); // Create domain label $domain = $fields->label(Language::_("Plesk.service_field.domain", true), "plesk_domain"); // Create domain field and attach to domain label $domain->attach($fields->fieldText("plesk_domain", $this->Html->ifSet($vars->plesk_domain), array('id'=>"plesk_domain"))); // Set the label as a field $fields->setField($domain); // Create username label $username = $fields->label(Language::_("Plesk.service_field.username", true), "plesk_username"); // Create username field and attach to username label $username->attach($fields->fieldText("plesk_username", $this->Html->ifSet($vars->plesk_username), array('id'=>"plesk_username"))); // Add tooltip $tooltip = $fields->tooltip(Language::_("Plesk.service_field.tooltip.username", true)); $username->attach($tooltip); // Set the label as a field $fields->setField($username); // Create password label $password = $fields->label(Language::_("Plesk.service_field.password", true), "plesk_password"); // Create password field and attach to password label $password->attach($fields->fieldPassword("plesk_password", array('id'=>"plesk_password", 'value'=>$this->Html->ifSet($vars->plesk_password)))); // Add tooltip $tooltip = $fields->tooltip(Language::_("Plesk.service_field.tooltip.password", true)); $password->attach($tooltip); // Set the label as a field $fields->setField($password); // Confirm password label $confirm_password = $fields->label(Language::_("Plesk.service_field.confirm_password", true), "plesk_confirm_password"); // Create confirm password field and attach to password label $confirm_password->attach($fields->fieldPassword("plesk_confirm_password", array('id'=>"plesk_confirm_password", 'value'=>$this->Html->ifSet($vars->plesk_password)))); // Add tooltip $confirm_password->attach($tooltip); // Set the label as a field $fields->setField($confirm_password); $webspace_id = $fields->label(Language::_("Plesk.service_field.webspace_id", true), "plesk_webspace_id"); // Create confirm password field and attach to password label $webspace_id->attach($fields->fieldText("plesk_webspace_id", $this->Html->ifSet($vars->plesk_webspace_id), array('id'=>"plesk_webspace_id"))); // Add tooltip $tooltip = $fields->tooltip(Language::_("Plesk.service_field.tooltip.webspace_id", true)); $webspace_id->attach($tooltip); // Set the label as a field $fields->setField($webspace_id); return $fields; } /** * Returns all fields to display to a client attempting to add a service with the module * * @param stdClass $package A stdClass object representing the selected package * @param $vars stdClass A stdClass object representing a set of post fields * @return ModuleFields A ModuleFields object, containg the fields to render as well as any additional HTML markup to include */ public function getClientAddFields($package, $vars=null) { Loader::loadHelpers($this, array("Html")); $fields = new ModuleFields(); // Create domain label $domain = $fields->label(Language::_("Plesk.service_field.domain", true), "plesk_domain"); // Create domain field and attach to domain label $domain->attach($fields->fieldText("plesk_domain", $this->Html->ifSet($vars->plesk_domain, $this->Html->ifSet($vars->domain)), array('id'=>"plesk_domain"))); // Set the label as a field $fields->setField($domain); return $fields; } /** * Returns all fields to display to an admin attempting to edit a service with the module * * @param stdClass $package A stdClass object representing the selected package * @param $vars stdClass A stdClass object representing a set of post fields * @return ModuleFields A ModuleFields object, containg the fields to render as well as any additional HTML markup to include */ public function getAdminEditFields($package, $vars=null) { Loader::loadHelpers($this, array("Html")); $fields = new ModuleFields(); // Create domain label $domain = $fields->label(Language::_("Plesk.service_field.domain", true), "plesk_domain"); // Create domain field and attach to domain label $domain->attach($fields->fieldText("plesk_domain", $this->Html->ifSet($vars->plesk_domain), array('id'=>"plesk_domain"))); // Set the label as a field $fields->setField($domain); // Create username label $username = $fields->label(Language::_("Plesk.service_field.username", true), "plesk_username"); // Create username field and attach to username label $username->attach($fields->fieldText("plesk_username", $this->Html->ifSet($vars->plesk_username), array('id'=>"plesk_username"))); // Add tooltip $tooltip = $fields->tooltip(Language::_("Plesk.service_field.tooltip.username", true)); $username->attach($tooltip); // Set the label as a field $fields->setField($username); // Create password label $password = $fields->label(Language::_("Plesk.service_field.password", true), "plesk_password"); // Create password field and attach to password label $password->attach($fields->fieldPassword("plesk_password", array('id'=>"plesk_password", 'value'=>$this->Html->ifSet($vars->plesk_password)))); // Add tooltip $tooltip = $fields->tooltip(Language::_("Plesk.service_field.tooltip.password", true)); $password->attach($tooltip); // Set the label as a field $fields->setField($password); // Confirm password label $confirm_password = $fields->label(Language::_("Plesk.service_field.confirm_password", true), "plesk_confirm_password"); // Create confirm password field and attach to password label $confirm_password->attach($fields->fieldPassword("plesk_confirm_password", array('id'=>"plesk_confirm_password", 'value'=>$this->Html->ifSet($vars->plesk_password)))); // Add tooltip $confirm_password->attach($tooltip); // Set the label as a field $fields->setField($confirm_password); $webspace_id = $fields->label(Language::_("Plesk.service_field.webspace_id", true), "plesk_webspace_id"); // Create confirm password field and attach to password label $webspace_id->attach($fields->fieldText("plesk_webspace_id", $this->Html->ifSet($vars->plesk_webspace_id), array('id'=>"plesk_webspace_id"))); // Add tooltip $tooltip = $fields->tooltip(Language::_("Plesk.service_field.tooltip.webspace_id_edit", true)); $webspace_id->attach($tooltip); // Set the label as a field $fields->setField($webspace_id); return $fields; } /** * Fetches the HTML content to display when viewing the service info in the * admin interface. * * @param stdClass $service A stdClass object representing the service * @param stdClass $package A stdClass object representing the service's package * @return string HTML content containing information to display when viewing the service info */ public function getAdminServiceInfo($service, $package) { $row = $this->getModuleRow(); // Load the view into this object, so helpers can be automatically added to the view $this->view = new View("admin_service_info", "default"); $this->view->base_uri = $this->base_uri; $this->view->setDefaultView("components" . DS . "modules" . DS . "plesk" . DS); // Load the helpers required for this view Loader::loadHelpers($this, array("Form", "Html")); $this->view->set("module_row", $row); $this->view->set("package", $package); $this->view->set("service", $service); $this->view->set("service_fields", $this->serviceFieldsToObject($service->fields)); return $this->view->fetch(); } /** * Fetches the HTML content to display when viewing the service info in the * client interface. * * @param stdClass $service A stdClass object representing the service * @param stdClass $package A stdClass object representing the service's package * @return string HTML content containing information to display when viewing the service info */ public function getClientServiceInfo($service, $package) { $row = $this->getModuleRow(); // Load the view into this object, so helpers can be automatically added to the view $this->view = new View("client_service_info", "default"); $this->view->base_uri = $this->base_uri; $this->view->setDefaultView("components" . DS . "modules" . DS . "plesk" . DS); // Load the helpers required for this view Loader::loadHelpers($this, array("Form", "Html")); $this->view->set("module_row", $row); $this->view->set("package", $package); $this->view->set("service", $service); $this->view->set("service_fields", $this->serviceFieldsToObject($service->fields)); return $this->view->fetch(); } /** * Statistics tab * * @param stdClass $package A stdClass object representing the current package * @param stdClass $service A stdClass object representing the current service * @param array $get Any GET parameters * @param array $post Any POST parameters * @param array $files Any FILES parameters * @return string The string representing the contents of this tab */ public function tabStats($package, $service, array $get=null, array $post=null, array $files=null) { $this->view = new View("tab_stats", "default"); // Load the helpers required for this view Loader::loadHelpers($this, array("Form", "Html")); $stats = $this->getStats($package, $service); $this->view->set("stats", $stats); #$this->view->set("user_type", $package->meta->type); $this->view->setDefaultView("components" . DS . "modules" . DS . "plesk" . DS); return $this->view->fetch(); } /** * Client Statistics tab * * @param stdClass $package A stdClass object representing the current package * @param stdClass $service A stdClass object representing the current service * @param array $get Any GET parameters * @param array $post Any POST parameters * @param array $files Any FILES parameters * @return string The string representing the contents of this tab */ public function tabClientStats($package, $service, array $get=null, array $post=null, array $files=null) { $this->view = new View("tab_client_stats", "default"); // Load the helpers required for this view Loader::loadHelpers($this, array("Form", "Html")); $stats = $this->getStats($package, $service); $this->view->set("stats", $stats); #$this->view->set("user_type", $package->meta->type); $this->view->setDefaultView("components" . DS . "modules" . DS . "plesk" . DS); return $this->view->fetch(); } /** * Fetches all status for a given subscription service * * @param stdClass $package A stdClass object representing the current package * @param stdClass $service A stdClass object representing the current service * @return stdClass A stdClass object representing all of the stats for the account */ private function getStats($package, $service) { $module_row = $this->getModuleRow(); $api = $this->getApi($module_row->meta->ip_address, $module_row->meta->username, $module_row->meta->password, $module_row->meta->port); $service_fields = $this->serviceFieldsToObject($service->fields); $stats = new stdClass(); $stats->account_info = array( 'domain' => $service_fields->plesk_domain, 'ip_address' => $module_row->meta->ip_address ); $stats->disk_usage = array( 'used' => null, 'used_formatted' => null, 'limit' => null, 'limit_formatted' => null, 'unused' => null, 'unused_formatted' => Language::_("Plesk.stats.unlimited", true) ); $stats->bandwidth_usage = array( 'used' => null, 'used_formatted' => null, 'limit' => null, 'limit_formatted' => null, 'unused' => null, 'unused_formatted' => Language::_("Plesk.stats.unlimited", true) ); $response = false; try { $subscription = $api->loadCommand("plesk_subscriptions", array($this->getApiVersion($module_row->meta->panel_version))); // Fetch these stats $options = array("gen_info", "hosting", "limits", "stat", "prefs", "disk_usage", "performance", "subscriptions", "permissions", "plan-items", "php-settings"); $data = array( 'id' => $service_fields->plesk_webspace_id, 'settings' => array() ); // Set the stats we want to fetch foreach ($options as $option) { $data['settings'][$option] = true; } $this->log($module_row->meta->ip_address . "|webspace:get", serialize($data), "input", true); $response = $this->parseResponse($subscription->get($data), $module_row); } catch (Exception $e) { // API request failed $this->Input->setErrors(array('api' => array('internal' => Language::_("Plesk.!error.api.internal", true)))); } // Format the results for the stats we will display if ($response && isset($response->result->data)) { $data = $response->result->data; // Set account info $stats->account_info['domain'] = $data->gen_info->name; $stats->account_info['ip_address'] = $data->gen_info->dns_ip_address; // Fetch account limits $totals = array(); foreach ($data->limits->limit as $item) { $totals[$item->name] = $item->value; } // Set bandwidth usage $stats->bandwidth_usage['used'] = $data->stat->traffic; $stats->bandwidth_usage['limit'] = (isset($totals['max_traffic']) ? $totals['max_traffic'] : null); // Set disk usage $stats->disk_usage['limit'] = (isset($totals['disk_space']) ? $totals['disk_space'] : null); $total_disk_usage = 0; $disk_usage_options = array("httpdocs", "httpsdocs", "subdomains", "web_users", "anonftp", "logs", "dbases", "mailboxes", "webapps", "maillists", "domaindumps", "configs", "chroot"); foreach ($disk_usage_options as $option) { if (property_exists($data->disk_usage, $option)) $total_disk_usage += $data->disk_usage->{$option}; } $stats->disk_usage['used'] = $total_disk_usage; // Format the values if ($stats->disk_usage['limit'] == "-1") $stats->disk_usage['limit_formatted'] = Language::_("Plesk.stats.unlimited", true); else { $stats->disk_usage['limit_formatted'] = $this->convertBytesToString($stats->disk_usage['limit']); // Set unused $stats->disk_usage['unused'] = abs($stats->disk_usage['limit']-$stats->disk_usage['used']); $stats->disk_usage['unused_formatted'] = $this->convertBytesToString($stats->disk_usage['unused']); } if ($stats->bandwidth_usage['limit'] == "-1") $stats->bandwidth_usage['limit_formatted'] = Language::_("Plesk.stats.unlimited", true); else { $stats->bandwidth_usage['limit_formatted'] = $this->convertBytesToString($stats->bandwidth_usage['limit']); // Set unused $stats->bandwidth_usage['unused'] = abs($stats->bandwidth_usage['limit']-$stats->bandwidth_usage['used']); $stats->bandwidth_usage['unused_formatted'] = $this->convertBytesToString($stats->bandwidth_usage['unused']); } $stats->disk_usage['used_formatted'] = $this->convertBytesToString($stats->disk_usage['used']); $stats->bandwidth_usage['used_formatted'] = $this->convertBytesToString($stats->bandwidth_usage['used']); } return $stats; } /** * Converts bytes to a string representation including the type * * @param int $bytes The number of bytes * @return string A formatted amount including the type (B, KB, MB, GB) */ private function convertBytesToString($bytes) { $step = 1024; $unit = "B"; if (($value = number_format($bytes/($step*$step*$step), 2)) >= 1) $unit = "GB"; elseif (($value = number_format($bytes/($step*$step), 2)) >= 1) $unit = "MB"; elseif (($value = number_format($bytes/($step), 2)) >= 1) $unit = "KB"; else $value = $bytes; return Language::_("Plesk.!bytes.value", true, $value, $unit); } /** * Returns an array of service fields to set for the service using the given input * * @param array $vars An array of key/value input pairs * @param stdClass $package A stdClass object representing the package for the service * @return array An array of key/value pairs representing service fields */ private function getFieldsFromInput(array $vars, $package) { $fields = array( 'domain' => isset($vars['plesk_domain']) ? $vars['plesk_domain'] : null, 'username' => isset($vars['plesk_username']) ? $vars['plesk_username']: null, 'password' => isset($vars['plesk_password']) ? $vars['plesk_password'] : null, 'webspace_id' => !empty($vars['plesk_webspace_id']) ? $vars['plesk_webspace_id'] : null ); return $fields; } /** * Retrieves the module row given the server or server group * * @param string $module_row The module row ID * @param string $module_group The module group (optional, default "") * @return mixed An stdClass object representing the module row, or null if it could not be determined */ private function getModuleRowByServer($module_row, $module_group = "") { // Fetch the module row available for this package $row = null; if ($module_group == "") { if ($module_row > 0) { $row = $this->getModuleRow($module_row); } else { $rows = $this->getModuleRows(); if (isset($rows[0])) $row = $rows[0]; unset($rows); } } else { // Fetch the 1st server from the list of servers in the selected group $rows = $this->getModuleRows($module_group); if (isset($rows[0])) $row = $rows[0]; unset($rows); } return $row; } /** * Fetches a listing of all service plans configured in Plesk for the given server * * @param stdClass $module_row A stdClass object representing a single server * @param boolean $reseller True to fetch reseller plans, false for user/hosting plans (optional, default false) * @param boolean $format True to format the response as a key/value pair (id => name), false to fetch all data (optional, default true) * @return array An array of packages in key/value pairs */ private function getPleskPlans($module_row, $reseller = false, $format = true) { if (!isset($this->DataStructure)) Loader::loadHelpers($this, array("DataStructure")); if (!isset($this->ArrayHelper)) $this->ArrayHelper = $this->DataStructure->create("Array"); $api = $this->getApi($module_row->meta->ip_address, $module_row->meta->username, $module_row->meta->password, $module_row->meta->port); // Fetch the plans try { $api_version = $this->getApiVersion($module_row->meta->panel_version); // Fetch reseller plans if ($reseller) { $service_plans = $api->loadCommand("plesk_reseller_plans", array($api_version)); // Fetch all reseller plans $data = array('filter' => array('all' => true)); $this->log($module_row->meta->ip_address . "|reseller-plan:get", serialize($data), "input", true); $response = $this->parseResponse($service_plans->get($data), $module_row); } else { // Fetch user/hosting plans $service_plans = $api->loadCommand("plesk_service_plans", array($api_version)); // Fetch all reseller plans $data = array('filter' => array()); $this->log($module_row->meta->ip_address . "|service-plan:get", serialize($data), "input", true); $response = $this->parseResponse($service_plans->get($data), $module_row); } // Response is only an array if there is more than 1 result returned if (is_array($response->result)) { $result = $response->result; if ($format) $result = $this->ArrayHelper->numericToKey($response->result, "id", "name"); } else { // Only 1 result $result = array($response->result); if ($format) { $result = array(); if (property_exists($response->result, "id") && property_exists($response->result, "name")) $result = array($response->result->id => $response->result->name); } } return $result; } catch (Exception $e) { // API request failed $this->Input->setErrors(array('api' => array('internal' => Language::_("Plesk.!error.api.internal", true)))); } return array(); } /** * Upgrades a customer account to a reseller account. Sets Input errors on failure * * @param stdClass $module_row An stdClass object representing a single server * @param stdClass $service An stdClass object representing the service to upgrade */ private function upgradeCustomerToReseller($module_row, $service) { $api = $this->getApi($module_row->meta->ip_address, $module_row->meta->username, $module_row->meta->password, $module_row->meta->port); $service_fields = $this->serviceFieldsToObject($service->fields); // Upgrade the account try { $customer = $api->loadCommand("plesk_customer_accounts", array($this->getApiVersion($module_row->meta->panel_version))); // Upgrade this customer account $data = array('filter' => array('login' => $service_fields->plesk_username)); $this->log($module_row->meta->ip_address . "|customer:convert-to-reseller", serialize($data), "input", true); $response = $this->parseResponse($customer->upgrade($data), $module_row); } catch (Exception $e) { // API request failed $this->Input->setErrors(array('api' => array('internal' => Language::_("Plesk.!error.api.internal", true)))); } } /** * Creates a reseller account. Sets Input errors on failure * * @param stdClass $module_row A stdClass object representing a single server * @param stdClass $package A stdClass object representing the selected package * @param int $client_id The ID of the client this customer account is being created on behalf of * @param array $params A list of data to pass into the reseller account * - username The account username * - password The account password * @return stdClass An stdClass object representing the response */ private function createResellerAccount($module_row, $package, $client_id, $params) { // Fetch the client fields $client_params = $this->getClientAccountFields($client_id); $api = $this->getApi($module_row->meta->ip_address, $module_row->meta->username, $module_row->meta->password, $module_row->meta->port); try { $reseller = $api->loadCommand("plesk_reseller_accounts", array($this->getApiVersion($module_row->meta->panel_version))); // Create the customer account $data = array_merge($client_params, array('login' => $params['username'], 'password' => $params['password'], 'plan' => array('id' => $package->meta->reseller_plan))); $masked_data = $data; $masked_data['password'] = "***"; $this->log($module_row->meta->ip_address . "|reseller:add", serialize($masked_data), "input", true); $response = $this->parseResponse($reseller->add($data), $module_row); } catch (Exception $e) { // API request failed $this->Input->setErrors(array('api' => array('internal' => Language::_("Plesk.!error.api.internal", true)))); } return (isset($response) ? $response : new stdClass()); } /** * Updates a reseller account. Sets Input errors on failure * * @param stdClass $module_row A stdClass object representing a single server * @param stdClass $service_fields An stdClass object representing the service fields * @param array $params A list of data to pass into the reseller account * - username The account username * - password The account password * @return stdClass An stdClass object representing the response */ private function updateResellerAccount($module_row, $service_fields, $params) { $api = $this->getApi($module_row->meta->ip_address, $module_row->meta->username, $module_row->meta->password, $module_row->meta->port); // Update the customer try { $reseller = $api->loadCommand("plesk_reseller_accounts", array($this->getApiVersion($module_row->meta->panel_version))); // Set the information to update $data = array( // Update this user 'filter' => array('login' => $service_fields->plesk_username), // with this information 'general' => array( 'login' => $params['username'], 'password' => $params['password'] ) ); // Mask sensitive data $masked_data = $data; $masked_data['general']['password'] = "***"; $this->log($module_row->meta->ip_address . "|reseller:set", serialize($masked_data), "input", true); $response = $this->parseResponse($reseller->set($data), $module_row); } catch (Exception $e) { // API request failed $this->Input->setErrors(array('api' => array('internal' => Language::_("Plesk.!error.api.internal", true)))); } return (isset($response) ? $response : new stdClass()); } /** * Deletes a reseller account. Sets Input errors on failure * * @param stdClass $module_row A stdClass object representing a single server * @param stdClass $service_fields An stdClass object representing the service fields * @return stdClass An stdClass object representing the response */ private function deleteResellerAccount($module_row, $service_fields) { $api = $this->getApi($module_row->meta->ip_address, $module_row->meta->username, $module_row->meta->password, $module_row->meta->port); // Delete the reseller account try { $reseller = $api->loadCommand("plesk_reseller_accounts", array($this->getApiVersion($module_row->meta->panel_version))); // Delete the account $data = array('filter' => array('login' => $service_fields->plesk_username)); // Some filter options must be set to avoid Plesk deleting everything if (empty($data['filter']['login'])) { $this->Input->setErrors(array('api' => array('filter-missing' => Language::_("Plesk.!error.api.reseller_delete_filter_missing", true)))); return; } $this->log($module_row->meta->ip_address . "|reseller:del", serialize($data), "input", true); $response = $this->parseResponse($reseller->delete($data), $module_row); } catch (Exception $e) { // API request failed $this->Input->setErrors(array('api' => array('internal' => Language::_("Plesk.!error.api.internal", true)))); } return (isset($response) ? $response : new stdClass()); } /** * Creates a customer account. Sets Input errors on failure * * @param stdClass $module_row A stdClass object representing a single server * @param stdClass $package A stdClass object representing the selected package * @param int $client_id The ID of the client this customer account is being created on behalf of * @param array $params A list of data to pass into the customer account * - username The account username * - password The account password * @return stdClass An stdClass object representing the response */ private function createCustomerAccount($module_row, $package, $client_id, $params) { // Fetch the client fields $client_params = $this->getClientAccountFields($client_id); $api = $this->getApi($module_row->meta->ip_address, $module_row->meta->username, $module_row->meta->password, $module_row->meta->port); try { $customer_accounts = $api->loadCommand("plesk_customer_accounts", array($this->getApiVersion($module_row->meta->panel_version))); // Create the customer account $data = array_merge($client_params, array('login' => $params['username'], 'password' => $params['password'])); $masked_data = $data; $masked_data['password'] = "***"; $this->log($module_row->meta->ip_address . "|customer:add", serialize($masked_data), "input", true); $response = $this->parseResponse($customer_accounts->add($data), $module_row); } catch (Exception $e) { // API request failed $this->Input->setErrors(array('api' => array('internal' => Language::_("Plesk.!error.api.internal", true)))); } return (isset($response) ? $response : new stdClass()); } /** * Updates a customer account. Sets Input errors on failure * * @param stdClass $module_row A stdClass object representing a single server * @param stdClass $service_fields An stdClass object representing the service fields * @param array $params A list of data to pass into the customer account * - username The account username * - password The account password * @return stdClass An stdClass object representing the response */ private function updateCustomerAccount($module_row, $service_fields, $params) { $api = $this->getApi($module_row->meta->ip_address, $module_row->meta->username, $module_row->meta->password, $module_row->meta->port); // Update the customer try { $customer = $api->loadCommand("plesk_customer_accounts", array($this->getApiVersion($module_row->meta->panel_version))); // Set the information to update $data = array( // Update this user 'filter' => array('login' => $service_fields->plesk_username), // with this information 'general' => array( 'login' => $params['username'], 'password' => $params['password'] ) ); // Mask sensitive data $masked_data = $data; $masked_data['general']['password'] = "***"; $this->log($module_row->meta->ip_address . "|customer:set", serialize($masked_data), "input", true); $response = $this->parseResponse($customer->set($data), $module_row); } catch (Exception $e) { // API request failed $this->Input->setErrors(array('api' => array('internal' => Language::_("Plesk.!error.api.internal", true)))); } return (isset($response) ? $response : new stdClass()); } /** * Deletes a customer account. Sets Input errors on failure * * @param stdClass $module_row A stdClass object representing a single server * @param stdClass $service_fields An stdClass object representing the service fields * @return stdClass An stdClass object representing the response */ private function deleteCustomerAccount($module_row, $service_fields) { $api = $this->getApi($module_row->meta->ip_address, $module_row->meta->username, $module_row->meta->password, $module_row->meta->port); // Delete the customer account try { $customer_accounts = $api->loadCommand("plesk_customer_accounts", array($this->getApiVersion($module_row->meta->panel_version))); // Delete the account $data = array('filter' => array('login' => $service_fields->plesk_username)); // Some filter options must be set to avoid Plesk deleting everything if (empty($data['filter']['login'])) { $this->Input->setErrors(array('api' => array('filter-missing' => Language::_("Plesk.!error.api.reseller_delete_filter_missing", true)))); return; } $this->log($module_row->meta->ip_address . "|customer:del", serialize($data), "input", true); $response = $this->parseResponse($customer_accounts->delete($data), $module_row); } catch (Exception $e) { // API request failed $this->Input->setErrors(array('api' => array('internal' => Language::_("Plesk.!error.api.internal", true)))); } return (isset($response) ? $response : new stdClass()); } /** * Retrieves a list of fields for creating a customer/reseller account * * @param int $client_id The ID of the client whose fields to fetch * @return array An array of client fields * @see Plesk::createCustomerAccount(), Plesk::createResellerAccount() */ private function getClientAccountFields($client_id) { // Fetch the client to set additional client fields Loader::loadModels($this, array("Clients")); $client_params = array(); if (($client = $this->Clients->get($client_id, false))) { $country = (!empty($client->country) ? $client->country : null); $client_params = array( 'name' => $client->first_name . " " . $client->last_name, 'email' => $client->email, 'company' => (!empty($client->company) ? $client->company : null), 'status' => "0", 'address' => (empty($client->address1) ? null : ($client->address1 . (!empty($client->address2) ? " " . $client->address2 : ""))), 'city' => (!empty($client->city) ? $client->city : null), 'state' => (!empty($client->state) && $country == "US" ? $client->state : null), 'country' => $country, 'zipcode' => (!empty($client->zip) && $country == "US" ? $client->zip : null) ); } return $client_params; } /** * Parses the response from SolusVM into an stdClass object * * @param SolusvmResponse $response The response from the API * @param string $xml_container_path The path to the XML container where the results reside * @param stdClass $module_row A stdClass object representing a single server (optional, required when Module::getModuleRow() is unavailable) * @param boolean $ignore_error Ignores any response error and returns the response anyway; useful when a response is expected to fail (e.g. check client exists) (optional, default false) * @return stdClass A stdClass object representing the response, void if the response was an error */ private function parseResponse(PleskResponse $response, $module_row = null, $ignore_error = false) { Loader::loadHelpers($this, array("Html")); // Set the module row if (!$module_row) $module_row = $this->getModuleRow(); $success = false; switch ($response->status()) { case "ok": $success = true; break; case "error": $success = false; // Ignore generating the error if ($ignore_error) break; // Set errors $errors = $response->errors(); $error = ""; if (isset($errors->errcode) && isset($errors->errtext)) $error = $errors->errcode . " " . $errors->errtext; $this->Input->setErrors(array('api' => array('response' => $this->Html->safe($error)))); break; default: // Invalid response $success = false; // Ignore generating the error if ($ignore_error) break; $this->Input->setErrors(array('api' => array('internal' => Language::_("Plesk.!error.api.internal", true)))); break; } // Replace sensitive fields $masked_params = array(); $output = $response->response(); $raw_output = $response->raw(); foreach ($masked_params as $masked_param) { if (property_exists($output, $masked_param)) $raw_output = preg_replace("/<" . $masked_param . ">(.*)<\/" . $masked_param . ">/", "<" . $masked_param . ">***</" . $masked_param . ">", $raw_output); } // Log the response $this->log($module_row->meta->ip_address, $raw_output, "output", $success); if (!$success && !$ignore_error) return; return $output; } /** * Initializes the CpanelApi and returns an instance of that object with the given $host, $user, and $pass set * * @param string $host The host to the Plesk server * @param string $user The user to connect as * @param string $pass The password to authenticate with * @param string $port The port on the host to connect on * @return PleskApi The PleskApi instance */ private function getApi($host, $user, $pass, $port) { Loader::load(dirname(__FILE__) . DS . "apis" . DS . "plesk_api.php"); return new PleskApi($user, $pass, $host, $port); } /** * Generates a username based on the given domain * * @param string $domain The domain name * @param int $client_id The ID of the client * @return string The FTP login username */ private function generateUsername($domain, $client_id) { // Remove everything except letters and numbers from the domain // ensure no number appears in the beginning $username = ltrim(preg_replace('/[^a-z0-9]/i', '', $domain), '0123456789'); $length = strlen($username); $pool = "abcdefghijklmnopqrstuvwxyz0123456789"; $pool_size = strlen($pool); if ($length < 5) { for ($i=$length; $i<8; $i++) { $username .= substr($pool, mt_rand(0, $pool_size-1), 1); } $length = strlen($username); } return (substr($username, 0, min($length, 8)) . $client_id); } /** * Generates a password * * @param int $min_length The minimum character length for the password (5 or larger) * @param int $max_length The maximum character length for the password (14 or fewer) * @return string The generated password */ private function generatePassword($min_length=10, $max_length=14) { $pool = "abcdefghijklmnopqrstuvwxyz0123456789!@#$%^&*()"; $pool_size = strlen($pool); $length = mt_rand(max($min_length, 5), min($max_length, 14)); $password = ""; for ($i=0; $i<$length; $i++) { $password .= substr($pool, mt_rand(0, $pool_size-1), 1); } return $password; } /** * Builds and returns the rules required to add/edit a module row (e.g. server) * * @param array $vars An array of key/value data pairs * @return array An array of Input rules suitable for Input::setRules() */ private function getRowRules(&$vars) { return array( 'server_name' => array( 'empty' => array( 'rule' => "isEmpty", 'negate' => true, 'message' => Language::_("Plesk.!error.server_name.empty", true) ) ), 'host_name' => array( 'valid' => array( 'rule' => array(array($this, "validateHostName")), 'message' => Language::_("Plesk.!error.host_name.valid", true) ) ), 'ip_address' => array( 'valid' => array( 'rule' => array(array($this, "validateIpAddress")), 'message' => Language::_("Plesk.!error.ip_address.valid", true) ) ), 'port' => array( 'format' => array( 'rule' => array("matches", "/^[0-9]+$/"), 'message' => Language::_("Plesk.!error.port.format", true) ) ), 'username' => array( 'empty' => array( 'rule' => "isEmpty", 'negate' => true, 'message' => Language::_("Plesk.!error.username.empty", true) ) ), 'password' => array( 'empty' => array( 'rule' => "isEmpty", 'negate' => true, 'message' => Language::_("Plesk.!error.password.empty", true) ) ), 'panel_version' => array( 'valid' => array( 'rule' => array(array($this, "validatePanelVersions")), 'message' => Language::_("Plesk.!error.panel_version.valid", true) ) ), 'reseller' => array( 'valid' => array( 'rule' => array("in_array", array("true", "false")), 'message' => Language::_("Plesk.!error.reseller.valid", true) ) ) ); } /** * Builds and returns rules required to be validated when adding/editing a package * * @param array $vars An array of key/value data pairs * @return array An array of Input rules suitable for Input::setRules() */ private function getPackageRules($vars) { $rules = array( 'meta[type]' => array( 'valid' => array( 'rule' => array("matches", "/^(standard|reseller)$/"), 'message' => Language::_("Plesk.!error.meta[type].valid", true), // type must be standard or reseller ) ), 'meta[plan]' => array( 'empty' => array( 'rule' => "isEmpty", 'negate' => true, 'message' => Language::_("Plesk.!error.meta[plan].empty", true) ) ), 'meta[reseller_plan]' => array( 'empty' => array( 'if_set' => true, 'rule' => "isEmpty", 'negate' => true, 'message' => Language::_("Plesk.!error.meta[reseller_plan].empty", true) ) ) ); return $rules; } /** * Validates that the given hostname is valid * * @param string $host_name The host name to validate * @return boolean True if the hostname is valid, false otherwise */ public function validateHostName($host_name) { if (strlen($host_name) > 255) return false; return $this->Input->matches($host_name, "/^([a-z0-9]|[a-z0-9][a-z0-9\-]{0,61}[a-z0-9])(\.([a-z0-9]|[a-z0-9][a-z0-9\-]{0,61}[a-z0-9]))+$/"); } /** * Validates that the given ip address is valid * * @param string $ip_address The ip address to validate * @return boolean True if the ip address is valid, false otherwise */ public function validateIpAddress($ip_address) { $range = "(?:25[0-5]|2[0-4][0-9]|1[0-9]{2}|[1-9][0-9]|[0-9])"; return $this->Input->matches($ip_address, "/^(?:" . $range . "\." . $range . "\." . $range . "\." . $range . ")$/"); } /** * Validates that the given panel version is valid * * @param string $version The version to validate * @return boolean True if the version validates, false otherwise */ public function validatePanelVersions($version) { return array_key_exists($version, $this->panel_versions); } } ?>