balmet.com

Unnamed repository; edit this file 'description' to name the repository.
Log | Files | Refs

License.php (18151B)


      1 <?php
      2 namespace ReduxAppsero;
      3 
      4 /**
      5  * Appsero License Checker
      6  *
      7  * This class will check, active and deactive license
      8  */
      9 class License {
     10 
     11 	/**
     12 	 * AppSero\Client
     13 	 *
     14 	 * @var object
     15 	 */
     16 	protected $client;
     17 
     18 	/**
     19 	 * Arguments of create menu
     20 	 *
     21 	 * @var array
     22 	 */
     23 	protected $menu_args;
     24 
     25 	/**
     26 	 * `option_name` of `wp_options` table
     27 	 *
     28 	 * @var string
     29 	 */
     30 	protected $option_key;
     31 
     32 	/**
     33 	 * Error message of HTTP request
     34 	 *
     35 	 * @var string
     36 	 */
     37 	public $error;
     38 
     39 	/**
     40 	 * Success message on form submit
     41 	 *
     42 	 * @var string
     43 	 */
     44 	public $success;
     45 
     46 	/**
     47 	 * Corn schedule hook name
     48 	 *
     49 	 * @var string
     50 	 */
     51 	protected $schedule_hook;
     52 
     53 	/**
     54 	 * Set value for valid licnese
     55 	 *
     56 	 * @var boolean
     57 	 */
     58 	private $is_valid_licnese = null;
     59 
     60 	/**
     61 	 * Initialize the class
     62 	 *
     63 	 * @param Appsero\Client
     64 	 */
     65 	public function __construct( Client $client ) {
     66 		$this->client = $client;
     67 
     68 		$this->option_key = 'appsero_' . md5( $this->client->slug ) . '_manage_license';
     69 
     70 		$this->schedule_hook = $this->client->slug . '_license_check_event';
     71 
     72 		// Run hook to check license status daily
     73 		add_action( $this->schedule_hook, array( $this, 'check_license_status' ) );
     74 
     75 		// Active/Deactive corn schedule
     76 		$this->run_schedule();
     77 	}
     78 
     79 	/**
     80 	 * Check license
     81 	 *
     82 	 * @return boolean
     83 	 */
     84 	public function check( $license_key ) {
     85 		$route = 'public/license/' . $this->client->hash . '/check';
     86 
     87 		return $this->send_request( $license_key, $route );
     88 	}
     89 
     90 	/**
     91 	 * Active a license
     92 	 *
     93 	 * @return boolean
     94 	 */
     95 	public function activate( $license_key ) {
     96 		$route = 'public/license/' . $this->client->hash . '/activate';
     97 
     98 		return $this->send_request( $license_key, $route );
     99 	}
    100 
    101 	/**
    102 	 * Deactivate a license
    103 	 *
    104 	 * @return boolean
    105 	 */
    106 	public function deactivate( $license_key ) {
    107 		$route = 'public/license/' . $this->client->hash . '/deactivate';
    108 
    109 		return $this->send_request( $license_key, $route );
    110 	}
    111 
    112 	/**
    113 	 * Send common request
    114 	 *
    115 	 * @param $license_key
    116 	 * @param $route
    117 	 *
    118 	 * @return array
    119 	 */
    120 	protected function send_request( $license_key, $route ) {
    121 		$params = array(
    122 			'license_key' => $license_key,
    123 			'url'         => esc_url( home_url() ),
    124 			'is_local'    => $this->client->is_local_server(),
    125 		);
    126 
    127 		$response = $this->client->send_request( $params, $route, true );
    128 
    129 		if ( is_wp_error( $response ) ) {
    130 			return array(
    131 				'success' => false,
    132 				'error'   => $response->get_error_message(),
    133 			);
    134 		}
    135 
    136 		$response = json_decode( wp_remote_retrieve_body( $response ), true );
    137 
    138 		if ( empty( $response ) || isset( $response['exception'] ) ) {
    139 			return array(
    140 				'success' => false,
    141 				'error'   => 'Unknown error occurred, Please try again.',
    142 			);
    143 		}
    144 
    145 		if ( isset( $response['errors'] ) && isset( $response['errors']['license_key'] ) ) {
    146 			$response = array(
    147 				'success' => false,
    148 				'error'   => $response['errors']['license_key'][0],
    149 			);
    150 		}
    151 
    152 		return $response;
    153 	}
    154 
    155 	/**
    156 	 * Add settings page for license
    157 	 *
    158 	 * @param array $args
    159 	 *
    160 	 * @return void
    161 	 */
    162 	public function add_settings_page( $args = array() ) {
    163 		$defaults = array(
    164 			'type'        => 'menu', // Can be: menu, options, submenu
    165 			'page_title'  => 'Manage License',
    166 			'menu_title'  => 'Manage License',
    167 			'capability'  => 'manage_options',
    168 			'menu_slug'   => $this->client->slug . '-manage-license',
    169 			'icon_url'    => '',
    170 			'position'    => null,
    171 			'parent_slug' => '',
    172 		);
    173 
    174 		$this->menu_args = wp_parse_args( $args, $defaults );
    175 
    176 		add_action( 'admin_menu', array( $this, 'admin_menu' ), 99 );
    177 	}
    178 
    179 	/**
    180 	 * Admin Menu hook
    181 	 *
    182 	 * @return void
    183 	 */
    184 	public function admin_menu() {
    185 		switch ( $this->menu_args['type'] ) {
    186 			case 'menu':
    187 				$this->create_menu_page();
    188 				break;
    189 
    190 			case 'submenu':
    191 				$this->create_submenu_page();
    192 				break;
    193 
    194 			case 'options':
    195 				$this->create_options_page();
    196 				break;
    197 		}
    198 	}
    199 
    200 	/**
    201 	 * License menu output
    202 	 */
    203 	public function menu_output() {
    204 
    205 		if ( isset( $_POST['submit'] ) ) {
    206 			$this->license_form_submit( $_POST );
    207 		}
    208 
    209 		$license = get_option( $this->option_key, null );
    210 		$action  = ( $license && isset( $license['status'] ) && 'activate' == $license['status'] ) ? 'deactive' : 'active';
    211 		$this->licenses_style();
    212 		?>
    213 
    214 		<div class="wrap appsero-license-settings-wrapper">
    215 			<h1>License Settings</h1>
    216 
    217 			<?php
    218 				$this->show_license_page_notices();
    219 				do_action( 'before_appsero_license_section' );
    220 			?>
    221 
    222 			<div class="appsero-license-settings appsero-license-section">
    223 				<?php $this->show_license_page_card_header(); ?>
    224 
    225 				<div class="appsero-license-details">
    226 					<p>Activate <strong><?php echo $this->client->name; ?></strong> by your license key to get professional support and automatic update from your WordPress dashboard.</p>
    227 					<form method="post" action="<?php $this->formActionUrl(); ?>" novalidate="novalidate" spellcheck="false">
    228 						<input type="hidden" name="_action" value="<?php echo $action; ?>">
    229 						<input type="hidden" name="_nonce" value="<?php echo wp_create_nonce( $this->client->name ); ?>">
    230 						<div class="license-input-fields">
    231 							<div class="license-input-key">
    232 								<svg enable-background="new 0 0 512 512" version="1.1" viewBox="0 0 512 512" xml:space="preserve" xmlns="http://www.w3.org/2000/svg">
    233 									<path d="m463.75 48.251c-64.336-64.336-169.01-64.335-233.35 1e-3 -43.945 43.945-59.209 108.71-40.181 167.46l-185.82 185.82c-2.813 2.813-4.395 6.621-4.395 10.606v84.858c0 8.291 6.709 15 15 15h84.858c3.984 0 7.793-1.582 10.605-4.395l21.211-21.226c3.237-3.237 4.819-7.778 4.292-12.334l-2.637-22.793 31.582-2.974c7.178-0.674 12.847-6.343 13.521-13.521l2.974-31.582 22.793 2.651c4.233 0.571 8.496-0.85 11.704-3.691 3.193-2.856 5.024-6.929 5.024-11.206v-27.929h27.422c3.984 0 7.793-1.582 10.605-4.395l38.467-37.958c58.74 19.043 122.38 4.929 166.33-39.046 64.336-64.335 64.336-169.01 0-233.35zm-42.435 106.07c-17.549 17.549-46.084 17.549-63.633 0s-17.549-46.084 0-63.633 46.084-17.549 63.633 0 17.548 46.084 0 63.633z"/>
    234 								</svg>
    235 								<input type="text" value="<?php echo $this->get_input_license_value( $action, $license ); ?>"
    236 									placeholder="Enter your license key to activate" name="license_key"
    237 									<?php echo ( 'deactive' == $action ) ? 'readonly="readonly"' : ''; ?>
    238 								/>
    239 							</div>
    240 							<button type="submit" name="submit" class="<?php echo 'deactive' == $action ? 'deactive-button' : ''; ?>">
    241 								<?php echo $action == 'active' ? 'Activate License' : 'Deactivate License'; ?>
    242 							</button>
    243 						</div>
    244 					</form>
    245 
    246 					<?php
    247 					if ( 'deactive' == $action && isset( $license['remaining'] ) ) {
    248 						$this->show_active_license_info( $license );
    249 					}
    250 					?>
    251 				</div>
    252 			</div> <!-- /.appsero-license-settings -->
    253 
    254 			<?php do_action( 'after_appsero_license_section' ); ?>
    255 		</div>
    256 		<?php
    257 	}
    258 
    259 	/**
    260 	 * License form submit
    261 	 */
    262 	public function license_form_submit( $form ) {
    263 		if ( ! isset( $form['_nonce'], $form['_action'] ) ) {
    264 			$this->error = 'Please add all information';
    265 			return;
    266 		}
    267 
    268 		if ( ! wp_verify_nonce( $form['_nonce'], $this->client->name ) ) {
    269 			$this->error = "You don't have permission to manage license.";
    270 			return;
    271 		}
    272 
    273 		switch ( $form['_action'] ) {
    274 			case 'active':
    275 				$this->active_client_license( $form );
    276 				break;
    277 
    278 			case 'deactive':
    279 				$this->deactive_client_license( $form );
    280 				break;
    281 		}
    282 	}
    283 
    284 	/**
    285 	 * Check license status on schedule
    286 	 */
    287 	public function check_license_status() {
    288 		$license = get_option( $this->option_key, null );
    289 
    290 		if ( isset( $license['key'] ) && ! empty( $license['key'] ) ) {
    291 			$response = $this->check( $license['key'] );
    292 
    293 			if ( isset( $response['success'] ) && $response['success'] ) {
    294 				$license['status']           = 'activate';
    295 				$license['remaining']        = $response['remaining'];
    296 				$license['activation_limit'] = $response['activation_limit'];
    297 				$license['expiry_days']      = $response['expiry_days'];
    298 				$license['title']            = $response['title'];
    299 				$license['source_id']        = $response['source_identifier'];
    300 				$license['recurring']        = $response['recurring'];
    301 			} else {
    302 				$license['status']      = 'deactivate';
    303 				$license['expiry_days'] = 0;
    304 			}
    305 
    306 			update_option( $this->option_key, $license, false );
    307 		}
    308 	}
    309 
    310 	/**
    311 	 * Check this is a valid license
    312 	 */
    313 	public function is_valid() {
    314 		if ( null !== $this->is_valid_licnese ) {
    315 			return $this->is_valid_licnese;
    316 		}
    317 
    318 		$license = get_option( $this->option_key, null );
    319 		if ( ! empty( $license['key'] ) && isset( $license['status'] ) && $license['status'] == 'activate' ) {
    320 			$this->is_valid_licnese = true;
    321 		} else {
    322 			$this->is_valid_licnese = false;
    323 		}
    324 
    325 		return $this->is_valid_licnese;
    326 	}
    327 
    328 	/**
    329 	 * Check this is a valid license
    330 	 */
    331 	public function is_valid_by( $option, $value ) {
    332 		$license = get_option( $this->option_key, null );
    333 
    334 		if ( ! empty( $license['key'] ) && isset( $license['status'] ) && $license['status'] == 'activate' ) {
    335 			if ( isset( $license[ $option ] ) && $license[ $option ] == $value ) {
    336 				return true;
    337 			}
    338 		}
    339 
    340 		return false;
    341 	}
    342 
    343 	/**
    344 	 * Styles for licenses page
    345 	 */
    346 	private function licenses_style() {
    347 		?>
    348 		<style type="text/css">
    349 			.appsero-license-section {
    350 				width: 100%;
    351 				max-width: 1100px;
    352 				min-height: 1px;
    353 				box-sizing: border-box;
    354 			}
    355 			.appsero-license-settings {
    356 				background-color: #fff;
    357 				box-shadow: 0px 3px 10px rgba(16, 16, 16, 0.05);
    358 			}
    359 			.appsero-license-settings * {
    360 				box-sizing: border-box;
    361 			}
    362 			.appsero-license-title {
    363 				background-color: #F8FAFB;
    364 				border-bottom: 2px solid #EAEAEA;
    365 				display: flex;
    366 				align-items: center;
    367 				padding: 10px 20px;
    368 			}
    369 			.appsero-license-title svg {
    370 				width: 30px;
    371 				height: 30px;
    372 				fill: #0082BF;
    373 			}
    374 			.appsero-license-title span {
    375 				font-size: 17px;
    376 				color: #444444;
    377 				margin-left: 10px;
    378 			}
    379 			.appsero-license-details {
    380 				padding: 20px;
    381 			}
    382 			.appsero-license-details p {
    383 				font-size: 15px;
    384 				margin: 0 0 20px 0;
    385 			}
    386 			.license-input-key {
    387 				position: relative;
    388 				flex: 0 0 72%;
    389 				max-width: 72%;
    390 			}
    391 			.license-input-key input {
    392 				background-color: #F9F9F9;
    393 				padding: 10px 15px 10px 48px;
    394 				border: 1px solid #E8E5E5;
    395 				border-radius: 3px;
    396 				height: 45px;
    397 				font-size: 16px;
    398 				color: #71777D;
    399 				width: 100%;
    400 				box-shadow: 0 0 0 transparent;
    401 			}
    402 			.license-input-key input:focus {
    403 				outline: 0 none;
    404 				border: 1px solid #E8E5E5;
    405 				box-shadow: 0 0 0 transparent;
    406 			}
    407 			.license-input-key svg {
    408 				width: 22px;
    409 				height: 22px;
    410 				fill: #0082BF;
    411 				position: absolute;
    412 				left: 14px;
    413 				top: 13px;
    414 			}
    415 			.license-input-fields {
    416 				display: flex;
    417 				justify-content: space-between;
    418 				margin-bottom: 30px;
    419 				max-width: 850px;
    420 				width: 100%;
    421 			}
    422 			.license-input-fields button {
    423 				color: #fff;
    424 				font-size: 17px;
    425 				padding: 8px;
    426 				height: 46px;
    427 				background-color: #0082BF;
    428 				border-radius: 3px;
    429 				cursor: pointer;
    430 				flex: 0 0 25%;
    431 				max-width: 25%;
    432 				border: 1px solid #0082BF;
    433 			}
    434 			.license-input-fields button.deactive-button {
    435 				background-color: #E40055;
    436 				border-color: #E40055;
    437 			}
    438 			.license-input-fields button:focus {
    439 				outline: 0 none;
    440 			}
    441 			.active-license-info {
    442 				display: flex;
    443 			}
    444 			.single-license-info {
    445 				min-width: 220px;
    446 				flex: 0 0 30%;
    447 			}
    448 			.single-license-info h3 {
    449 				font-size: 18px;
    450 				margin: 0 0 12px 0;
    451 			}
    452 			.single-license-info p {
    453 				margin: 0;
    454 				color: #00C000;
    455 			}
    456 			.single-license-info p.occupied {
    457 				color: #E40055;
    458 			}
    459 		</style>
    460 		<?php
    461 	}
    462 
    463 	/**
    464 	 * Show active license information
    465 	 */
    466 	private function show_active_license_info( $license ) {
    467 		?>
    468 		<div class="active-license-info">
    469 			<div class="single-license-info">
    470 				<h3>Activation Remaining</h3>
    471 				<?php if ( empty( $license['activation_limit'] ) ) : ?>
    472 					<p>Unlimited</p>
    473 				<?php else : ?>
    474 					<p class="<?php echo $license['remaining'] ? '' : 'occupied'; ?>">
    475 						<?php echo $license['remaining']; ?> out of <?php echo $license['activation_limit']; ?>
    476 					</p>
    477 				<?php endif; ?>
    478 			</div>
    479 			<div class="single-license-info">
    480 				<h3>Expires in</h3>
    481 				<?php
    482 				if ( $license['recurring'] && false !== $license['expiry_days'] ) {
    483 					$occupied = $license['expiry_days'] > 10 ? '' : 'occupied';
    484 					echo '<p class="' . $occupied . '">' . $license['expiry_days'] . ' days</p>';
    485 				} else {
    486 					echo '<p>Never</p>';
    487 				}
    488 				?>
    489 			</div>
    490 		</div>
    491 		<?php
    492 	}
    493 
    494 	/**
    495 	 * Show license settings page notices
    496 	 */
    497 	private function show_license_page_notices() {
    498 		if ( ! empty( $this->error ) ) :
    499 			?>
    500 			<div class="notice notice-error is-dismissible appsero-license-section">
    501 				<p><?php echo $this->error; ?></p>
    502 			</div>
    503 			<?php
    504 			endif;
    505 		if ( ! empty( $this->success ) ) :
    506 			?>
    507 			<div class="notice notice-success is-dismissible appsero-license-section">
    508 				<p><?php echo $this->success; ?></p>
    509 			</div>
    510 			<?php
    511 			endif;
    512 			echo '<br />';
    513 	}
    514 
    515 	/**
    516 	 * Card header
    517 	 */
    518 	private function show_license_page_card_header() {
    519 		?>
    520 		<div class="appsero-license-title">
    521 			<svg enable-background="new 0 0 299.995 299.995" version="1.1" viewBox="0 0 300 300" xml:space="preserve" xmlns="http://www.w3.org/2000/svg">
    522 				<path d="m150 161.48c-8.613 0-15.598 6.982-15.598 15.598 0 5.776 3.149 10.807 7.817 13.505v17.341h15.562v-17.341c4.668-2.697 7.817-7.729 7.817-13.505 0-8.616-6.984-15.598-15.598-15.598z"/>
    523 				<path d="m150 85.849c-13.111 0-23.775 10.665-23.775 23.775v25.319h47.548v-25.319c-1e-3 -13.108-10.665-23.775-23.773-23.775z"/>
    524 				<path d="m150 1e-3c-82.839 0-150 67.158-150 150 0 82.837 67.156 150 150 150s150-67.161 150-150c0-82.839-67.161-150-150-150zm46.09 227.12h-92.173c-9.734 0-17.626-7.892-17.626-17.629v-56.919c0-8.491 6.007-15.582 14.003-17.25v-25.697c0-27.409 22.3-49.711 49.711-49.711 27.409 0 49.709 22.3 49.709 49.711v25.697c7.993 1.673 14 8.759 14 17.25v56.919h2e-3c0 9.736-7.892 17.629-17.626 17.629z"/>
    525 			</svg>
    526 			<span>Activate License</span>
    527 		</div>
    528 		<?php
    529 	}
    530 
    531 	/**
    532 	 * Active client license
    533 	 */
    534 	private function active_client_license( $form ) {
    535 		if ( empty( $form['license_key'] ) ) {
    536 			$this->error = 'The license key field is required.';
    537 			return;
    538 		}
    539 
    540 		$license_key = sanitize_text_field( $form['license_key'] );
    541 		$response    = $this->activate( $license_key );
    542 
    543 		if ( ! $response['success'] ) {
    544 			$this->error = $response['error'] ? $response['error'] : 'Unknown error occurred.';
    545 			return;
    546 		}
    547 
    548 		$data = array(
    549 			'key'              => $license_key,
    550 			'status'           => 'activate',
    551 			'remaining'        => $response['remaining'],
    552 			'activation_limit' => $response['activation_limit'],
    553 			'expiry_days'      => $response['expiry_days'],
    554 			'title'            => $response['title'],
    555 			'source_id'        => $response['source_identifier'],
    556 			'recurring'        => $response['recurring'],
    557 		);
    558 
    559 		update_option( $this->option_key, $data, false );
    560 
    561 		$this->success = 'License activated successfully.';
    562 	}
    563 
    564 	/**
    565 	 * Deactive client license
    566 	 */
    567 	private function deactive_client_license( $form ) {
    568 		$license = get_option( $this->option_key, null );
    569 
    570 		if ( empty( $license['key'] ) ) {
    571 			$this->error = 'License key not found.';
    572 			return;
    573 		}
    574 
    575 		$response = $this->deactivate( $license['key'] );
    576 
    577 		$data = array(
    578 			'key'    => '',
    579 			'status' => 'deactivate',
    580 		);
    581 
    582 		update_option( $this->option_key, $data, false );
    583 
    584 		if ( ! $response['success'] ) {
    585 			$this->error = $response['error'] ? $response['error'] : 'Unknown error occurred.';
    586 			return;
    587 		}
    588 
    589 		$this->success = 'License deactivated successfully.';
    590 	}
    591 
    592 	/**
    593 	 * Add license menu page
    594 	 */
    595 	private function create_menu_page() {
    596 		call_user_func(
    597 			'add_' . 'menu' . '_page',
    598 			$this->menu_args['page_title'],
    599 			$this->menu_args['menu_title'],
    600 			$this->menu_args['capability'],
    601 			$this->menu_args['menu_slug'],
    602 			array( $this, 'menu_output' ),
    603 			$this->menu_args['icon_url'],
    604 			$this->menu_args['position']
    605 		);
    606 	}
    607 
    608 	/**
    609 	 * Add submenu page
    610 	 */
    611 	private function create_submenu_page() {
    612 		call_user_func(
    613 			'add_' . 'submenu' . '_page',
    614 			$this->menu_args['parent_slug'],
    615 			$this->menu_args['page_title'],
    616 			$this->menu_args['menu_title'],
    617 			$this->menu_args['capability'],
    618 			$this->menu_args['menu_slug'],
    619 			array( $this, 'menu_output' ),
    620 			$this->menu_args['position']
    621 		);
    622 	}
    623 
    624 	/**
    625 	 * Add submenu page
    626 	 */
    627 	private function create_options_page() {
    628 		call_user_func(
    629 			'add_' . 'options' . '_page',
    630 			$this->menu_args['page_title'],
    631 			$this->menu_args['menu_title'],
    632 			$this->menu_args['capability'],
    633 			$this->menu_args['menu_slug'],
    634 			array( $this, 'menu_output' ),
    635 			$this->menu_args['position']
    636 		);
    637 	}
    638 
    639 	/**
    640 	 * Schedule daily sicense checker event
    641 	 */
    642 	public function schedule_cron_event() {
    643 		if ( ! wp_next_scheduled( $this->schedule_hook ) ) {
    644 			wp_schedule_event( time(), 'daily', $this->schedule_hook );
    645 
    646 			wp_schedule_single_event( time() + 20, $this->schedule_hook );
    647 		}
    648 	}
    649 
    650 	/**
    651 	 * Clear any scheduled hook
    652 	 */
    653 	public function clear_scheduler() {
    654 		wp_clear_scheduled_hook( $this->schedule_hook );
    655 	}
    656 
    657 	/**
    658 	 * Enable/Disable schedule
    659 	 */
    660 	private function run_schedule() {
    661 		switch ( $this->client->type ) {
    662 			case 'plugin':
    663 				register_activation_hook( $this->client->file, array( $this, 'schedule_cron_event' ) );
    664 				register_deactivation_hook( $this->client->file, array( $this, 'clear_scheduler' ) );
    665 				break;
    666 
    667 			case 'theme':
    668 				add_action( 'after_switch_theme', array( $this, 'schedule_cron_event' ) );
    669 				add_action( 'switch_theme', array( $this, 'clear_scheduler' ) );
    670 				break;
    671 		}
    672 	}
    673 
    674 	/**
    675 	 * Form action URL
    676 	 */
    677 	private function formActionUrl() {
    678 		echo add_query_arg(
    679 			array( 'page' => $_GET['page'] ),
    680 			admin_url( basename( $_SERVER['SCRIPT_NAME'] ) )
    681 		);
    682 	}
    683 
    684 	/**
    685 	 * Get input license key
    686 	 *
    687 	 * @param  $action
    688 	 * @return $license
    689 	 */
    690 	private function get_input_license_value( $action, $license ) {
    691 		if ( 'active' == $action ) {
    692 			return isset( $license['key'] ) ? $license['key'] : '';
    693 		}
    694 
    695 		if ( 'deactive' == $action ) {
    696 			$key_length = strlen( $license['key'] );
    697 
    698 			return str_pad(
    699 				substr( $license['key'], 0, $key_length / 2 ),
    700 				$key_length,
    701 				'*'
    702 			);
    703 		}
    704 
    705 		return '';
    706 	}
    707 
    708 }