Commit 30219bf9 by lmf

增加信用卡支付插件

parent 2e6888fd
......@@ -33,6 +33,7 @@
"ext-xsl": "*",
"ext-zip": "*",
"lib-libxml": "*",
"airwallex/payments-plugin-magento": "^1.2",
"colinmollenhour/cache-backend-file": "~1.4.1",
"colinmollenhour/cache-backend-redis": "1.11.0",
"colinmollenhour/credis": "1.11.1",
......
......@@ -4,9 +4,49 @@
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
"This file is @generated automatically"
],
"content-hash": "c6e9f5bf77fc89c8660b540862019810",
"content-hash": "96d54abdc29e1aeacfdc595d5d248fb3",
"packages": [
{
"name": "airwallex/payments-plugin-magento",
"version": "1.2.2",
"source": {
"type": "git",
"url": "https://github.com/airwallex/paymentacceptance-plugin-magento.git",
"reference": "38119a84cc0f9998d8c0d3b9b3e2f87a31dea8c7"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/airwallex/paymentacceptance-plugin-magento/zipball/38119a84cc0f9998d8c0d3b9b3e2f87a31dea8c7",
"reference": "38119a84cc0f9998d8c0d3b9b3e2f87a31dea8c7",
"shasum": "",
"mirrors": [
{
"url": "https://mirrors.aliyun.com/composer/dists/%package%/%reference%.%type%",
"preferred": true
}
]
},
"require": {
"ext-json": "*",
"mobiledetect/mobiledetectlib": "^2.8"
},
"type": "magento2-module",
"autoload": {
"files": [
"registration.php"
],
"psr-4": {
"Airwallex\\Payments\\": ""
}
},
"notification-url": "https://packagist.org/downloads/",
"support": {
"issues": "https://github.com/airwallex/paymentacceptance-plugin-magento/issues",
"source": "https://github.com/airwallex/paymentacceptance-plugin-magento/tree/1.2.2"
},
"time": "2022-06-01T09:48:45+00:00"
},
{
"name": "aws/aws-crt-php",
"version": "v1.0.2",
"source": {
......@@ -4469,6 +4509,68 @@
]
},
{
"name": "mobiledetect/mobiledetectlib",
"version": "2.8.39",
"source": {
"type": "git",
"url": "https://github.com/serbanghita/Mobile-Detect.git",
"reference": "0fd6753003fc870f6e229bae869cc1337c99bc45"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/serbanghita/Mobile-Detect/zipball/0fd6753003fc870f6e229bae869cc1337c99bc45",
"reference": "0fd6753003fc870f6e229bae869cc1337c99bc45",
"shasum": "",
"mirrors": [
{
"url": "https://mirrors.aliyun.com/composer/dists/%package%/%reference%.%type%",
"preferred": true
}
]
},
"require": {
"php": ">=5.0.0"
},
"require-dev": {
"phpunit/phpunit": "~4.8.35||~5.7"
},
"type": "library",
"autoload": {
"psr-0": {
"Detection": "namespaced/"
},
"classmap": [
"Mobile_Detect.php"
]
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Serban Ghita",
"email": "serbanghita@gmail.com",
"homepage": "http://mobiledetect.net",
"role": "Developer"
}
],
"description": "Mobile_Detect is a lightweight PHP class for detecting mobile devices. It uses the User-Agent string combined with specific HTTP headers to detect the mobile environment.",
"homepage": "https://github.com/serbanghita/Mobile-Detect",
"keywords": [
"detect mobile devices",
"mobile",
"mobile detect",
"mobile detector",
"php mobile detect"
],
"support": {
"issues": "https://github.com/serbanghita/Mobile-Detect/issues",
"source": "https://github.com/serbanghita/Mobile-Detect/tree/2.8.39"
},
"time": "2022-02-17T19:24:25+00:00"
},
{
"name": "monolog/monolog",
"version": "1.27.1",
"source": {
......
name: CI
on: [push]
jobs:
build:
runs-on: [ubuntu-latest]
steps:
- uses: actions/checkout@v2
- name: Cache Composer dependencies
uses: actions/cache@v2
with:
path: /tmp/composer-cache
key: ${{ runner.os }}-${{ hashFiles('**/composer.lock') }}
- uses: php-actions/composer@v5
\ No newline at end of file
<?php
/**
* This file is part of the Airwallex Payments module.
*
* DISCLAIMER
*
* Do not edit or add to this file if you wish to upgrade
* to newer versions in the future.
*
* @copyright Copyright (c) 2021 Magebit, Ltd. (https://magebit.com/)
* @license GNU General Public License ("GPL") v3.0
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Airwallex\Payments\Api\Data;
interface PaymentIntentInterface
{
public const TABLE = 'airwallex_payment_intents';
public const ID_COLUMN = 'id';
public const PAYMENT_INTENT_ID_COLUMN = 'payment_intent_id';
public const ORDER_INCREMENT_ID_COLUMN = 'order_increment_id';
/**
* @return mixed
*/
public function getId();
/**
* @return string
*/
public function getPaymentIntentId(): string;
/**
* @return string
*/
public function getOrderIncrementId(): string;
/**
* @param string $paymentIntentId
*
* @return $this
*/
public function setPaymentIntentId(string $paymentIntentId): self;
/**
* @param string $orderIncrementId
*
* @return $this
*/
public function setOrderIncrementId(string $orderIncrementId): self;
}
<?php
/**
* This file is part of the Airwallex Payments module.
*
* DISCLAIMER
*
* Do not edit or add to this file if you wish to upgrade
* to newer versions in the future.
*
* @copyright Copyright (c) 2021 Magebit, Ltd. (https://magebit.com/)
* @license GNU General Public License ("GPL") v3.0
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Airwallex\Payments\Api;
interface ServiceInterface
{
/**
* @param string $method
*
* @return string
*/
public function createIntent(string $method): string;
/**
* @return string
*/
public function redirectUrl(): string;
/**
* @param string $intentId
* @param string $method
*
* @return string
*/
public function refreshIntent(string $intentId, string $method): string;
}
<?php
/**
* This file is part of the Airwallex Payments module.
*
* DISCLAIMER
*
* Do not edit or add to this file if you wish to upgrade
* to newer versions in the future.
*
* @copyright Copyright (c) 2021 Magebit, Ltd. (https://magebit.com/)
* @license GNU General Public License ("GPL") v3.0
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Airwallex\Payments\Block\Adminhtml\Config;
use Magento\Config\Block\System\Config\Form\Fieldset as AdminhtmlFieldset;
use Magento\Framework\Data\Form\Element\AbstractElement;
class Fieldset extends AdminhtmlFieldset
{
/**
* Add custom css class
*
* @param AbstractElement $element
* @return string
*/
protected function _getFrontendClass($element): string
{
return parent::_getFrontendClass($element) . ' with-button enabled';
}
/**
* Return header title part of html for payment solution
*
* @param AbstractElement $element
* @return string
* @SuppressWarnings(PHPMD.NPathComplexity)
*/
protected function _getHeaderTitleHtml($element): string
{
$html = '<div class="config-heading" >';
$htmlId = $element->getHtmlId();
$html .= '<div class="button-container"><button type="button"' .
' class="button action-configure' .
'" id="' .
$htmlId .
'-head" onclick="toggleSolution.call(this, \'' .
$htmlId .
"', '" .
$this->getUrl(
'adminhtml/*/state'
) . '\'); return false;"><span class="state-closed">' . __(
'Configure'
) . '</span><span class="state-opened">' . __(
'Close'
) . '</span></button>';
$html .= '</div>';
$html .= '<div class="heading"><strong>' . $element->getLegend() . '</strong>';
if ($comment = $element->getComment()) {
$html .= '<span class="heading-intro">' . $comment . '</span>';
}
$html .= '<div class="config-alt"></div>';
$html .= '</div></div>';
return $html;
}
/**
* Return header comment part of html for payment solution
*
* @param AbstractElement $element
* @return string
* @SuppressWarnings(PHPMD.UnusedFormalParameter)
*/
protected function _getHeaderCommentHtml($element): string
{
return '';
}
/**
* Get collapsed state on-load
*
* @param AbstractElement $element
* @return false
* @SuppressWarnings(PHPMD.UnusedFormalParameter)
*/
protected function _isCollapseState($element): bool
{
return false;
}
/**
* @param AbstractElement $element
* @return string
* @SuppressWarnings(PHPMD.UnusedFormalParameter)
*/
protected function _getExtraJs($element): string
{
return '';
}
}
<?php
/**
* This file is part of the Airwallex Payments module.
*
* DISCLAIMER
*
* Do not edit or add to this file if you wish to upgrade
* to newer versions in the future.
*
* @copyright Copyright (c) 2021 Magebit, Ltd. (https://magebit.com/)
* @license GNU General Public License ("GPL") v3.0
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Airwallex\Payments\Controller\Webhooks;
use Airwallex\Payments\Logger\Logger;
use Airwallex\Payments\Model\Webhook\Webhook;
use Exception;
use Magento\Framework\App\Action\HttpPostActionInterface;
use Magento\Framework\App\CsrfAwareActionInterface;
use Magento\Framework\App\Request\Http as RequestHttp;
use Magento\Framework\App\Request\InvalidRequestException;
use Magento\Framework\App\RequestInterface;
use Magento\Framework\App\Response\Http as ResponseHttp;
class Index implements HttpPostActionInterface, CsrfAwareActionInterface
{
private const JSON_DECODE_DEPTH = 512;
private const HTTP_OK = 200;
/**
* @var Webhook
*/
private Webhook $webhook;
/**
* @var RequestHttp
*/
private RequestHttp $request;
/**
* @var ResponseHttp
*/
private ResponseHttp $response;
/**
* @var Logger
*/
private Logger $logger;
/**
* Index constructor.
*
* @param Webhook $webhook
* @param RequestHttp $request
* @param ResponseHttp $response
* @param Logger $logger
*/
public function __construct(
Webhook $webhook,
RequestHttp $request,
ResponseHttp $response,
Logger $logger
) {
$this->webhook = $webhook;
$this->request = $request;
$this->response = $response;
$this->logger = $logger;
}
/**
* Get request from airwallex. Check request checksum for security. Each request parse and run webhook action
*
* @return ResponseHttp
* @throws \JsonException
*/
public function execute()
{
$data = json_decode($this->request->getContent(), false, self::JSON_DECODE_DEPTH, JSON_THROW_ON_ERROR);
try {
$this->webhook->checkChecksum($this->request);
if ($data->data) {
$this->webhook->dispatch($data->name, $data->data->object);
}
} catch (Exception $exception) {
$this->logger->addError($exception->getMessage());
}
return $this->response->setStatusCode(self::HTTP_OK);
}
/**
* @param RequestInterface $request
* @SuppressWarnings(PHPMD.UnusedFormalParameter)
*
* @return InvalidRequestException|null
*/
public function createCsrfValidationException(RequestInterface $request): ?InvalidRequestException
{
return null;
}
/**
* @param RequestInterface $request
* @SuppressWarnings(PHPMD.UnusedFormalParameter)
*
* @return bool|null
*/
public function validateForCsrf(RequestInterface $request): ?bool
{
return true;
}
}
<?php
/**
* This file is part of the Airwallex Payments module.
*
* DISCLAIMER
*
* Do not edit or add to this file if you wish to upgrade
* to newer versions in the future.
*
* @copyright Copyright (c) 2021 Magebit, Ltd. (https://magebit.com/)
* @license GNU General Public License ("GPL") v3.0
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Airwallex\Payments\Exception;
use Magento\Framework\Exception\LocalizedException;
class WebhookException extends LocalizedException
{
}
<?php
/**
* This file is part of the Airwallex Payments module.
*
* DISCLAIMER
*
* Do not edit or add to this file if you wish to upgrade
* to newer versions in the future.
*
* @copyright Copyright (c) 2021 Magebit, Ltd. (https://magebit.com/)
* @license GNU General Public License ("GPL") v3.0
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Airwallex\Payments\Helper;
use Airwallex\Payments\Model\Client\Request\Authentication;
use Magento\Framework\App\CacheInterface;
use Magento\Framework\ObjectManagerInterface;
class AuthenticationHelper
{
private const CACHE_NAME = 'airwallex_token';
/**
* @var CacheInterface
*/
private CacheInterface $cache;
/**
* @var ObjectManagerInterface
*/
private ObjectManagerInterface $objectManager;
/**
* AuthenticationHelper constructor.
*
* @param CacheInterface $cache
* @param ObjectManagerInterface $objectManager
*/
public function __construct(
CacheInterface $cache,
ObjectManagerInterface $objectManager
) {
$this->cache = $cache;
$this->objectManager = $objectManager;
}
/**
* @return string
*/
public function getBearerToken(): string
{
$token = $this->cache->load(self::CACHE_NAME);
if (empty($token)) {
$authenticationData = $this->objectManager->create(Authentication::class)->send();
$token = $authenticationData->token;
$cacheLifetime = $this->getCacheLifetime($authenticationData->expires_at);
$this->cache->save($token, self::CACHE_NAME, [], $cacheLifetime);
}
return $token;
}
/**
* Clear authentication token from cache.
*
* @return void
*/
public function clearToken()
{
$this->cache->remove(self::CACHE_NAME);
}
/**
* @param string $expiresAt
* @return int
* @throws \Exception
*/
protected function getCacheLifetime(string $expiresAt): int
{
$expiresAtDate = new \DateTime($expiresAt);
$currentDate = new \DateTime();
$currentDate->setTimezone($expiresAtDate->getTimezone());
return $expiresAtDate->getTimestamp() - $currentDate->getTimestamp();
}
}
<?php
/**
* This file is part of the Airwallex Payments module.
*
* DISCLAIMER
*
* Do not edit or add to this file if you wish to upgrade
* to newer versions in the future.
*
* @copyright Copyright (c) 2021 Magebit, Ltd. (https://magebit.com/)
* @license GNU General Public License ("GPL") v3.0
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Airwallex\Payments\Helper;
use Airwallex\Payments\Model\Client\Request\AvailablePaymentMethods;
use Airwallex\Payments\Model\Methods\AbstractMethod;
use Exception;
use Magento\Framework\App\CacheInterface;
use Magento\Framework\Serialize\SerializerInterface;
use Magento\Store\Model\StoreManagerInterface;
class AvailablePaymentMethodsHelper
{
private const CACHE_NAME = 'airwallex_payment_methods';
private const CACHE_TIME = 60;
private const METHOD_MAPPING = [
'wechat' => 'wechatpay'
];
/**
* @var AvailablePaymentMethods
*/
private AvailablePaymentMethods $availablePaymentMethod;
/**
* @var CacheInterface
*/
private CacheInterface $cache;
/**
* @var StoreManagerInterface
*/
private StoreManagerInterface $storeManager;
/**
* @var SerializerInterface
*/
private SerializerInterface $serializer;
/**
* @var Configuration
*/
private Configuration $configuration;
/**
* AvailablePaymentMethodsHelper constructor.
*
* @param AvailablePaymentMethods $availablePaymentMethod
* @param CacheInterface $cache
* @param SerializerInterface $serializer
* @param StoreManagerInterface $storeManager
* @param Configuration $configuration
*/
public function __construct(
AvailablePaymentMethods $availablePaymentMethod,
CacheInterface $cache,
SerializerInterface $serializer,
StoreManagerInterface $storeManager,
Configuration $configuration
) {
$this->availablePaymentMethod = $availablePaymentMethod;
$this->cache = $cache;
$this->storeManager = $storeManager;
$this->serializer = $serializer;
$this->configuration = $configuration;
}
/**
* @return bool
*/
public function canInitialize(): bool
{
return class_exists('Mobile_Detect') &&
!is_null($this->configuration->getApiKey()) &&
!is_null($this->configuration->getClientId());
}
/**
* @param string $code
*
* @return bool
*/
public function isAvailable(string $code): bool
{
$code = self::METHOD_MAPPING[$code] ?? $code;
return $this->canInitialize() && in_array($code, $this->getAllMethods(), true);
}
/**
* @return array
*/
private function getAllMethods(): array
{
$methods = $this->cache->load($this->getCacheName());
if ($methods) {
return $this->serializer->unserialize($methods);
}
try {
$methods = $this->availablePaymentMethod->setCurrency($this->getCurrencyCode())->send();
} catch (Exception $e) {
$methods = [];
}
$this->cache->save(
$this->serializer->serialize($methods),
$this->getCacheName(),
AbstractMethod::CACHE_TAGS,
self::CACHE_TIME
);
return $methods;
}
/**
* @return string
*/
private function getCacheName(): string
{
return self::CACHE_NAME . $this->getCurrencyCode();
}
/**
* @return string
*/
private function getCurrencyCode(): string
{
try {
return $this->storeManager->getStore()->getCurrentCurrency()->getCode();
} catch (Exception $exception) {
return '';
}
}
}
<?php
/**
* This file is part of the Airwallex Payments module.
*
* DISCLAIMER
*
* Do not edit or add to this file if you wish to upgrade
* to newer versions in the future.
*
* @copyright Copyright (c) 2021 Magebit, Ltd. (https://magebit.com/)
* @license GNU General Public License ("GPL") v3.0
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Airwallex\Payments\Helper;
class CancelHelper
{
/**
* @var bool
*/
private bool $webhookCanceling = false;
/**
* @return bool
*/
public function isWebhookCanceling(): bool
{
return $this->webhookCanceling;
}
/**
* @param bool $webhookCanceling
*/
public function setWebhookCanceling(bool $webhookCanceling): void
{
$this->webhookCanceling = $webhookCanceling;
}
}
<?php
/**
* This file is part of the Airwallex Payments module.
*
* DISCLAIMER
*
* Do not edit or add to this file if you wish to upgrade
* to newer versions in the future.
*
* @copyright Copyright (c) 2021 Magebit, Ltd. (https://magebit.com/)
* @license GNU General Public License ("GPL") v3.0
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Airwallex\Payments\Helper;
use Airwallex\Payments\Model\Config\Source\Mode;
use Magento\Framework\App\Helper\AbstractHelper;
use Magento\Payment\Model\MethodInterface;
class Configuration extends AbstractHelper
{
public const MODULE_NAME = 'Airwallex_Payments';
private const DEMO_BASE_URL = 'https://pci-api-demo.airwallex.com/api/v1/';
private const PRODUCTION_BASE_URL = 'https://pci-api.airwallex.com/api/v1/';
/**
* @return string|null
*/
public function getClientId(): ?string
{
return $this->scopeConfig->getValue('airwallex/general/' . $this->getMode() . '_client_id');
}
/**
* @return string|null
*/
public function getApiKey(): ?string
{
return $this->scopeConfig->getValue('airwallex/general/' . $this->getMode() . '_api_key');
}
/**
* @return bool
*/
public function isRequestLoggerEnable(): bool
{
return (bool) $this->scopeConfig->getValue('airwallex/general/request_logger');
}
/**
* @return string
*/
public function getWebhookSecretKey(): string
{
return $this->scopeConfig->getValue(
'airwallex/general/webhook_' . $this->getMode() . '_secret_key'
);
}
/**
* @return string
*/
public function getMode(): string
{
return $this->scopeConfig->getValue('airwallex/general/mode');
}
/**
* @return string
*/
public function getCardPaymentAction(): string
{
return $this->scopeConfig->getValue('payment/airwallex_payments_card/airwallex_payment_action');
}
/**
* @return string
*/
public function getApiUrl(): string
{
return $this->isDemoMode() ? self::DEMO_BASE_URL : self::PRODUCTION_BASE_URL;
}
/**
* @return bool
*/
private function isDemoMode(): bool
{
return $this->getMode() === Mode::DEMO;
}
/**
* @return bool
*/
public function isCaptureEnabled() {
return $this->scopeConfig->getValue('payment/airwallex_payments_card/airwallex_payment_action') === MethodInterface::ACTION_AUTHORIZE_CAPTURE;
}
}
<?php
/**
* This file is part of the Airwallex Payments module.
*
* DISCLAIMER
*
* Do not edit or add to this file if you wish to upgrade
* to newer versions in the future.
*
* @copyright Copyright (c) 2021 Magebit, Ltd. (https://magebit.com/)
* @license GNU General Public License ("GPL") v3.0
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Airwallex\Payments\Logger\Guzzle;
use Exception;
use GuzzleHttp\MessageFormatter as BaseMessageFormatter;
use Psr\Http\Message\RequestInterface;
use Psr\Http\Message\ResponseInterface;
class MessageFormatter extends BaseMessageFormatter
{
private const WITHOUT_HEADERS = [
'Authorization',
'x-client-id',
'x-api-key'
];
/**
* Returns a formatted message string.
*
* @param RequestInterface $request Request that was sent
* @param ResponseInterface|null $response Response that was received
* @param \Throwable|null $error Exception that was received
*
* @return string
*/
public function format(
RequestInterface $request,
ResponseInterface $response = null,
\Throwable $error = null
): string {
foreach (self::WITHOUT_HEADERS as $header) {
$request = $request->withoutHeader($header);
}
return parent::format($request, $response, $error);
}
}
<?php
/**
* This file is part of the Airwallex Payments module.
*
* DISCLAIMER
*
* Do not edit or add to this file if you wish to upgrade
* to newer versions in the future.
*
* @copyright Copyright (c) 2021 Magebit, Ltd. (https://magebit.com/)
* @license GNU General Public License ("GPL") v3.0
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Airwallex\Payments\Logger\Guzzle;
use Airwallex\Payments\Helper\Configuration;
use Airwallex\Payments\Logger\Logger;
use GuzzleHttp\HandlerStack;
use GuzzleHttp\Middleware;
use Magento\Framework\App\Filesystem\DirectoryList;
use Magento\Framework\Exception\FileSystemException;
use Monolog\Handler\StreamHandler;
class RequestLogger
{
private const FILE_NAME = 'airwallex_request.log';
/**
* @var Configuration
*/
private Configuration $configuration;
/**
* @var DirectoryList
*/
private DirectoryList $directoryList;
/**
* @var Logger
*/
private Logger $logger;
/**
* RequestLogger constructor.
*
* @param Configuration $configuration
* @param DirectoryList $directoryList
* @param Logger $logger
*/
public function __construct(Configuration $configuration, DirectoryList $directoryList, Logger $logger)
{
$this->configuration = $configuration;
$this->directoryList = $directoryList;
$this->logger = $logger;
}
/**
* @return HandlerStack
* @throws \Exception
*/
public function getStack(): HandlerStack
{
$stack = HandlerStack::create();
if (!$this->configuration->isRequestLoggerEnable()) {
return $stack;
}
$stack->push(Middleware::log(
(new Logger('Logger'))->pushHandler(new StreamHandler($this->getFileLocation())),
new MessageFormatter(MessageFormatter::DEBUG)
));
return $stack;
}
/**
* @return string
*/
private function getFileLocation(): string
{
try {
return $this->directoryList->getPath(DirectoryList::LOG) . DIRECTORY_SEPARATOR . self::FILE_NAME;
} catch (FileSystemException $exception) {
$this->logger->error($exception->getMessage());
}
return '';
}
}
<?php
/**
* This file is part of the Airwallex Payments module.
*
* DISCLAIMER
*
* Do not edit or add to this file if you wish to upgrade
* to newer versions in the future.
*
* @copyright Copyright (c) 2021 Magebit, Ltd. (https://magebit.com/)
* @license GNU General Public License ("GPL") v3.0
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Airwallex\Payments\Logger;
use Magento\Framework\Logger\Handler\Base;
class Handler extends Base
{
/**
* Logging level
* @var int
*/
protected $loggerType = Logger::NOTICE;
/**
* File name
* @var string
*/
protected $fileName = '/var/log/airwallex_payments.log';
}
<?php
/**
* This file is part of the Airwallex Payments module.
*
* DISCLAIMER
*
* Do not edit or add to this file if you wish to upgrade
* to newer versions in the future.
*
* @copyright Copyright (c) 2021 Magebit, Ltd. (https://magebit.com/)
* @license GNU General Public License ("GPL") v3.0
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Airwallex\Payments\Logger;
use Magento\Quote\Model\Quote;
use Magento\Sales\Model\Order;
use Monolog\Logger as BaseLogger;
class Logger extends BaseLogger
{
/**
* @param Quote $quote
* @param string $method
* @param string $message
*
* @return bool
*/
public function quoteError(Quote $quote, string $method, string $message): bool
{
$text = sprintf(
'%s Quote: %s - %s',
mb_strtoupper($method),
$quote->getId(),
$message
);
return $this->error($text);
}
/**
* @param Order $order
* @param string $method
* @param string $message
*
* @return bool
*/
public function orderError(Order $order, string $method, string $message): bool
{
$text = sprintf(
'%s Order: %s - %s',
mb_strtoupper($method),
$order->getIncrementId(),
$message
);
return $this->error($text);
}
}
<?php
/**
* This file is part of the Airwallex Payments module.
*
* DISCLAIMER
*
* Do not edit or add to this file if you wish to upgrade
* to newer versions in the future.
*
* @copyright Copyright (c) 2021 Magebit, Ltd. (https://magebit.com/)
* @license GNU General Public License ("GPL") v3.0
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Airwallex\Payments\Model\Adminhtml\Notifications;
use Airwallex\Payments\Helper\AvailablePaymentMethodsHelper;
use Magento\Framework\Notification\MessageInterface;
class Dependencies implements MessageInterface
{
/**
* @var string|null
*/
private ?string $displayedText = null;
/**
* @var AvailablePaymentMethodsHelper
*/
private AvailablePaymentMethodsHelper $availablePaymentMethodsHelper;
/**
* Dependencies constructor.
*
* @param AvailablePaymentMethodsHelper $availablePaymentMethodsHelper
*/
public function __construct(AvailablePaymentMethodsHelper $availablePaymentMethodsHelper)
{
$this->availablePaymentMethodsHelper = $availablePaymentMethodsHelper;
$this->hasDependencies();
}
/**
* @return string
*/
public function getIdentity(): string
{
return 'airwallex_payments_notification_dependencies';
}
/**
* @return bool
*/
public function isDisplayed(): bool
{
return $this->displayedText !== null;
}
/**
* @return string
*/
public function getText(): string
{
return $this->displayedText;
}
/**
* @return int
*/
public function getSeverity(): int
{
return self::SEVERITY_MAJOR;
}
/**
* @return void
*/
private function hasDependencies(): void
{
if (!$this->availablePaymentMethodsHelper->canInitialize()) {
$this->displayedText = __('The Airwallex Payment module is missing dependency
Please run "composer require mobiledetect/mobiledetectlib" to install the dependency.');
}
}
}
<?php
/**
* This file is part of the Airwallex Payments module.
*
* DISCLAIMER
*
* Do not edit or add to this file if you wish to upgrade
* to newer versions in the future.
*
* @copyright Copyright (c) 2021 Magebit, Ltd. (https://magebit.com/)
* @license GNU General Public License ("GPL") v3.0
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Airwallex\Payments\Model\Client;
use Airwallex\Payments\Helper\AuthenticationHelper;
use Airwallex\Payments\Helper\Configuration;
use Airwallex\Payments\Logger\Guzzle\RequestLogger;
use Airwallex\Payments\Model\Client\Interfaces\BearerAuthenticationInterface;
use GuzzleHttp\Client;
use GuzzleHttp\Exception\GuzzleException;
use Magento\Framework\DataObject\IdentityService;
use Magento\Framework\Module\ModuleListInterface;
use Psr\Http\Message\ResponseInterface;
abstract class AbstractClient
{
private const JSON_DECODE_DEPTH = 512;
private const SUCCESS_STATUS_START = 200;
private const SUCCESS_STATUS_END = 299;
private const AUTHENTICATION_FAILED = 401;
private const TIME_OUT = 30;
private const DEFAULT_HEADER = [
'Content-Type' => 'application/json',
'region' => 'string'
];
/**
* @var AuthenticationHelper
*/
private AuthenticationHelper $authenticationHelper;
/**
* @var IdentityService
*/
private IdentityService $identityService;
/**
* @var RequestLogger
*/
private RequestLogger $requestLogger;
/**
* @var Configuration
*/
protected Configuration $configuration;
/**
* @var ModuleListInterface
*/
protected ModuleListInterface $moduleList;
/**
* @var array
*/
private array $params = [];
/**
* AbstractClient constructor.
*
* @param AuthenticationHelper $authenticationHelper
* @param IdentityService $identityService
* @param RequestLogger $requestLogger
* @param Configuration $configuration
* @param ModuleListInterface $moduleList
*/
public function __construct(
AuthenticationHelper $authenticationHelper,
IdentityService $identityService,
RequestLogger $requestLogger,
Configuration $configuration,
ModuleListInterface $moduleList
) {
$this->authenticationHelper = $authenticationHelper;
$this->identityService = $identityService;
$this->requestLogger = $requestLogger;
$this->configuration = $configuration;
$this->moduleList = $moduleList;
}
/**
* @return mixed
* @throws GuzzleException
* @throws \JsonException
* @throws RequestException
*/
public function send()
{
$client = new Client([
'base_uri' => $this->configuration->getApiUrl(),
'timeout' => self::TIME_OUT,
'handler' => $this->requestLogger->getStack()
]);
$request = $this->createRequest($client);
$statusCode = $request->getStatusCode();
// If authorization fails on first try, clear token from cache and try again.
if ($statusCode === self::AUTHENTICATION_FAILED) {
$this->authenticationHelper->clearToken();
$request = $this->createRequest($client);
$statusCode = $request->getStatusCode();
}
// If still invalid response, process error.
if (!($statusCode >= self::SUCCESS_STATUS_START && $statusCode < self::SUCCESS_STATUS_END)) {
$response = $this->parseJson($request);
throw new RequestException($response->message);
}
return $this->parseResponse($request);
}
/**
* @param array $params
*
* @return $this
*/
protected function setParams(array $params): AbstractClient
{
$this->params = array_merge($this->params, $params);
return $this;
}
/**
* @param string $name
* @param string $value
*
* @return $this
*/
protected function setParam(string $name, string $value): AbstractClient
{
$this->params[$name] = $value;
return $this;
}
/**
* @return string
*/
protected function getMethod(): string
{
return 'POST';
}
/**
* @param ResponseInterface $request
*
* @return object
* @throws \JsonException
*/
protected function parseJson(ResponseInterface $request): object
{
return json_decode((string) $request->getBody(), false, self::JSON_DECODE_DEPTH, JSON_THROW_ON_ERROR);
}
/**
* Get options to create request.
*
* @return array
*/
protected function getRequestOptions(): array
{
return [
'headers' => array_merge(self::DEFAULT_HEADER, $this->getHeaders()),
'http_errors' => false
];
}
/**
* @return array
*/
protected function getHeaders(): array
{
$header = [];
if ($this instanceof BearerAuthenticationInterface) {
$header['Authorization'] = 'Bearer ' . $this->authenticationHelper->getBearerToken();
}
return $header;
}
/**
* Get information about Magento version executing the request.
*
* @return array
*/
protected function getReferrerData(): array
{
return [
'type' => 'magento',
'version' => $this->moduleList->getOne(Configuration::MODULE_NAME)['setup_version']
];
}
/**
* Create request to Airwallex.
*
* @param Client $client
* @return ResponseInterface
* @throws GuzzleException
*/
protected function createRequest(Client $client): ResponseInterface
{
$method = $this->getMethod();
$options = $this->getRequestOptions();
if ($method === 'POST') {
$this->params['request_id'] = $this->identityService->generateId();
$this->params['referrer_data'] = $this->getReferrerData();
$options['json'] = $this->params;
}
return $client->request($this->getMethod(), $this->getUri(), $options);
}
/**
* @return string
*/
abstract protected function getUri(): string;
/**
* @param ResponseInterface $request
*
* @return mixed
*/
abstract protected function parseResponse(ResponseInterface $request);
}
<?php
/**
* This file is part of the Airwallex Payments module.
*
* DISCLAIMER
*
* Do not edit or add to this file if you wish to upgrade
* to newer versions in the future.
*
* @copyright Copyright (c) 2021 Magebit, Ltd. (https://magebit.com/)
* @license GNU General Public License ("GPL") v3.0
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Airwallex\Payments\Model\Client\Interfaces;
interface BearerAuthenticationInterface
{
}
<?php
/**
* This file is part of the Airwallex Payments module.
*
* DISCLAIMER
*
* Do not edit or add to this file if you wish to upgrade
* to newer versions in the future.
*
* @copyright Copyright (c) 2021 Magebit, Ltd. (https://magebit.com/)
* @license GNU General Public License ("GPL") v3.0
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Airwallex\Payments\Model\Client\Request;
use Airwallex\Payments\Model\Client\AbstractClient;
use JsonException;
use Psr\Http\Message\ResponseInterface;
class Authentication extends AbstractClient
{
private const X_API_VERSION = '2020-04-30';
/**
* @return string[]
*/
protected function getHeaders(): array
{
return [
'x-client-id' => $this->configuration->getClientId(),
'x-api-key' => $this->configuration->getApiKey(),
'x-api-version' => self::X_API_VERSION
];
}
/**
* @return string
*/
protected function getUri(): string
{
return 'authentication/login';
}
/**
* @param ResponseInterface $request
*
* @return object
* @throws JsonException
*/
protected function parseResponse(ResponseInterface $request): object
{
return $this->parseJson($request);
}
}
<?php
/**
* This file is part of the Airwallex Payments module.
*
* DISCLAIMER
*
* Do not edit or add to this file if you wish to upgrade
* to newer versions in the future.
*
* @copyright Copyright (c) 2021 Magebit, Ltd. (https://magebit.com/)
* @license GNU General Public License ("GPL") v3.0
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Airwallex\Payments\Model\Client\Request;
use Airwallex\Payments\Model\Client\AbstractClient;
use Airwallex\Payments\Model\Client\Interfaces\BearerAuthenticationInterface;
use Psr\Http\Message\ResponseInterface;
class AvailablePaymentMethods extends AbstractClient implements BearerAuthenticationInterface
{
private const TRANSACTION_MODE = 'oneoff';
/**
* @var string
*/
private string $currency;
/**
* @param string $currency
*
* @return $this
*/
public function setCurrency(string $currency): self
{
$this->currency = $currency;
return $this;
}
/**
* @return string
*/
protected function getUri(): string
{
$params = http_build_query([
'transaction_mode' => self::TRANSACTION_MODE,
'transaction_currency' => $this->currency,
'active' => true,
]);
return 'pa/config/payment_method_types?' . $params;
}
/**
* @return string
*/
protected function getMethod(): string
{
return 'GET';
}
/**
* @param ResponseInterface $request
*
* @return array
* @throws \JsonException
*/
protected function parseResponse(ResponseInterface $request): array
{
$response = $this->parseJson($request);
return array_map(static function (object $item) {
return $item->name;
}, $response->items);
}
}
<?php
/**
* This file is part of the Airwallex Payments module.
*
* DISCLAIMER
*
* Do not edit or add to this file if you wish to upgrade
* to newer versions in the future.
*
* @copyright Copyright (c) 2021 Magebit, Ltd. (https://magebit.com/)
* @license GNU General Public License ("GPL") v3.0
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Airwallex\Payments\Model\Client\Request\PaymentIntents;
use Airwallex\Payments\Model\Client\AbstractClient;
use Airwallex\Payments\Model\Client\Interfaces\BearerAuthenticationInterface;
use Psr\Http\Message\ResponseInterface;
class Cancel extends AbstractClient implements BearerAuthenticationInterface
{
/**
* @var string
*/
private string $paymentIntentId;
/**
* @param string $id
*
* @return $this
*/
public function setPaymentIntentId(string $id): self
{
$this->paymentIntentId = $id;
return $this;
}
/**
* @return string
*/
protected function getUri(): string
{
return 'pa/payment_intents/' . $this->paymentIntentId . '/cancel';
}
/**
* @param ResponseInterface $request
*
* @return object
* @throws \JsonException
*/
protected function parseResponse(ResponseInterface $request): object
{
return $this->parseJson($request);
}
}
<?php
/**
* This file is part of the Airwallex Payments module.
*
* DISCLAIMER
*
* Do not edit or add to this file if you wish to upgrade
* to newer versions in the future.
*
* @copyright Copyright (c) 2021 Magebit, Ltd. (https://magebit.com/)
* @license GNU General Public License ("GPL") v3.0
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Airwallex\Payments\Model\Client\Request\PaymentIntents;
use Airwallex\Payments\Model\Client\AbstractClient;
use Airwallex\Payments\Model\Client\Interfaces\BearerAuthenticationInterface;
use Psr\Http\Message\ResponseInterface;
class Capture extends AbstractClient implements BearerAuthenticationInterface
{
/**
* @var string
*/
private string $paymentIntentId;
/**
* @param string $id
*
* @return $this
*/
public function setPaymentIntentId(string $id): self
{
$this->paymentIntentId = $id;
return $this;
}
/**
* @param float $amount
*
* @return Capture
*/
public function setInformation(float $amount): self
{
return $this->setParams([
'amount' => $amount,
]);
}
/**
* @return string
*/
protected function getUri(): string
{
return 'pa/payment_intents/' . $this->paymentIntentId . '/capture';
}
/**
* @param ResponseInterface $request
*
* @return object
* @throws \JsonException
*/
protected function parseResponse(ResponseInterface $request): object
{
return $this->parseJson($request);
}
}
<?php
/**
* This file is part of the Airwallex Payments module.
*
* DISCLAIMER
*
* Do not edit or add to this file if you wish to upgrade
* to newer versions in the future.
*
* @copyright Copyright (c) 2021 Magebit, Ltd. (https://magebit.com/)
* @license GNU General Public License ("GPL") v3.0
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Airwallex\Payments\Model\Client\Request\PaymentIntents;
use Airwallex\Payments\Model\Client\AbstractClient;
use Airwallex\Payments\Model\Client\Interfaces\BearerAuthenticationInterface;
use Psr\Http\Message\ResponseInterface;
class Confirm extends AbstractClient implements BearerAuthenticationInterface
{
private const DESKTOP_FLOW = 'webqr';
private const MOBILE_FLOW = 'mweb';
/**
* @var string
*/
private string $paymentIntentId;
/**
* @param string $id
*
* @return $this
*/
public function setPaymentIntentId(string $id): self
{
$this->paymentIntentId = $id;
return $this;
}
/**
* @param string $method
* @param bool $isMobile
* @param string|null $osType
*
* @return Confirm
*/
public function setInformation(string $method, bool $isMobile, string $osType = null): self
{
$data = [
'type' => $method
];
$data[$method] = [
'flow' => $isMobile ? self::MOBILE_FLOW : self::DESKTOP_FLOW
];
if ($isMobile) {
$data[$method]['os_type'] = $osType;
}
return $this->setParams([
'payment_method' => $data
]);
}
/**
* @return string
*/
protected function getUri(): string
{
return 'pa/payment_intents/' . $this->paymentIntentId . '/confirm';
}
/**
* @param ResponseInterface $request
*
* @return string
* @throws \JsonException
*/
protected function parseResponse(ResponseInterface $request): string
{
$request = $this->parseJson($request);
return $request->next_action->url;
}
}
<?php
/**
* This file is part of the Airwallex Payments module.
*
* DISCLAIMER
*
* Do not edit or add to this file if you wish to upgrade
* to newer versions in the future.
*
* @copyright Copyright (c) 2021 Magebit, Ltd. (https://magebit.com/)
* @license GNU General Public License ('GPL') v3.0
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Airwallex\Payments\Model\Client\Request\PaymentIntents;
use Airwallex\Payments\Model\Client\AbstractClient;
use Airwallex\Payments\Model\Client\Interfaces\BearerAuthenticationInterface;
use Magento\Quote\Model\Quote;
use Magento\Quote\Model\Quote\Item;
use Psr\Http\Message\ResponseInterface;
class Create extends AbstractClient implements BearerAuthenticationInterface
{
/**
* @param Quote $quote
* @param string $returnUrl
*
* @return AbstractClient|Create
*/
public function setQuote(Quote $quote, string $returnUrl): self
{
return $this->setParams([
'amount' => $quote->getBaseGrandTotal(),
'currency' => $quote->getQuoteCurrencyCode(),
'merchant_order_id' => $quote->getReservedOrderId(),
'supplementary_amount' => 1,
'return_url' => $returnUrl,
'order' => [
'products' => array_values(array_filter($this->getQuoteProducts($quote))),
'shipping' => $this->getShippingAddress($quote)
]
]);
}
/**
* @return string
*/
protected function getUri(): string
{
return 'pa/payment_intents/create';
}
/**
* @param ResponseInterface $request
*
* @return array
* @throws \JsonException
*/
protected function parseResponse(ResponseInterface $request): array
{
$data = $this->parseJson($request);
return [
'clientSecret' => $data->client_secret,
'id' => $data->id,
];
}
/**
* @param Quote $quote
*
* @return array|null
*/
private function getShippingAddress(Quote $quote): ?array
{
$shippingAddress = $quote->getShippingAddress();
if ($quote->getIsVirtual()) {
return null;
}
return [
'fist_name' => $shippingAddress->getName(),
'last_name' => $shippingAddress->getLastname(),
'phone_number' => $shippingAddress->getTelephone(),
'shipping_method' => $shippingAddress->getShippingMethod(),
'address' => [
'city' => $shippingAddress->getCity(),
'country_code' => $shippingAddress->getCountryId(),
'postcode' => $shippingAddress->getPostcode(),
'state' => $shippingAddress->getRegion(),
'street' => current($shippingAddress->getStreet()),
]
];
}
/**
* @param Quote $quote
*
* @return array
*/
private function getQuoteProducts(Quote $quote): array
{
return array_map(static function (Item $item) {
if ((float) $item->getPrice() === 0.0) {
return null;
}
$child = $item->getChildren();
$child = $child ? current($child) : null;
$name = $child ? $child->getName() : $item->getName();
return [
'code' => $item->getSku(),
'desc' => $name,
'name' => $name,
'quantity' => $item->getQty(),
'sku' => $item->getSku(),
'unit_price' => $item->getPrice(),
'url' => $item->getProduct()->getProductUrl()
];
}, $quote->getAllItems());
}
}
<?php
/**
* This file is part of the Airwallex Payments module.
*
* DISCLAIMER
*
* Do not edit or add to this file if you wish to upgrade
* to newer versions in the future.
*
* @copyright Copyright (c) 2021 Magebit, Ltd. (https://magebit.com/)
* @license GNU General Public License ("GPL") v3.0
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Airwallex\Payments\Model\Client\Request\PaymentIntents;
use Airwallex\Payments\Model\Client\AbstractClient;
use Airwallex\Payments\Model\Client\Interfaces\BearerAuthenticationInterface;
use Psr\Http\Message\ResponseInterface;
class Refund extends AbstractClient implements BearerAuthenticationInterface
{
/**
* @param string $paymentIntentId
* @param float $amount
*
* @return Refund
*/
public function setInformation(string $paymentIntentId, float $amount): self
{
return $this->setParams([
'amount' => $amount,
'payment_intent_id' => $paymentIntentId
]);
}
/**
* @return string
*/
protected function getUri(): string
{
return 'pa/refunds/create';
}
/**
* @param ResponseInterface $request
*
* @return object
* @throws \JsonException
*/
protected function parseResponse(ResponseInterface $request): object
{
return $this->parseJson($request);
}
}
<?php
/**
* This file is part of the Airwallex Payments module.
*
* DISCLAIMER
*
* Do not edit or add to this file if you wish to upgrade
* to newer versions in the future.
*
* @copyright Copyright (c) 2021 Magebit, Ltd. (https://magebit.com/)
* @license GNU General Public License ("GPL") v3.0
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Airwallex\Payments\Model\Client;
use RuntimeException;
class RequestException extends RuntimeException
{
}
<?php
/**
* This file is part of the Airwallex Payments module.
*
* DISCLAIMER
*
* Do not edit or add to this file if you wish to upgrade
* to newer versions in the future.
*
* @copyright Copyright (c) 2021 Magebit, Ltd. (https://magebit.com/)
* @license GNU General Public License ("GPL") v3.0
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Airwallex\Payments\Model\Config\Source;
use Magento\Framework\Data\OptionSourceInterface;
class Mode implements OptionSourceInterface
{
public const DEMO = 'demo';
private const PRODUCTION = 'prod';
/**
* @return array[]
*/
public function toOptionArray(): array
{
return [
[
'value' => self::DEMO,
'label' => __('Demo')
],
[
'value' => self::PRODUCTION,
'label' => __('Production')
],
];
}
}
<?php
/**
* This file is part of the Airwallex Payments module.
*
* DISCLAIMER
*
* Do not edit or add to this file if you wish to upgrade
* to newer versions in the future.
*
* @copyright Copyright (c) 2021 Magebit, Ltd. (https://magebit.com/)
* @license GNU General Public License ("GPL") v3.0
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Airwallex\Payments\Model\Config\Source;
use Magento\Framework\Data\OptionSourceInterface;
use Magento\Payment\Model\MethodInterface;
class PaymentAction implements OptionSourceInterface
{
/**
* @return array[]
*/
public function toOptionArray(): array
{
return [
[
'value' => MethodInterface::ACTION_AUTHORIZE,
'label' => __('Authorize Only')
],
[
'value' => MethodInterface::ACTION_AUTHORIZE_CAPTURE,
'label' => __('Authorize and Capture')
],
];
}
}
<?php
/**
* This file is part of the Airwallex Payments module.
*
* DISCLAIMER
*
* Do not edit or add to this file if you wish to upgrade
* to newer versions in the future.
*
* @copyright Copyright (c) 2021 Magebit, Ltd. (https://magebit.com/)
* @license GNU General Public License ("GPL") v3.0
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Airwallex\Payments\Model\Config\Source;
use Magento\Backend\Block\Template\Context;
use Magento\Config\Block\System\Config\Form\Field;
use Magento\Framework\App\Config\ScopeConfigInterface;
use Magento\Framework\Data\Form\Element\AbstractElement;
class WebhookUrl extends Field
{
private const WEBHOOK_PATH = 'airwallex/webhooks';
/**
* @var ScopeConfigInterface
*/
private ScopeConfigInterface $scopeConfig;
/**
* WebhookUrl constructor.
*
* @param ScopeConfigInterface $scopeConfig
* @param Context $context
* @param array $data
*/
public function __construct(
ScopeConfigInterface $scopeConfig,
Context $context,
array $data = []
) {
parent::__construct($context, $data);
$this->scopeConfig = $scopeConfig;
}
/**
* {@inheritDoc}
* @param AbstractElement $element
* @return string
*/
public function _getElementHtml(AbstractElement $element): string
{
$element->setValue($this->scopeConfig->getValue('web/secure/base_url') . self::WEBHOOK_PATH);
$element->setDisabled('disabled');
return parent::_getElementHtml($element);
}
}
<?php
/**
* This file is part of the Airwallex Payments module.
*
* DISCLAIMER
*
* Do not edit or add to this file if you wish to upgrade
* to newer versions in the future.
*
* @copyright Copyright (c) 2021 Magebit, Ltd. (https://magebit.com/)
* @license GNU General Public License ("GPL") v3.0
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Airwallex\Payments\Model\Methods;
use Airwallex\Payments\Helper\AvailablePaymentMethodsHelper;
use Airwallex\Payments\Helper\CancelHelper;
use Airwallex\Payments\Model\Client\Request\PaymentIntents\Cancel;
use Airwallex\Payments\Model\Client\Request\PaymentIntents\Capture;
use Airwallex\Payments\Model\Client\Request\PaymentIntents\Confirm;
use Airwallex\Payments\Model\Client\Request\PaymentIntents\Refund;
use Airwallex\Payments\Model\PaymentIntentRepository;
use Exception;
use GuzzleHttp\Exception\GuzzleException;
use Magento\Checkout\Helper\Data as CheckoutData;
use Magento\Framework\DataObject;
use Magento\Framework\Event\ManagerInterface;
use Magento\Framework\Exception\AlreadyExistsException;
use Magento\Framework\Exception\LocalizedException;
use Magento\Payment\Gateway\Command\CommandManagerInterface;
use Magento\Payment\Gateway\Command\CommandPoolInterface;
use Magento\Payment\Gateway\Config\ValueHandlerPoolInterface;
use Magento\Payment\Gateway\Data\PaymentDataObjectFactory;
use Magento\Payment\Gateway\Validator\ValidatorPoolInterface;
use Magento\Payment\Model\InfoInterface;
use Magento\Payment\Model\Method\Adapter;
use Magento\Quote\Api\Data\CartInterface;
use Psr\Log\LoggerInterface;
use RuntimeException;
/**
* @SuppressWarnings(PHPMD.CouplingBetweenObjects)
* @SuppressWarnings(PHPMD.ExcessiveParameterList)
*/
abstract class AbstractMethod extends Adapter
{
public const CACHE_TAGS = ['airwallex'];
public const PAYMENT_PREFIX = 'airwallex_payments_';
/**
* @var LoggerInterface|null
*/
protected $logger;
/**
* @var Refund
*/
private Refund $refund;
/**
* @var Capture
*/
protected Capture $capture;
/**
* @var PaymentIntentRepository
*/
private PaymentIntentRepository $paymentIntentRepository;
/**
* @var Cancel
*/
private Cancel $cancel;
/**
* @var CancelHelper
*/
private CancelHelper $cancelHelper;
/**
* @var AvailablePaymentMethodsHelper
*/
private AvailablePaymentMethodsHelper $availablePaymentMethodsHelper;
/**
* @var Confirm
*/
protected Confirm $confirm;
/**
* @var CheckoutData
*/
protected CheckoutData $checkoutHelper;
/**
* Payment constructor.
*
* @param ManagerInterface $eventManager
* @param ValueHandlerPoolInterface $valueHandlerPool
* @param PaymentDataObjectFactory $paymentDataObjectFactory
* @param string $code
* @param string $formBlockType
* @param string $infoBlockType
* @param Refund $refund
* @param Capture $capture
* @param Cancel $cancel
* @param Confirm $confirm
* @param CheckoutData $checkoutHelper
* @param AvailablePaymentMethodsHelper $availablePaymentMethodsHelper
* @param CancelHelper $cancelHelper
* @param PaymentIntentRepository $paymentIntentRepository
* @param CommandPoolInterface|null $commandPool
* @param ValidatorPoolInterface|null $validatorPool
* @param CommandManagerInterface|null $commandExecutor
* @param LoggerInterface|null $logger
*/
public function __construct(
ManagerInterface $eventManager,
ValueHandlerPoolInterface $valueHandlerPool,
PaymentDataObjectFactory $paymentDataObjectFactory,
$code,
$formBlockType,
$infoBlockType,
Refund $refund,
Capture $capture,
Cancel $cancel,
Confirm $confirm,
CheckoutData $checkoutHelper,
AvailablePaymentMethodsHelper $availablePaymentMethodsHelper,
CancelHelper $cancelHelper,
PaymentIntentRepository $paymentIntentRepository,
CommandPoolInterface $commandPool = null,
ValidatorPoolInterface $validatorPool = null,
CommandManagerInterface $commandExecutor = null,
LoggerInterface $logger = null
) {
parent::__construct(
$eventManager,
$valueHandlerPool,
$paymentDataObjectFactory,
$code,
$formBlockType,
$infoBlockType,
$commandPool,
$validatorPool,
$commandExecutor,
$logger
);
$this->logger = $logger;
$this->refund = $refund;
$this->capture = $capture;
$this->paymentIntentRepository = $paymentIntentRepository;
$this->cancel = $cancel;
$this->availablePaymentMethodsHelper = $availablePaymentMethodsHelper;
$this->cancelHelper = $cancelHelper;
$this->confirm = $confirm;
$this->checkoutHelper = $checkoutHelper;
}
/**
* @param DataObject $data
*
* @return $this
* @throws LocalizedException
*/
public function assignData(DataObject $data): self
{
$additionalData = $data->getData('additional_data');
if (isset($additionalData['intent_id'])) {
$info = $this->getInfoInstance();
$info->setAdditionalInformation('intent_id', $additionalData['intent_id']);
}
return $this;
}
/**
* @param InfoInterface $payment
* @param float $amount
*
* @return $this
* @throws AlreadyExistsException|LocalizedException
* @SuppressWarnings(PHPMD.UnusedFormalParameter)
*/
public function authorize(InfoInterface $payment, $amount): self
{
$intentId = $this->getIntentId();
$payment->setTransactionId($intentId);
$payment->setIsTransactionClosed(false);
$this->paymentIntentRepository->save(
$payment->getOrder()->getIncrementId(),
$intentId
);
return $this;
}
/**
* @param InfoInterface $payment
* @param float $amount
*
* @return $this
* @SuppressWarnings(PHPMD.UnusedFormalParameter)
*/
public function capture(InfoInterface $payment, $amount): self
{
return $this;
}
/**
* @param InfoInterface $payment
*
* @return $this
* @throws Exception
*/
public function cancel(InfoInterface $payment): self
{
if ($this->cancelHelper->isWebhookCanceling()) {
return $this;
}
$paymentTransactionId = str_replace(['-void', '-cancel'], '', $payment->getTransactionId());
try {
$this->cancel->setPaymentIntentId($paymentTransactionId)->send();
} catch (GuzzleException $exception) {
$this->logger->orderError($payment->getOrder(), 'cancel', $exception->getMessage());
throw new RuntimeException(__($exception->getMessage()));
}
return $this;
}
/**
* @param InfoInterface $payment
* @param float $amount
*
* @return $this
* @throws Exception
*/
public function refund(InfoInterface $payment, $amount): self
{
$paymentTransactionId = str_replace('-refund', '', $payment->getTransactionId());
$paymentTransactionId = str_replace('-capture', '', $paymentTransactionId);
try {
$this->refund
->setInformation($paymentTransactionId, $amount)
->send();
} catch (GuzzleException $exception) {
$this->logger->orderError($payment->getOrder(), 'refund', $exception->getMessage());
throw new RuntimeException(__($exception->getMessage()));
}
return $this;
}
/**
* @param InfoInterface $payment
*
* @return $this
* @throws Exception
*/
public function void(InfoInterface $payment): self
{
return $this->cancel($payment);
}
/**
* @param CartInterface|null $quote
*
* @return bool
*/
public function isAvailable(CartInterface $quote = null): bool
{
return parent::isAvailable($quote) &&
$this->availablePaymentMethodsHelper->isAvailable($this->getPaymentMethodCode());
}
/**
* @return string
* @throws LocalizedException
*/
protected function getIntentId(): string
{
return $this->getInfoInstance()->getAdditionalInformation('intent_id');
}
/**
* @return string
*/
protected function getPaymentMethodCode(): string
{
return str_replace(self::PAYMENT_PREFIX, '', $this->getCode());
}
}
<?php
/**
* This file is part of the Airwallex Payments module.
*
* DISCLAIMER
*
* Do not edit or add to this file if you wish to upgrade
* to newer versions in the future.
*
* @copyright Copyright (c) 2021 Magebit, Ltd. (https://magebit.com/)
* @license GNU General Public License ("GPL") v3.0
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Airwallex\Payments\Model\Methods;
use GuzzleHttp\Exception\GuzzleException;
use Magento\Framework\Exception\LocalizedException;
use Magento\Payment\Model\InfoInterface;
class CardMethod extends AbstractMethod
{
public const CODE = 'airwallex_payments_card';
/**
* @param InfoInterface $payment
* @param float $amount
*
* @return $this
* @throws LocalizedException
*/
public function capture(InfoInterface $payment, $amount): self
{
$intentId = $this->getIntentId();
$payment->setTransactionId($intentId);
try {
$this->capture
->setPaymentIntentId($intentId)
->setInformation($amount)
->send();
$this->logger->error(sprintf('Credit Card: Payment Intent %s, Capture information', $intentId));
} catch (GuzzleException $exception) {
$this->logger->orderError($payment->getOrder(), 'capture', $exception->getMessage());
}
return $this;
}
}
<?php
/**
* This file is part of the Airwallex Payments module.
*
* DISCLAIMER
*
* Do not edit or add to this file if you wish to upgrade
* to newer versions in the future.
*
* @copyright Copyright (c) 2021 Magebit, Ltd. (https://magebit.com/)
* @license GNU General Public License ("GPL") v3.0
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Airwallex\Payments\Model\Methods;
use GuzzleHttp\Exception\GuzzleException;
use Magento\Framework\Exception\AlreadyExistsException;
use Magento\Framework\Exception\LocalizedException;
use Magento\Payment\Model\InfoInterface;
use Mobile_Detect;
use Exception;
class RedirectMethod extends AbstractMethod
{
public const DANA_CODE = 'airwallex_payments_dana';
public const ALIPAYCN_CODE = 'airwallex_payments_alipaycn';
public const ALIPAYHK_CODE = 'airwallex_payments_alipayhk';
public const GCASH_CODE = 'airwallex_payments_gcash';
public const KAKAO_CODE = 'airwallex_payments_kakaopay';
public const TOUCH_N_GO_CODE = 'airwallex_payments_tng';
/**
* @param InfoInterface $payment
* @param float $amount
*
* @return $this
* @throws GuzzleException
* @throws AlreadyExistsException
* @throws LocalizedException
*/
public function authorize(InfoInterface $payment, $amount): self
{
parent::authorize($payment, $amount);
$detect = new Mobile_Detect();
try {
$returnUrl = $this->confirm
->setPaymentIntentId($this->getIntentId())
->setInformation($this->getPaymentMethodCode(), $detect->isMobile(), $this->getMobileOS($detect))
->send();
} catch (Exception $exception) {
throw new LocalizedException(__($exception->getMessage()));
}
$this->checkoutHelper->getCheckout()->setAirwallexPaymentsRedirectUrl($returnUrl);
return $this;
}
/**
* @param Mobile_Detect $detect
*
* @return string|null
*/
private function getMobileOS(Mobile_Detect $detect): ?string
{
if (!$detect->isMobile()) {
return null;
}
return $detect->isAndroidOS() ? 'android' : 'ios';
}
}
<?php
/**
* This file is part of the Airwallex Payments module.
*
* DISCLAIMER
*
* Do not edit or add to this file if you wish to upgrade
* to newer versions in the future.
*
* @copyright Copyright (c) 2021 Magebit, Ltd. (https://magebit.com/)
* @license GNU General Public License ("GPL") v3.0
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Airwallex\Payments\Model\Methods;
class WechatMethod extends AbstractMethod
{
public const CODE = 'airwallex_payments_wechat';
}
<?php
/**
* This file is part of the Airwallex Payments module.
*
* DISCLAIMER
*
* Do not edit or add to this file if you wish to upgrade
* to newer versions in the future.
*
* @copyright Copyright (c) 2021 Magebit, Ltd. (https://magebit.com/)
* @license GNU General Public License ("GPL") v3.0
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Airwallex\Payments\Model;
use Airwallex\Payments\Api\Data\PaymentIntentInterface;
use Magento\Framework\DataObject\IdentityInterface;
use Magento\Framework\Model\AbstractModel;
use Airwallex\Payments\Model\ResourceModel\PaymentIntent as ResourcePaymentIntent;
class PaymentIntent extends AbstractModel implements IdentityInterface, PaymentIntentInterface
{
/**
* @return void
*/
public function _construct()
{
$this->_init(ResourcePaymentIntent::class);
}
/**
* @return string[]
*/
public function getIdentities(): array
{
return ['airwallex_payment_intents' . '_' . $this->getId()];
}
/**
* @return string
*/
public function getPaymentIntentId(): string
{
return $this->getData(PaymentIntentInterface::PAYMENT_INTENT_ID_COLUMN);
}
/**
* @return string
*/
public function getOrderIncrementId(): string
{
return $this->getData(PaymentIntentInterface::ORDER_INCREMENT_ID_COLUMN);
}
/**
* @param string $paymentIntentId
*
* @return PaymentIntentInterface
*/
public function setPaymentIntentId(string $paymentIntentId): PaymentIntentInterface
{
return $this->setData(PaymentIntentInterface::PAYMENT_INTENT_ID_COLUMN, $paymentIntentId);
}
/**
* @param string $orderIncrementId
*
* @return PaymentIntentInterface
*/
public function setOrderIncrementId(string $orderIncrementId): PaymentIntentInterface
{
return $this->setData(PaymentIntentInterface::ORDER_INCREMENT_ID_COLUMN, $orderIncrementId);
}
}
<?php
/**
* This file is part of the Airwallex Payments module.
*
* DISCLAIMER
*
* Do not edit or add to this file if you wish to upgrade
* to newer versions in the future.
*
* @copyright Copyright (c) 2021 Magebit, Ltd. (https://magebit.com/)
* @license GNU General Public License ("GPL") v3.0
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Airwallex\Payments\Model;
use Airwallex\Payments\Api\Data\PaymentIntentInterface;
use Airwallex\Payments\Model\ResourceModel\PaymentIntent as PaymentIntentResource;
use Airwallex\Payments\Model\ResourceModel\PaymentIntent\CollectionFactory;
use Magento\Framework\Exception\AlreadyExistsException;
use Magento\Sales\Api\Data\OrderInterface;
class PaymentIntentRepository
{
private const RACE_SLEEP_TIME = 4;
/**
* @var CollectionFactory
*/
private CollectionFactory $collectionFactory;
/**
* @var PaymentIntentFactory
*/
private PaymentIntentFactory $paymentIntentFactory;
/**
* @var PaymentIntentResource
*/
private PaymentIntentResource $paymentIntent;
/**
* @var OrderInterface
*/
private OrderInterface $order;
/**
* PaymentIntentRepository constructor.
*
* @param CollectionFactory $collectionFactory
* @param PaymentIntentFactory $paymentIntentFactory
* @param PaymentIntentResource $paymentIntent
* @param OrderInterface $order
*/
public function __construct(
CollectionFactory $collectionFactory,
PaymentIntentFactory $paymentIntentFactory,
PaymentIntentResource $paymentIntent,
OrderInterface $order
) {
$this->collectionFactory = $collectionFactory;
$this->paymentIntentFactory = $paymentIntentFactory;
$this->paymentIntent = $paymentIntent;
$this->order = $order;
}
/**
* Webhooks Race Condition: Sometimes we may receive the webhook before Magento commits the order to the database,
* so we give it a few seconds and try again. Can happen when multiple subscriptions are purchased together.
* @param string $paymentIntentId
* @param int $count
*
* @return OrderInterface|null
*/
public function loadOrderByPaymentIntent(string $paymentIntentId, int $count = 5): ?OrderInterface
{
$order = $this->getOrder($paymentIntentId);
if ($order === null || (empty($order->getId()) && $count >= 0)) {
// phpcs:ignore Magento2.Functions.DiscouragedFunction
sleep(self::RACE_SLEEP_TIME);
return $this->loadOrderByPaymentIntent($paymentIntentId, $count - 1);
}
return $order;
}
/**
* @param string $paymentIntentId
*
* @return OrderInterface|null
*/
public function getOrder(string $paymentIntentId): ?OrderInterface
{
$intentCollection = $this->collectionFactory->create();
/** @var PaymentIntentInterface|null $intent */
$intent = $intentCollection
->addFieldToFilter('payment_intent_id', ['eq' => $paymentIntentId])
->getFirstItem();
if ($intent->getId() === null) {
return null;
}
$order = $this->order->loadByIncrementId($intent->getOrderIncrementId());
return $order->getId() === null ? null : $order;
}
/**
* @param string $orderIncrement
* @param string $paymentIntentId
*
* @return void
* @throws AlreadyExistsException
*/
public function save(string $orderIncrement, string $paymentIntentId): void
{
$paymentIntent = $this->paymentIntentFactory->create();
$paymentIntent->setPaymentIntentId($paymentIntentId)
->setOrderIncrementId($orderIncrement);
$this->paymentIntent->save($paymentIntent);
}
}
<?php
/**
* This file is part of the Airwallex Payments module.
*
* DISCLAIMER
*
* Do not edit or add to this file if you wish to upgrade
* to newer versions in the future.
*
* @copyright Copyright (c) 2021 Magebit, Ltd. (https://magebit.com/)
* @license GNU General Public License ("GPL") v3.0
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Airwallex\Payments\Model;
use Airwallex\Payments\Logger\Logger;
use Airwallex\Payments\Model\Client\Request\PaymentIntents\Create;
use Airwallex\Payments\Model\Client\Request\PaymentIntents\Cancel;
use Airwallex\Payments\Model\Methods\AbstractMethod;
use GuzzleHttp\Exception\GuzzleException;
use Magento\Checkout\Model\Session;
use Magento\Framework\App\CacheInterface;
use Magento\Framework\Exception\LocalizedException;
use Magento\Framework\Exception\NoSuchEntityException;
use Magento\Framework\Serialize\SerializerInterface;
use Magento\Framework\UrlInterface;
use Magento\Quote\Model\Quote;
use Magento\Quote\Model\QuoteRepository;
/**
* @SuppressWarnings(PHPMD.CookieAndSessionMisuse)
*/
class PaymentIntents
{
private const CACHE_TIME = 60;
/**
* @var Create
*/
private Create $paymentIntentsCreate;
/**
* @var Cancel
*/
private Cancel $paymentIntentsCancel;
/**
* @var Session
*/
private Session $checkoutSession;
/**
* @var CacheInterface
*/
private CacheInterface $cache;
/**
* @var SerializerInterface
*/
private SerializerInterface $serializer;
/**
* @var QuoteRepository
*/
private QuoteRepository $quoteRepository;
/**
* @var Logger
*/
private Logger $logger;
/**
* @var UrlInterface
*/
private UrlInterface $urlInterface;
public function __construct(
Create $paymentIntentsCreate,
Cancel $paymentIntentsCancel,
Session $checkoutSession,
SerializerInterface $serializer,
QuoteRepository $quoteRepository,
CacheInterface $cache,
UrlInterface $urlInterface,
Logger $logger
) {
$this->paymentIntentsCancel = $paymentIntentsCancel;
$this->paymentIntentsCreate = $paymentIntentsCreate;
$this->checkoutSession = $checkoutSession;
$this->cache = $cache;
$this->serializer = $serializer;
$this->quoteRepository = $quoteRepository;
$this->logger = $logger;
$this->urlInterface = $urlInterface;
}
/**
* @return array
* @throws GuzzleException
* @throws LocalizedException
* @throws NoSuchEntityException
*/
public function getIntents(): array
{
$quote = $this->checkoutSession->getQuote();
$cacheKey = $this->getCacheKey($quote);
if ($response = $this->cache->load($cacheKey)) {
return $this->serializer->unserialize($response);
}
$this->saveQuote($quote);
$returnUrl = $this->urlInterface->getUrl('checkout/onepage/success');
try {
$response = $this->paymentIntentsCreate
->setQuote($quote, $returnUrl)
->send();
} catch (GuzzleException $exception) {
$this->logger->quoteError($quote, 'intents', $exception->getMessage());
throw $exception;
}
$this->cache->save(
$this->serializer->serialize($response),
$cacheKey,
AbstractMethod::CACHE_TAGS,
self::CACHE_TIME
);
return $response;
}
/**
* @return void
* @throws LocalizedException
* @throws NoSuchEntityException
*/
public function removeIntents(): void
{
$this->cache->remove($this->getCacheKey($this->checkoutSession->getQuote()));
}
/**
* @param Quote $quote
*
* @return string
*/
private function getCacheKey(Quote $quote): string
{
return 'airwallex-intent-' . $quote->getId();
}
/**
* @param Quote $quote
*
* @return void
*/
private function saveQuote(Quote $quote): void
{
if (!$quote->getReservedOrderId()) {
$quote->reserveOrderId();
$this->quoteRepository->save($quote);
}
}
/**
* @param string $intentId
* @return mixed
* @throws GuzzleException
* @throws LocalizedException
* @throws NoSuchEntityException
* @throws \JsonException
*/
public function cancelIntent(string $intentId) {
try {
$response = $this->paymentIntentsCancel
->setPaymentIntentId($intentId)
->send();
} catch (GuzzleException $exception) {
$quote = $this->checkoutSession->getQuote();
$this->logger->quoteError($quote, 'intents', $exception->getMessage());
throw $exception;
}
$this->removeIntents();
return $response;
}
}
<?php
/**
* This file is part of the Airwallex Payments module.
*
* DISCLAIMER
*
* Do not edit or add to this file if you wish to upgrade
* to newer versions in the future.
*
* @copyright Copyright (c) 2021 Magebit, Ltd. (https://magebit.com/)
* @license GNU General Public License ("GPL") v3.0
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Airwallex\Payments\Model\ResourceModel;
use Airwallex\Payments\Api\Data\PaymentIntentInterface;
use Magento\Framework\Model\ResourceModel\Db\AbstractDb;
class PaymentIntent extends AbstractDb
{
/**
* @return void
*/
protected function _construct()
{
$this->_init(PaymentIntentInterface::TABLE, PaymentIntentInterface::ID_COLUMN);
}
}
<?php
/**
* This file is part of the Airwallex Payments module.
*
* DISCLAIMER
*
* Do not edit or add to this file if you wish to upgrade
* to newer versions in the future.
*
* @copyright Copyright (c) 2021 Magebit, Ltd. (https://magebit.com/)
* @license GNU General Public License ("GPL") v3.0
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Airwallex\Payments\Model\ResourceModel\PaymentIntent;
use Airwallex\Payments\Model\PaymentIntent;
use Airwallex\Payments\Model\ResourceModel\PaymentIntent as ResourcePaymentIntent;
use Magento\Framework\Model\ResourceModel\Db\Collection\AbstractCollection;
class Collection extends AbstractCollection
{
/**
* @return void
*/
protected function _construct()
{
$this->_init(PaymentIntent::class, ResourcePaymentIntent::class);
}
}
<?php
/**
* This file is part of the Airwallex Payments module.
*
* DISCLAIMER
*
* Do not edit or add to this file if you wish to upgrade
* to newer versions in the future.
*
* @copyright Copyright (c) 2021 Magebit, Ltd. (https://magebit.com/)
* @license GNU General Public License ("GPL") v3.0
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Airwallex\Payments\Model;
use Airwallex\Payments\Api\ServiceInterface;
use Airwallex\Payments\Helper\Configuration;
use Airwallex\Payments\Model\Methods\CardMethod;
use GuzzleHttp\Exception\GuzzleException;
use Magento\Checkout\Helper\Data as CheckoutData;
use Magento\Framework\Exception\LocalizedException;
use Magento\Framework\Exception\NoSuchEntityException;
use Magento\Payment\Model\MethodInterface;
use Zend_Json;
class Service implements ServiceInterface
{
/**
* @var PaymentIntents
*/
private PaymentIntents $paymentIntents;
/**
* @var Configuration
*/
private Configuration $configuration;
/**
* @var CheckoutData
*/
private CheckoutData $checkoutHelper;
/**
* Index constructor.
*
* @param PaymentIntents $paymentIntents
* @param Configuration $configuration
* @param CheckoutData $checkoutHelper
*/
public function __construct(
PaymentIntents $paymentIntents,
Configuration $configuration,
CheckoutData $checkoutHelper
) {
$this->paymentIntents = $paymentIntents;
$this->configuration = $configuration;
$this->checkoutHelper = $checkoutHelper;
}
/**
* @param string $method
*
* @return string
* @throws GuzzleException
* @throws LocalizedException
* @throws NoSuchEntityException
*/
public function createIntent(string $method): string
{
$response = $this->paymentIntents->getIntents();
$response['mode'] = $this->configuration->getMode();
$response = array_merge($response, $this->getExtraConfiguration($method));
return Zend_Json::encode($response);
}
/**
* Return URL
*
* @return string
* @throws LocalizedException
*/
public function redirectUrl(): string
{
$checkout = $this->checkoutHelper->getCheckout();
if (empty($checkout->getLastRealOrderId())) {
throw new LocalizedException(__("Sorry, the order could not be placed. Please contact us for more help."));
}
return $checkout->getAirwallexPaymentsRedirectUrl();
}
/**
* @param string $method
*
* @return array
*/
private function getExtraConfiguration(string $method): array
{
$data = [];
if ($method === CardMethod::CODE) {
$paymentAction = $this->configuration->getCardPaymentAction();
$data['card']['auto_capture'] = $paymentAction === MethodInterface::ACTION_AUTHORIZE_CAPTURE;
}
return $data;
}
/**
* @param string $intentId
* @param string $method
* @return string
* @throws GuzzleException
* @throws LocalizedException
* @throws NoSuchEntityException
* @throws \JsonException
*/
public function refreshIntent(string $intentId, string $method): string
{
$this->paymentIntents->cancelIntent($intentId);
return $this->createIntent($method);
}
}
<?php
namespace Airwallex\Payments\Model\Ui;
use Airwallex\Payments\Helper\Configuration;
use \Magento\Checkout\Model\ConfigProviderInterface;
class ConfigProvider implements ConfigProviderInterface
{
/**
* @var Configuration
*/
protected $configuration;
/**
* ConfigProvider constructor.
* @param Configuration $configuration
*/
public function __construct(
Configuration $configuration
) {
$this->configuration = $configuration;
}
/**
* Adds mode to checkout config array
*
* @return \array[][]
*/
public function getConfig()
{
$config = [
'payment' => [
'airwallex_payments' => [
'mode' => $this->configuration->getMode(),
'cc_auto_capture' => $this->configuration->isCaptureEnabled()
]
]
];
return $config;
}
}
<?php
/**
* This file is part of the Airwallex Payments module.
*
* DISCLAIMER
*
* Do not edit or add to this file if you wish to upgrade
* to newer versions in the future.
*
* @copyright Copyright (c) 2021 Magebit, Ltd. (https://magebit.com/)
* @license GNU General Public License ("GPL") v3.0
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Airwallex\Payments\Model\Webhook;
use Airwallex\Payments\Model\PaymentIntentRepository;
use Magento\Sales\Model\OrderRepository;
abstract class AbstractWebhook
{
/**
* @var OrderRepository
*/
protected OrderRepository $orderRepository;
/**
* @var PaymentIntentRepository
*/
protected PaymentIntentRepository $paymentIntentRepository;
/**
* AbstractWebhook constructor.
*
* @param OrderRepository $orderRepository
* @param PaymentIntentRepository $paymentIntentRepository
*/
public function __construct(
OrderRepository $orderRepository,
PaymentIntentRepository $paymentIntentRepository
) {
$this->orderRepository = $orderRepository;
$this->paymentIntentRepository = $paymentIntentRepository;
}
/**
* @param object $data
*
* @return void
*/
abstract public function execute(object $data): void;
}
<?php
/**
* This file is part of the Airwallex Payments module.
*
* DISCLAIMER
*
* Do not edit or add to this file if you wish to upgrade
* to newer versions in the future.
*
* @copyright Copyright (c) 2021 Magebit, Ltd. (https://magebit.com/)
* @license GNU General Public License ("GPL") v3.0
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Airwallex\Payments\Model\Webhook;
use Airwallex\Payments\Exception\WebhookException;
use Airwallex\Payments\Helper\CancelHelper;
use Airwallex\Payments\Model\PaymentIntentRepository;
use Magento\Framework\Exception\AlreadyExistsException;
use Magento\Framework\Exception\InputException;
use Magento\Framework\Exception\LocalizedException;
use Magento\Framework\Exception\NoSuchEntityException;
use Magento\Sales\Model\OrderRepository;
class Cancel extends AbstractWebhook
{
public const WEBHOOK_NAME = 'payment_attempt.cancelled';
/**
* @var CancelHelper
*/
private CancelHelper $cancelHelper;
/**
* Cancel constructor.
*
* @param OrderRepository $orderRepository
* @param PaymentIntentRepository $paymentIntentRepository
* @param CancelHelper $cancelHelper
*/
public function __construct(
OrderRepository $orderRepository,
PaymentIntentRepository $paymentIntentRepository,
CancelHelper $cancelHelper
) {
parent::__construct($orderRepository, $paymentIntentRepository);
$this->cancelHelper = $cancelHelper;
}
/**
* @param object $data
*
* @return void
* @throws AlreadyExistsException
* @throws InputException
* @throws LocalizedException
* @throws NoSuchEntityException
* @throws WebhookException
*/
public function execute(object $data): void
{
$paymentIntent = $data->payment_intent_id;
$order = $this->paymentIntentRepository->getOrder($paymentIntent);
if ($order === null) {
throw new WebhookException(__('Can\'t find order %s', $paymentIntent));
}
if (!$order->canCancel()) {
throw new WebhookException(__('Can\'t cancel order %s', $paymentIntent));
}
$this->cancelHelper->setWebhookCanceling(true);
$order->cancel();
$this->orderRepository->save($order);
}
}
<?php
/**
* This file is part of the Airwallex Payments module.
*
* DISCLAIMER
*
* Do not edit or add to this file if you wish to upgrade
* to newer versions in the future.
*
* @copyright Copyright (c) 2021 Magebit, Ltd. (https://magebit.com/)
* @license GNU General Public License ("GPL") v3.0
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Airwallex\Payments\Model\Webhook;
use Airwallex\Payments\Exception\WebhookException;
use Airwallex\Payments\Model\PaymentIntentRepository;
use Magento\Framework\DB\TransactionFactory;
use Magento\Framework\Exception\LocalizedException;
use Magento\Sales\Model\Order\Invoice;
use Magento\Sales\Model\OrderRepository;
use Magento\Sales\Model\Service\InvoiceService;
class Capture extends AbstractWebhook
{
public const WEBHOOK_NAME = 'payment_attempt.capture_requested';
/**
* @var InvoiceService
*/
private InvoiceService $invoiceService;
/**
* @var TransactionFactory
*/
private TransactionFactory $transactionFactory;
/**
* Capture constructor.
*
* @param OrderRepository $orderRepository
* @param PaymentIntentRepository $paymentIntentRepository
* @param InvoiceService $invoiceService
* @param TransactionFactory $transactionFactory
*/
public function __construct(
OrderRepository $orderRepository,
PaymentIntentRepository $paymentIntentRepository,
InvoiceService $invoiceService,
TransactionFactory $transactionFactory
) {
parent::__construct($orderRepository, $paymentIntentRepository);
$this->invoiceService = $invoiceService;
$this->transactionFactory = $transactionFactory;
}
/**
* @param object $data
*
* @return void
* @throws LocalizedException
*/
public function execute(object $data): void
{
$order = $this->paymentIntentRepository->loadOrderByPaymentIntent($data->payment_intent_id);
if ($order === null) {
throw new WebhookException(__('Payment Intent: ' . $data->payment_intent_id . ': Can\'t find Order'));
}
$paid = $order->getBaseGrandTotal() - $order->getBaseTotalPaid();
if ($paid === 0.0) {
return;
}
$amount = $data->captured_amount;
$invoice = $this->invoiceService->prepareInvoice($order);
$invoice->setSubtotal($amount);
$invoice->setBaseSubtotal($amount);
$invoice->setGrandTotal($amount);
$invoice->setTransactionId($data->payment_intent_id);
$invoice->setBaseGrandTotal($amount);
$invoice->setRequestedCaptureCase(Invoice::CAPTURE_OFFLINE);
$invoice->register();
$invoice->getOrder()->setCustomerNoteNotify(false);
$invoice->getOrder()->setIsInProcess(true);
$transactionSave = $this->transactionFactory->create()
->addObject($invoice)
->addObject($invoice->getOrder());
$transactionSave->save();
}
}
<?php
/**
* This file is part of the Airwallex Payments module.
*
* DISCLAIMER
*
* Do not edit or add to this file if you wish to upgrade
* to newer versions in the future.
*
* @copyright Copyright (c) 2021 Magebit, Ltd. (https://magebit.com/)
* @license GNU General Public License ("GPL") v3.0
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Airwallex\Payments\Model\Webhook;
use Airwallex\Payments\Exception\WebhookException;
use Airwallex\Payments\Model\PaymentIntentRepository;
use Magento\Framework\Exception\AlreadyExistsException;
use Magento\Framework\Exception\InputException;
use Magento\Framework\Exception\LocalizedException;
use Magento\Framework\Exception\NoSuchEntityException;
use Magento\Sales\Model\Order;
use Magento\Sales\Model\Order\CreditmemoFactory;
use Magento\Sales\Model\OrderRepository;
use Magento\Sales\Model\Service\CreditmemoService;
class Refund extends AbstractWebhook
{
public const WEBHOOK_ACCEPTED_NAME = 'refund.accepted';
public const WEBHOOK_SUCCESS_NAME = 'refund.succeeded';
/**
* @var CreditmemoFactory
*/
private CreditmemoFactory $creditmemoFactory;
/**
* @var CreditmemoService
*/
private CreditmemoService $creditmemoService;
/**
* Refund constructor.
*
* @param OrderRepository $orderRepository
* @param PaymentIntentRepository $paymentIntentRepository
* @param CreditmemoFactory $creditmemoFactory
* @param CreditmemoService $creditmemoService
*/
public function __construct(
OrderRepository $orderRepository,
PaymentIntentRepository $paymentIntentRepository,
CreditmemoFactory $creditmemoFactory,
CreditmemoService $creditmemoService
) {
parent::__construct($orderRepository, $paymentIntentRepository);
$this->creditmemoFactory = $creditmemoFactory;
$this->creditmemoService = $creditmemoService;
}
/**
* @param object $data
*
* @return void
* @throws AlreadyExistsException
* @throws InputException
* @throws LocalizedException
* @throws NoSuchEntityException
* @throws WebhookException
*/
public function execute(object $data): void
{
$order = $this->paymentIntentRepository->getOrder($data->payment_intent_id);
if ($order === null) {
throw new WebhookException(__('Can\'t find order'));
}
if ($order->getState() === Order::STATE_HOLDED && $order->canUnhold()) {
$order->unhold();
}
if (!$order->canCreditmemo()) {
if ($order->canCancel()) {
$order->cancel();
$this->orderRepository->save($order);
}
return;
}
$this->createCreditMemo($order, $data->amount, $data->reason);
}
/**
* @param Order $order
* @param float $refundAmount
* @param string $reason
*
* @return void
* @throws LocalizedException
*/
private function createCreditMemo(Order $order, float $refundAmount, string $reason): void
{
$invoice = $order->getInvoiceCollection()->getFirstItem();
if ($invoice === null) {
return;
}
$baseToOrderRate = $order->getBaseToOrderRate();
$baseTotalNotRefunded = $order->getBaseGrandTotal() - $order->getBaseTotalRefunded();
$creditMemo = $this->creditmemoFactory->createByOrder($order);
$creditMemo->setInvoice($invoice);
if ($baseTotalNotRefunded > $refundAmount) {
$baseDiff = $baseTotalNotRefunded - $refundAmount;
$creditMemo->setAdjustmentPositive($baseDiff);
}
$creditMemo->setBaseGrandTotal($refundAmount);
$creditMemo->setGrandTotal($refundAmount * $baseToOrderRate);
$this->creditmemoService->refund($creditMemo, true);
$order->addCommentToStatusHistory(__('Order refunded through Airwallex, Reason: %1', $reason));
}
}
<?php
/**
* This file is part of the Airwallex Payments module.
*
* DISCLAIMER
*
* Do not edit or add to this file if you wish to upgrade
* to newer versions in the future.
*
* @copyright Copyright (c) 2021 Magebit, Ltd. (https://magebit.com/)
* @license GNU General Public License ("GPL") v3.0
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Airwallex\Payments\Model\Webhook;
use Airwallex\Payments\Exception\WebhookException;
use Airwallex\Payments\Helper\Configuration;
use Magento\Framework\App\Request\Http;
use Magento\Framework\Exception\AlreadyExistsException;
use Magento\Framework\Exception\InputException;
use Magento\Framework\Exception\LocalizedException;
use Magento\Framework\Exception\NoSuchEntityException;
use stdClass;
class Webhook
{
private const HASH_ALGORITHM = 'sha256';
/**
* @var Refund
*/
private Refund $refund;
/**
* @var Configuration
*/
private Configuration $configuration;
/**
* @var Capture
*/
private Capture $capture;
/**
* @var Cancel
*/
private Cancel $cancel;
/**
* Webhook constructor.
*
* @param Configuration $configuration
* @param Refund $refund
* @param Capture $capture
* @param Cancel $cancel
*/
public function __construct(Configuration $configuration, Refund $refund, Capture $capture, Cancel $cancel)
{
$this->refund = $refund;
$this->configuration = $configuration;
$this->capture = $capture;
$this->cancel = $cancel;
}
/**
* @param Http $request
*
* @return void
* @throws WebhookException
*/
public function checkChecksum(Http $request): void
{
$signature = $request->getHeader('x-signature');
$data = $request->getHeader('x-timestamp') . $request->getContent();
if (hash_hmac(self::HASH_ALGORITHM, $data, $this->configuration->getWebhookSecretKey()) !== $signature) {
throw new WebhookException(__('failed to verify the signature'));
}
}
/**
* @param string $type
* @param stdClass $data
*
* @return void
* @throws AlreadyExistsException
* @throws InputException
* @throws LocalizedException
* @throws NoSuchEntityException
* @throws WebhookException
*/
public function dispatch(string $type, stdClass $data): void
{
if (in_array($type, [Refund::WEBHOOK_ACCEPTED_NAME, Refund::WEBHOOK_SUCCESS_NAME], true)) {
$this->refund->execute($data);
}
if ($type === Capture::WEBHOOK_NAME) {
$this->capture->execute($data);
}
if ($type === Cancel::WEBHOOK_NAME) {
$this->cancel->execute($data);
}
}
}
<?php
/**
* This file is part of the Airwallex Payments module.
*
* DISCLAIMER
*
* Do not edit or add to this file if you wish to upgrade
* to newer versions in the future.
*
* @copyright Copyright (c) 2021 Magebit, Ltd. (https://magebit.com/)
* @license GNU General Public License ("GPL") v3.0
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Airwallex\Payments\Observer;
use Airwallex\Payments\Model\PaymentIntents;
use Magento\Framework\Event\Observer;
use Magento\Framework\Event\ObserverInterface;
use Magento\Framework\Exception\LocalizedException;
use Magento\Framework\Exception\NoSuchEntityException;
class ClearSavedIntent implements ObserverInterface
{
/**
* @var PaymentIntents
*/
private PaymentIntents $paymentIntents;
/**
* ClearSavedIntent constructor.
*
* @param PaymentIntents $paymentIntents
*/
public function __construct(PaymentIntents $paymentIntents)
{
$this->paymentIntents = $paymentIntents;
}
/**
* @param Observer $observer
*
* @return void
* @throws LocalizedException
* @throws NoSuchEntityException
* @SuppressWarnings(PHPMD.UnusedFormalParameter)
*/
public function execute(Observer $observer): void
{
$this->paymentIntents->removeIntents();
}
}
<?php
/**
* This file is part of the Airwallex Payments module.
*
* DISCLAIMER
*
* Do not edit or add to this file if you wish to upgrade
* to newer versions in the future.
*
* @copyright Copyright (c) 2021 Magebit, Ltd. (https://magebit.com/)
* @license GNU General Public License ("GPL") v3.0
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Airwallex\Payments\Plugin;
use Airwallex\Payments\Model\Methods\AbstractMethod;
use Magento\Payment\Block\Form\Container;
use Magento\Payment\Model\MethodInterface;
class RemoveMethodsFromAdminReorder
{
/**
* @param Container $subject
* @param array $results
*
* @return array
* @SuppressWarnings(PHPMD.UnusedFormalParameter)
*/
public function afterGetMethods(Container $subject, array $results): array
{
$results = array_filter($results, static function (MethodInterface $method) {
return strpos($method->getCode(), AbstractMethod::PAYMENT_PREFIX) === false;
});
return array_values($results);
}
}
<?php
/**
* This file is part of the Airwallex Payments module.
*
* DISCLAIMER
*
* Do not edit or add to this file if you wish to upgrade
* to newer versions in the future.
*
* @copyright Copyright (c) 2021 Magebit, Ltd. (https://magebit.com/)
* @license GNU General Public License ("GPL") v3.0
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Airwallex\Payments\Plugin;
use Airwallex\Payments\Model\PaymentIntents;
use Magento\Framework\Exception\LocalizedException;
use Magento\Framework\Exception\NoSuchEntityException;
class StorePlugin
{
/**
* @var PaymentIntents
*/
private PaymentIntents $paymentIntents;
/**
* ClearSavedIntent constructor.
*
* @param PaymentIntents $paymentIntents
*/
public function __construct(PaymentIntents $paymentIntents)
{
$this->paymentIntents = $paymentIntents;
}
/**
* @return void
* @throws LocalizedException
* @throws NoSuchEntityException
*/
public function afterSetCurrentCurrencyCode(): void
{
$this->paymentIntents->removeIntents();
}
}
{
"name": "airwallex/payments-plugin-magento",
"type": "magento2-module",
"description": "",
"version": "1.2.2",
"require": {
"ext-json": "*",
"mobiledetect/mobiledetectlib": "^2.8"
},
"autoload": {
"files": [ "registration.php" ],
"psr-4": {
"Airwallex\\Payments\\": ""
}
}
}
<?xml version="1.0"?>
<!--
/**
* This file is part of the Airwallex Payments module.
*
* DISCLAIMER
*
* Do not edit or add to this file if you wish to upgrade
* to newer versions in the future.
*
* @copyright Copyright (c) 2021 Magebit, Ltd. (https://magebit.com/)
* @license GNU General Public License ("GPL") v3.0
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
-->
<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:ObjectManager/etc/config.xsd">
<type name="Magento\Config\Model\Config\TypePool">
<arguments>
<argument name="sensitive" xsi:type="array">
<item name="airwallex/general/demo_api_key" xsi:type="string">1</item>
<item name="airwallex/general/prod_api_key" xsi:type="string">1</item>
<item name="airwallex/general/webhook_prod_secret_key" xsi:type="string">1</item>
<item name="airwallex/general/webhook_demo_secret_key" xsi:type="string">1</item>
</argument>
</arguments>
</type>
<type name="Magento\Framework\Notification\MessageList">
<arguments>
<argument name="messages" xsi:type="array">
<item name="AirwallexDependenciesNotification" xsi:type="string">Airwallex\Payments\Model\Adminhtml\Notifications\Dependencies</item>
</argument>
</arguments>
</type>
</config>
<?xml version="1.0"?>
<!--
/**
* This file is part of the Airwallex Payments module.
*
* DISCLAIMER
*
* Do not edit or add to this file if you wish to upgrade
* to newer versions in the future.
*
* @copyright Copyright (c) 2021 Magebit, Ltd. (https://magebit.com/)
* @license GNU General Public License ("GPL") v3.0
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
-->
<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:module:Magento_Config:etc/system_file.xsd">
<system>
<section id="payment">
<group id="airwallex_payments" translate="label comment" type="text" sortOrder="10" showInDefault="1" showInWebsite="1" showInStore="1">
<label>Airwallex</label>
<comment>Airwallex provides you with the payment methods your customers trust and choose, from international cards to popular local payment methods</comment>
<fieldset_css>complex airwallex-admin-config</fieldset_css>
<frontend_model>Airwallex\Payments\Block\Adminhtml\Config\Fieldset</frontend_model>
<attribute type="displayIn">recommended_solutions</attribute>
<include path="Airwallex_Payments::system/basic.xml"/>
<include path="Airwallex_Payments::system/card.xml"/>
<include path="Airwallex_Payments::system/wechat.xml"/>
<include path="Airwallex_Payments::system/redirect.xml"/>
</group>
</section>
</system>
</config>
<?xml version="1.0"?>
<!--
/**
* This file is part of the Airwallex Payments module.
*
* DISCLAIMER
*
* Do not edit or add to this file if you wish to upgrade
* to newer versions in the future.
*
* @copyright Copyright (c) 2021 Magebit, Ltd. (https://magebit.com/)
* @license GNU General Public License ("GPL") v3.0
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
-->
<include xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:module:Magento_Config:etc/system_include.xsd">
<group id="basic" translate="label" type="text" sortOrder="1" showInDefault="1" showInWebsite="0" showInStore="0">
<label>Basic Settings</label>
<field id="mode" translate="label" type="select" sortOrder="10" showInDefault="1" showInWebsite="1" canRestore="1">
<label>Mode</label>
<source_model>Airwallex\Payments\Model\Config\Source\Mode</source_model>
<config_path>airwallex/general/mode</config_path>
</field>
<field id="demo_client_id" translate="label" type="text" sortOrder="20" showInDefault="1" showInWebsite="1" showInStore="1">
<label>Demo Client ID</label>
<config_path>airwallex/general/demo_client_id</config_path>
<depends>
<field id="mode">demo</field>
</depends>
</field>
<field id="demo_api_key" translate="label" type="obscure" sortOrder="30" showInDefault="1" showInWebsite="1" showInStore="1">
<label>Demo API Key</label>
<backend_model>Magento\Config\Model\Config\Backend\Encrypted</backend_model>
<config_path>airwallex/general/demo_api_key</config_path>
<depends>
<field id="mode">demo</field>
</depends>
</field>
<field id="webhook_demo_secret_key" translate="label" type="obscure" sortOrder="30" showInDefault="1" showInWebsite="1" showInStore="1">
<label>Webhook Demo Secret Key</label>
<backend_model>Magento\Config\Model\Config\Backend\Encrypted</backend_model>
<config_path>airwallex/general/webhook_demo_secret_key</config_path>
<depends>
<field id="mode">demo</field>
</depends>
</field>
<field id="prod_client_id" translate="label" type="text" sortOrder="20" showInDefault="1" showInWebsite="1" showInStore="1">
<label>Production Client ID</label>
<config_path>airwallex/general/prod_client_id</config_path>
<depends>
<field id="mode">prod</field>
</depends>
</field>
<field id="prod_api_key" translate="label" type="obscure" sortOrder="30" showInDefault="1" showInWebsite="1" showInStore="1">
<label>Production API Key</label>
<backend_model>Magento\Config\Model\Config\Backend\Encrypted</backend_model>
<config_path>airwallex/general/prod_api_key</config_path>
<depends>
<field id="mode">prod</field>
</depends>
</field>
<field id="webhook_prod_secret_key" translate="label" type="obscure" sortOrder="30" showInDefault="1" showInWebsite="1" showInStore="1">
<label>Webhook Production Secret Key</label>
<backend_model>Magento\Config\Model\Config\Backend\Encrypted</backend_model>
<config_path>airwallex/general/webhook_prod_secret_key</config_path>
<depends>
<field id="mode">prod</field>
</depends>
</field>
<field id="webhook_url" translate="label" sortOrder="30" showInDefault="1" showInWebsite="1" showInStore="0">
<label>Webhook Url</label>
<frontend_model>Airwallex\Payments\Model\Config\Source\WebhookUrl</frontend_model>
</field>
<field id="request_logger" translate="label" type="select" sortOrder="40" showInDefault="1" showInWebsite="1" canRestore="1">
<label>Request Logger</label>
<source_model>Magento\Config\Model\Config\Source\Yesno</source_model>
<config_path>airwallex/general/request_logger</config_path>
</field>
</group>
</include>
<?xml version="1.0"?>
<!--
/**
* This file is part of the Airwallex Payments module.
*
* DISCLAIMER
*
* Do not edit or add to this file if you wish to upgrade
* to newer versions in the future.
*
* @copyright Copyright (c) 2021 Magebit, Ltd. (https://magebit.com/)
* @license GNU General Public License ("GPL") v3.0
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
-->
<include xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:module:Magento_Config:etc/system_include.xsd">
<group id="card" translate="label" type="text" sortOrder="1" showInDefault="1" showInWebsite="1" showInStore="1">
<label>Credit Card</label>
<field id="active" translate="label" type="select" sortOrder="1" showInDefault="1" showInWebsite="1" canRestore="1">
<label>Enable</label>
<source_model>Magento\Config\Model\Config\Source\Yesno</source_model>
<config_path>payment/airwallex_payments_card/active</config_path>
</field>
<field id="title" translate="label comment" type="text" sortOrder="40" showInDefault="1" showInWebsite="1" showInStore="1">
<label>Title</label>
<comment><![CDATA[This is the payment method title used at the checkout page]]></comment>
<config_path>payment/airwallex_payments_card/title</config_path>
</field>
<field id="airwallex_payment_action" translate="label" type="select" sortOrder="30" showInDefault="1" showInWebsite="0" showInStore="0">
<label>Payment Action</label>
<source_model>Airwallex\Payments\Model\Config\Source\PaymentAction</source_model>
<config_path>payment/airwallex_payments_card/airwallex_payment_action</config_path>
</field>
<field id="allowspecific" translate="label" type="allowspecific" sortOrder="50" showInDefault="1" showInWebsite="1" showInStore="1">
<label>Payment From Applicable Countries</label>
<source_model>Magento\Payment\Model\Config\Source\Allspecificcountries</source_model>
<config_path>payment/airwallex_payments_card/allowspecific</config_path>
</field>
<field id="specificcountry" translate="label comment" type="multiselect" sortOrder="60" showInDefault="1" showInWebsite="1" showInStore="1">
<label>Display Payment Method For</label>
<comment><![CDATA[Select the countries and currencies for which Airwallex is available at the checkout.]]></comment>
<source_model>Magento\Directory\Model\Config\Source\Country</source_model>
<config_path>payment/airwallex_payments_card/specificcountry</config_path>
<depends>
<field id="allowspecific">1</field>
</depends>
</field>
<field id="sort_order" translate="label" type="text" sortOrder="210" showInDefault="1" showInWebsite="1" showInStore="1">
<label>Sort Order</label>
<comment>Adjust this to move the payment method above or below other payment methods</comment>
<frontend_class>validate-number</frontend_class>
<config_path>payment/airwallex_payments_card/sort_order</config_path>
</field>
</group>
</include>
<?xml version="1.0"?>
<include xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:module:Magento_Config:etc/system_include.xsd">
<group id="redirect" translate="label" type="text" sortOrder="16" showInDefault="1" showInWebsite="1" showInStore="1">
<label>Other Payment Methods</label>
<include path="Airwallex_Payments::system/redirect/alipaycn.xml"/>
<include path="Airwallex_Payments::system/redirect/alipayhk.xml"/>
<include path="Airwallex_Payments::system/redirect/dana.xml"/>
<include path="Airwallex_Payments::system/redirect/gcash.xml"/>
<include path="Airwallex_Payments::system/redirect/kakao.xml"/>
<include path="Airwallex_Payments::system/redirect/touch_n_go.xml"/>
</group>
</include>
<?xml version="1.0"?>
<!--
/**
* This file is part of the Airwallex Payments module.
*
* DISCLAIMER
*
* Do not edit or add to this file if you wish to upgrade
* to newer versions in the future.
*
* @copyright Copyright (c) 2021 Magebit, Ltd. (https://magebit.com/)
* @license GNU General Public License ("GPL") v3.0
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
-->
<include xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:module:Magento_Config:etc/system_include.xsd">
<group id="alipay_cn" translate="label" type="text" sortOrder="1" showInDefault="1" showInWebsite="1" showInStore="1">
<label>Alipay CN</label>
<field id="active" translate="label" type="select" sortOrder="1" showInDefault="1" showInWebsite="1" canRestore="1">
<label>Enable</label>
<source_model>Magento\Config\Model\Config\Source\Yesno</source_model>
<config_path>payment/airwallex_payments_alipaycn/active</config_path>
</field>
<field id="title" translate="label comment" type="text" sortOrder="40" showInDefault="1" showInWebsite="1" showInStore="1">
<label>Title</label>
<comment><![CDATA[This is the payment method title used at the checkout page]]></comment>
<config_path>payment/airwallex_payments_alipaycn/title</config_path>
</field>
<field id="allowspecific" translate="label" type="allowspecific" sortOrder="50" showInDefault="1" showInWebsite="1" showInStore="1">
<label>Payment From Applicable Countries</label>
<source_model>Magento\Payment\Model\Config\Source\Allspecificcountries</source_model>
<config_path>payment/airwallex_payments_alipaycn/allowspecific</config_path>
</field>
<field id="specificcountry" translate="label comment" type="multiselect" sortOrder="60" showInDefault="1" showInWebsite="1" showInStore="1">
<label>Display Payment Method For</label>
<comment><![CDATA[Select the countries and currencies for which Airwallex is available at the checkout.]]></comment>
<source_model>Magento\Directory\Model\Config\Source\Country</source_model>
<config_path>payment/airwallex_payments_alipaycn/specificcountry</config_path>
<depends>
<field id="allowspecific">1</field>
</depends>
</field>
<field id="sort_order" translate="label" type="text" sortOrder="210" showInDefault="1" showInWebsite="1" showInStore="1">
<label>Sort Order</label>
<comment>Adjust this to move the payment method above or below other payment methods</comment>
<frontend_class>validate-number</frontend_class>
<config_path>payment/airwallex_payments_alipaycn/sort_order</config_path>
</field>
</group>
</include>
<?xml version="1.0"?>
<!--
/**
* This file is part of the Airwallex Payments module.
*
* DISCLAIMER
*
* Do not edit or add to this file if you wish to upgrade
* to newer versions in the future.
*
* @copyright Copyright (c) 2021 Magebit, Ltd. (https://magebit.com/)
* @license GNU General Public License ("GPL") v3.0
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
-->
<include xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:module:Magento_Config:etc/system_include.xsd">
<group id="alipay_hk" translate="label" type="text" sortOrder="1" showInDefault="1" showInWebsite="1" showInStore="1">
<label>Alipay HK</label>
<field id="active" translate="label" type="select" sortOrder="1" showInDefault="1" showInWebsite="1" canRestore="1">
<label>Enable</label>
<source_model>Magento\Config\Model\Config\Source\Yesno</source_model>
<config_path>payment/airwallex_payments_alipayhk/active</config_path>
</field>
<field id="title" translate="label comment" type="text" sortOrder="40" showInDefault="1" showInWebsite="1" showInStore="1">
<label>Title</label>
<comment><![CDATA[This is the payment method title used at the checkout page]]></comment>
<config_path>payment/airwallex_payments_alipayhk/title</config_path>
</field>
<field id="allowspecific" translate="label" type="allowspecific" sortOrder="50" showInDefault="1" showInWebsite="1" showInStore="1">
<label>Payment From Applicable Countries</label>
<source_model>Magento\Payment\Model\Config\Source\Allspecificcountries</source_model>
<config_path>payment/airwallex_payments_alipayhk/allowspecific</config_path>
</field>
<field id="specificcountry" translate="label comment" type="multiselect" sortOrder="60" showInDefault="1" showInWebsite="1" showInStore="1">
<label>Display Payment Method For</label>
<comment><![CDATA[Select the countries and currencies for which Airwallex is available at the checkout.]]></comment>
<source_model>Magento\Directory\Model\Config\Source\Country</source_model>
<config_path>payment/airwallex_payments_alipayhk/specificcountry</config_path>
<depends>
<field id="allowspecific">1</field>
</depends>
</field>
<field id="sort_order" translate="label" type="text" sortOrder="210" showInDefault="1" showInWebsite="1" showInStore="1">
<label>Sort Order</label>
<comment>Adjust this to move the payment method above or below other payment methods</comment>
<frontend_class>validate-number</frontend_class>
<config_path>payment/airwallex_payments_alipayhk/sort_order</config_path>
</field>
</group>
</include>
<?xml version="1.0"?>
<!--
/**
* This file is part of the Airwallex Payments module.
*
* DISCLAIMER
*
* Do not edit or add to this file if you wish to upgrade
* to newer versions in the future.
*
* @copyright Copyright (c) 2021 Magebit, Ltd. (https://magebit.com/)
* @license GNU General Public License ("GPL") v3.0
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
-->
<include xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:module:Magento_Config:etc/system_include.xsd">
<group id="dana" translate="label" type="text" sortOrder="1" showInDefault="1" showInWebsite="1" showInStore="1">
<label>Dana</label>
<field id="active" translate="label" type="select" sortOrder="1" showInDefault="1" showInWebsite="1" canRestore="1">
<label>Enable</label>
<source_model>Magento\Config\Model\Config\Source\Yesno</source_model>
<config_path>payment/airwallex_payments_dana/active</config_path>
</field>
<field id="title" translate="label comment" type="text" sortOrder="40" showInDefault="1" showInWebsite="1" showInStore="1">
<label>Title</label>
<comment><![CDATA[This is the payment method title used at the checkout page]]></comment>
<config_path>payment/airwallex_payments_dana/title</config_path>
</field>
<field id="allowspecific" translate="label" type="allowspecific" sortOrder="50" showInDefault="1" showInWebsite="1" showInStore="1">
<label>Payment From Applicable Countries</label>
<source_model>Magento\Payment\Model\Config\Source\Allspecificcountries</source_model>
<config_path>payment/airwallex_payments_dana/allowspecific</config_path>
</field>
<field id="specificcountry" translate="label comment" type="multiselect" sortOrder="60" showInDefault="1" showInWebsite="1" showInStore="1">
<label>Display Payment Method For</label>
<comment><![CDATA[Select the countries and currencies for which Airwallex is available at the checkout.]]></comment>
<source_model>Magento\Directory\Model\Config\Source\Country</source_model>
<config_path>payment/airwallex_payments_dana/specificcountry</config_path>
<depends>
<field id="allowspecific">1</field>
</depends>
</field>
<field id="sort_order" translate="label" type="text" sortOrder="210" showInDefault="1" showInWebsite="1" showInStore="1">
<label>Sort Order</label>
<comment>Adjust this to move the payment method above or below other payment methods</comment>
<frontend_class>validate-number</frontend_class>
<config_path>payment/airwallex_payments_dana/sort_order</config_path>
</field>
</group>
</include>
<?xml version="1.0"?>
<!--
/**
* This file is part of the Airwallex Payments module.
*
* DISCLAIMER
*
* Do not edit or add to this file if you wish to upgrade
* to newer versions in the future.
*
* @copyright Copyright (c) 2021 Magebit, Ltd. (https://magebit.com/)
* @license GNU General Public License ("GPL") v3.0
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
-->
<include xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:module:Magento_Config:etc/system_include.xsd">
<group id="gcash" translate="label" type="text" sortOrder="1" showInDefault="1" showInWebsite="1" showInStore="1">
<label>GCash</label>
<field id="active" translate="label" type="select" sortOrder="1" showInDefault="1" showInWebsite="1" canRestore="1">
<label>Enable</label>
<source_model>Magento\Config\Model\Config\Source\Yesno</source_model>
<config_path>payment/airwallex_payments_gcash/active</config_path>
</field>
<field id="title" translate="label comment" type="text" sortOrder="40" showInDefault="1" showInWebsite="1" showInStore="1">
<label>Title</label>
<comment><![CDATA[This is the payment method title used at the checkout page]]></comment>
<config_path>payment/airwallex_payments_gcash/title</config_path>
</field>
<field id="allowspecific" translate="label" type="allowspecific" sortOrder="50" showInDefault="1" showInWebsite="1" showInStore="1">
<label>Payment From Applicable Countries</label>
<source_model>Magento\Payment\Model\Config\Source\Allspecificcountries</source_model>
<config_path>payment/airwallex_payments_gcash/allowspecific</config_path>
</field>
<field id="specificcountry" translate="label comment" type="multiselect" sortOrder="60" showInDefault="1" showInWebsite="1" showInStore="1">
<label>Display Payment Method For</label>
<comment><![CDATA[Select the countries and currencies for which Airwallex is available at the checkout.]]></comment>
<source_model>Magento\Directory\Model\Config\Source\Country</source_model>
<config_path>payment/airwallex_payments_gcash/specificcountry</config_path>
<depends>
<field id="allowspecific">1</field>
</depends>
</field>
<field id="sort_order" translate="label" type="text" sortOrder="210" showInDefault="1" showInWebsite="1" showInStore="1">
<label>Sort Order</label>
<comment>Adjust this to move the payment method above or below other payment methods</comment>
<frontend_class>validate-number</frontend_class>
<config_path>payment/airwallex_payments_gcash/sort_order</config_path>
</field>
</group>
</include>
<?xml version="1.0"?>
<!--
/**
* This file is part of the Airwallex Payments module.
*
* DISCLAIMER
*
* Do not edit or add to this file if you wish to upgrade
* to newer versions in the future.
*
* @copyright Copyright (c) 2021 Magebit, Ltd. (https://magebit.com/)
* @license GNU General Public License ("GPL") v3.0
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
-->
<include xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:module:Magento_Config:etc/system_include.xsd">
<group id="kakao" translate="label" type="text" sortOrder="1" showInDefault="1" showInWebsite="1" showInStore="1">
<label>Kakao Pay</label>
<field id="active" translate="label" type="select" sortOrder="1" showInDefault="1" showInWebsite="1" canRestore="1">
<label>Enable</label>
<source_model>Magento\Config\Model\Config\Source\Yesno</source_model>
<config_path>payment/airwallex_payments_kakaopay/active</config_path>
</field>
<field id="title" translate="label comment" type="text" sortOrder="40" showInDefault="1" showInWebsite="1" showInStore="1">
<label>Title</label>
<comment><![CDATA[This is the payment method title used at the checkout page]]></comment>
<config_path>payment/airwallex_payments_kakaopay/title</config_path>
</field>
<field id="allowspecific" translate="label" type="allowspecific" sortOrder="50" showInDefault="1" showInWebsite="1" showInStore="1">
<label>Payment From Applicable Countries</label>
<source_model>Magento\Payment\Model\Config\Source\Allspecificcountries</source_model>
<config_path>payment/airwallex_payments_kakaopay/allowspecific</config_path>
</field>
<field id="specificcountry" translate="label comment" type="multiselect" sortOrder="60" showInDefault="1" showInWebsite="1" showInStore="1">
<label>Display Payment Method For</label>
<comment><![CDATA[Select the countries and currencies for which Airwallex is available at the checkout.]]></comment>
<source_model>Magento\Directory\Model\Config\Source\Country</source_model>
<config_path>payment/airwallex_payments_kakaoairwallex_payments_kakaopay/specificcountry</config_path>
<depends>
<field id="allowspecific">1</field>
</depends>
</field>
<field id="sort_order" translate="label" type="text" sortOrder="210" showInDefault="1" showInWebsite="1" showInStore="1">
<label>Sort Order</label>
<comment>Adjust this to move the payment method above or below other payment methods</comment>
<frontend_class>validate-number</frontend_class>
<config_path>payment/airwallex_payments_kakaopay/sort_order</config_path>
</field>
</group>
</include>
<?xml version="1.0"?>
<!--
/**
* This file is part of the Airwallex Payments module.
*
* DISCLAIMER
*
* Do not edit or add to this file if you wish to upgrade
* to newer versions in the future.
*
* @copyright Copyright (c) 2021 Magebit, Ltd. (https://magebit.com/)
* @license GNU General Public License ("GPL") v3.0
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
-->
<include xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:module:Magento_Config:etc/system_include.xsd">
<group id="touch_n_go" translate="label" type="text" sortOrder="1" showInDefault="1" showInWebsite="1" showInStore="1">
<label>Touch ‘n Go</label>
<field id="active" translate="label" type="select" sortOrder="1" showInDefault="1" showInWebsite="1" canRestore="1">
<label>Enable</label>
<source_model>Magento\Config\Model\Config\Source\Yesno</source_model>
<config_path>payment/airwallex_payments_tng/active</config_path>
</field>
<field id="title" translate="label comment" type="text" sortOrder="40" showInDefault="1" showInWebsite="1" showInStore="1">
<label>Title</label>
<comment><![CDATA[This is the payment method title used at the checkout page]]></comment>
<config_path>payment/airwallex_payments_tng/title</config_path>
</field>
<field id="allowspecific" translate="label" type="allowspecific" sortOrder="50" showInDefault="1" showInWebsite="1" showInStore="1">
<label>Payment From Applicable Countries</label>
<source_model>Magento\Payment\Model\Config\Source\Allspecificcountries</source_model>
<config_path>payment/airwallex_payments_tng/allowspecific</config_path>
</field>
<field id="specificcountry" translate="label comment" type="multiselect" sortOrder="60" showInDefault="1" showInWebsite="1" showInStore="1">
<label>Display Payment Method For</label>
<comment><![CDATA[Select the countries and currencies for which Airwallex is available at the checkout.]]></comment>
<source_model>Magento\Directory\Model\Config\Source\Country</source_model>
<config_path>payment/airwallex_payments_tng/specificcountry</config_path>
<depends>
<field id="allowspecific">1</field>
</depends>
</field>
<field id="sort_order" translate="label" type="text" sortOrder="210" showInDefault="1" showInWebsite="1" showInStore="1">
<label>Sort Order</label>
<comment>Adjust this to move the payment method above or below other payment methods</comment>
<frontend_class>validate-number</frontend_class>
<config_path>payment/airwallex_payments_tng/sort_order</config_path>
</field>
</group>
</include>
<?xml version="1.0"?>
<!--
/**
* This file is part of the Airwallex Payments module.
*
* DISCLAIMER
*
* Do not edit or add to this file if you wish to upgrade
* to newer versions in the future.
*
* @copyright Copyright (c) 2021 Magebit, Ltd. (https://magebit.com/)
* @license GNU General Public License ("GPL") v3.0
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
-->
<include xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:module:Magento_Config:etc/system_include.xsd">
<group id="wechat" translate="label" type="text" sortOrder="1" showInDefault="1" showInWebsite="1" showInStore="1">
<label>WeChat</label>
<field id="active" translate="label" type="select" sortOrder="1" showInDefault="1" showInWebsite="1" canRestore="1">
<label>Enable</label>
<source_model>Magento\Config\Model\Config\Source\Yesno</source_model>
<config_path>payment/airwallex_payments_wechat/active</config_path>
</field>
<field id="title" translate="label comment" type="text" sortOrder="40" showInDefault="1" showInWebsite="1" showInStore="1">
<label>Title</label>
<comment><![CDATA[This is the payment method title used at the checkout page]]></comment>
<config_path>payment/airwallex_payments_wechat/title</config_path>
</field>
<field id="allowspecific" translate="label" type="allowspecific" sortOrder="50" showInDefault="1" showInWebsite="1" showInStore="1">
<label>Payment From Applicable Countries</label>
<source_model>Magento\Payment\Model\Config\Source\Allspecificcountries</source_model>
<config_path>payment/airwallex_payments_wechat/allowspecific</config_path>
</field>
<field id="specificcountry" translate="label comment" type="multiselect" sortOrder="60" showInDefault="1" showInWebsite="1" showInStore="1">
<label>Display Payment Method For</label>
<comment><![CDATA[Select the countries and currencies for which Airwallex is available at the checkout.]]></comment>
<source_model>Magento\Directory\Model\Config\Source\Country</source_model>
<config_path>payment/airwallex_payments_wechat/specificcountry</config_path>
<depends>
<field id="allowspecific">1</field>
</depends>
</field>
<field id="sort_order" translate="label" type="text" sortOrder="210" showInDefault="1" showInWebsite="1" showInStore="1">
<label>Sort Order</label>
<comment>Adjust this to move the payment method above or below other payment methods</comment>
<frontend_class>validate-number</frontend_class>
<config_path>payment/airwallex_payments_wechat/sort_order</config_path>
</field>
</group>
</include>
<?xml version="1.0"?>
<!--
/**
* This file is part of the Airwallex Payments module.
*
* DISCLAIMER
*
* Do not edit or add to this file if you wish to upgrade
* to newer versions in the future.
*
* @copyright Copyright (c) 2021 Magebit, Ltd. (https://magebit.com/)
* @license GNU General Public License ("GPL") v3.0
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
-->
<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:module:Magento_Store:etc/config.xsd">
<default>
<airwallex>
<general>
<mode>demo</mode>
<demo_client_id />
<demo_api_key backend_model="Magento\Config\Model\Config\Backend\Encrypted" />
<prod_client_id />
<prod_api_key backend_model="Magento\Config\Model\Config\Backend\Encrypted" />
<webhook_demo_secret_key backend_model="Magento\Config\Model\Config\Backend\Encrypted" />
<webhook_prod_secret_key backend_model="Magento\Config\Model\Config\Backend\Encrypted" />
</general>
</airwallex>
<payment>
<airwallex_payments_card>
<active>0</active>
<model>AirwallexPaymentsCardsGatewayFacade</model>
<allowspecific>0</allowspecific>
<title>Pay by Card (Airwallex)</title>
<payment_action>authorize</payment_action>
<airwallex_payment_action>authorize_capture</airwallex_payment_action>
<is_gateway>1</is_gateway>
<can_authorize>1</can_authorize>
<can_capture>1</can_capture>
<can_capture_partial>0</can_capture_partial>
<can_refund>1</can_refund>
<can_refund_partial_per_invoice>1</can_refund_partial_per_invoice>
<can_void>1</can_void>
<can_cancel>1</can_cancel>
<can_use_internal>1</can_use_internal>
<can_use_checkout>1</can_use_checkout>
<can_save_cc>0</can_save_cc>
<sort_order>10</sort_order>
</airwallex_payments_card>
<airwallex_payments_wechat>
<active>0</active>
<model>AirwallexPaymentsWechatGatewayFacade</model>
<allowspecific>0</allowspecific>
<title>Pay by Wechat (Airwallex)</title>
<payment_action>authorize</payment_action>
<is_gateway>1</is_gateway>
<can_authorize>1</can_authorize>
<can_capture>1</can_capture>
<can_capture_partial>0</can_capture_partial>
<can_refund>1</can_refund>
<can_refund_partial_per_invoice>1</can_refund_partial_per_invoice>
<can_void>1</can_void>
<can_cancel>1</can_cancel>
<can_use_internal>1</can_use_internal>
<can_use_checkout>1</can_use_checkout>
<sort_order>20</sort_order>
</airwallex_payments_wechat>
<airwallex_payments_alipaycn>
<active>0</active>
<model>AirwallexPaymentsAlipayCNGatewayFacade</model>
<allowspecific>0</allowspecific>
<title>Pay by Alipay CN (Airwallex)</title>
<payment_action>authorize</payment_action>
<is_gateway>1</is_gateway>
<can_authorize>1</can_authorize>
<can_capture>1</can_capture>
<can_capture_partial>0</can_capture_partial>
<can_refund>1</can_refund>
<can_refund_partial_per_invoice>1</can_refund_partial_per_invoice>
<can_void>1</can_void>
<can_cancel>1</can_cancel>
<can_use_internal>1</can_use_internal>
<can_use_checkout>1</can_use_checkout>
<sort_order>30</sort_order>
</airwallex_payments_alipaycn>
<airwallex_payments_dana>
<active>0</active>
<model>AirwallexPaymentsDanaGatewayFacade</model>
<allowspecific>0</allowspecific>
<title>Pay by Dana (Airwallex)</title>
<payment_action>authorize</payment_action>
<is_gateway>1</is_gateway>
<can_authorize>1</can_authorize>
<can_capture>1</can_capture>
<can_capture_partial>0</can_capture_partial>
<can_refund>1</can_refund>
<can_refund_partial_per_invoice>1</can_refund_partial_per_invoice>
<can_void>1</can_void>
<can_cancel>1</can_cancel>
<can_use_internal>1</can_use_internal>
<can_use_checkout>1</can_use_checkout>
<sort_order>40</sort_order>
</airwallex_payments_dana>
<airwallex_payments_alipayhk>
<active>0</active>
<model>AirwallexPaymentsAlipayHKGatewayFacade</model>
<allowspecific>0</allowspecific>
<title>Pay by Alipay HK (Airwallex)</title>
<payment_action>authorize</payment_action>
<is_gateway>1</is_gateway>
<can_authorize>1</can_authorize>
<can_capture>1</can_capture>
<can_capture_partial>0</can_capture_partial>
<can_refund>1</can_refund>
<can_refund_partial_per_invoice>1</can_refund_partial_per_invoice>
<can_void>1</can_void>
<can_cancel>1</can_cancel>
<can_use_internal>1</can_use_internal>
<can_use_checkout>1</can_use_checkout>
<sort_order>50</sort_order>
</airwallex_payments_alipayhk>
<airwallex_payments_gcash>
<active>0</active>
<model>AirwallexPaymentsGCashGatewayFacade</model>
<allowspecific>0</allowspecific>
<title>Pay by GCash (Airwallex)</title>
<payment_action>authorize</payment_action>
<is_gateway>1</is_gateway>
<can_authorize>1</can_authorize>
<can_capture>1</can_capture>
<can_capture_partial>0</can_capture_partial>
<can_refund>1</can_refund>
<can_refund_partial_per_invoice>1</can_refund_partial_per_invoice>
<can_void>1</can_void>
<can_cancel>1</can_cancel>
<can_use_internal>1</can_use_internal>
<can_use_checkout>1</can_use_checkout>
<sort_order>60</sort_order>
</airwallex_payments_gcash>
<airwallex_payments_kakaopay>
<active>0</active>
<model>AirwallexPaymentsKakaoGatewayFacade</model>
<allowspecific>0</allowspecific>
<title>Pay by Kakao (Airwallex)</title>
<payment_action>authorize</payment_action>
<is_gateway>1</is_gateway>
<can_authorize>1</can_authorize>
<can_capture>1</can_capture>
<can_capture_partial>0</can_capture_partial>
<can_refund>1</can_refund>
<can_refund_partial_per_invoice>1</can_refund_partial_per_invoice>
<can_void>1</can_void>
<can_cancel>1</can_cancel>
<can_use_internal>1</can_use_internal>
<can_use_checkout>1</can_use_checkout>
<sort_order>70</sort_order>
</airwallex_payments_kakaopay>
<airwallex_payments_tng>
<active>0</active>
<model>AirwallexPaymentsTouchNGoGatewayFacade</model>
<allowspecific>0</allowspecific>
<title>Pay by Touch ‘n Go (Airwallex)</title>
<payment_action>authorize</payment_action>
<is_gateway>1</is_gateway>
<can_authorize>1</can_authorize>
<can_capture>1</can_capture>
<can_capture_partial>0</can_capture_partial>
<can_refund>1</can_refund>
<can_refund_partial_per_invoice>1</can_refund_partial_per_invoice>
<can_void>1</can_void>
<can_cancel>1</can_cancel>
<can_use_internal>1</can_use_internal>
<can_use_checkout>1</can_use_checkout>
<sort_order>80</sort_order>
</airwallex_payments_tng>
</payment>
</default>
</config>
<?xml version="1.0"?>
<!--
/**
* This file is part of the Airwallex Payments module.
*
* DISCLAIMER
*
* Do not edit or add to this file if you wish to upgrade
* to newer versions in the future.
*
* @copyright Copyright (c) 2021 Magebit, Ltd. (https://magebit.com/)
* @license GNU General Public License ("GPL") v3.0
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
-->
<csp_whitelist xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="urn:magento:module:Magento_Csp/etc/csp_whitelist.xsd">
<policies>
<policy id="script-src">
<values>
<value id="airwallex-api" type="host">checkout.airwallex.com</value>
<value id="metrix" type="host">h.online-metrix.net/</value>
</values>
</policy>
<policy id="connect-src">
<values>
<value id="airwallex-api" type="host">checkout.airwallex.com</value>
<value id="metrix" type="host">h.online-metrix.net/</value>
</values>
</policy>
<policy id="frame-src">
<values>
<value id="airwallex-api" type="host">checkout.airwallex.com</value>
<value id="airwallex-demo-api" type="host">checkout-demo.airwallex.com</value>
<value id="metrix" type="host">h.online-metrix.net/</value>
<value id="pci-api-demo-airwallex" type="host">pci-api-demo.airwallex.com</value>
<value id="demo-pacybsmock-airwallex" type="host">demo-pacybsmock.airwallex.com</value>
</values>
</policy>
<policy id="img-src">
<values>
<value id="metrix" type="host">*.online-metrix.net/</value>
</values>
</policy>
</policies>
</csp_whitelist>
<?xml version="1.0"?>
<!--
/**
* This file is part of the Magebit Lichtkoning module.
*
* DISCLAIMER
*
* Do not edit or add to this file if you wish to upgrade
* to newer versions in the future.
*
* @copyright Copyright (c) 2020 Magebit, Ltd. (https://magebit.com/)
* @license GNU General Public License ("GPL") v3.0
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
-->
<schema xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:Setup/Declaration/Schema/etc/schema.xsd">
<table name="airwallex_payment_intents">
<column xsi:type="int" name="id" padding="6" unsigned="false" nullable="false" identity="true" />
<column xsi:type="varchar" name="order_increment_id" nullable="false" />
<column xsi:type="varchar" name="payment_intent_id" nullable="false" />
<constraint xsi:type="primary" referenceId="PRIMARY">
<column name="id"/>
</constraint>
</table>
</schema>
<?xml version="1.0"?>
<!--
/**
* This file is part of the Airwallex Payments module.
*
* DISCLAIMER
*
* Do not edit or add to this file if you wish to upgrade
* to newer versions in the future.
*
* @copyright Copyright (c) 2021 Magebit, Ltd. (https://magebit.com/)
* @license GNU General Public License ("GPL") v3.0
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
-->
<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:ObjectManager/etc/config.xsd">
<preference for="Airwallex\Payments\Api\ServiceInterface" type="Airwallex\Payments\Model\Service" />
<type name="Magento\Payment\Block\Form\Container">
<plugin name="remove_methods_from_admin_reorder" type="Airwallex\Payments\Plugin\RemoveMethodsFromAdminReorder" sortOrder="1" />
</type>
<type name="Magento\Store\Model\Store">
<plugin name="remove_intent_after_change_currency" type="Airwallex\Payments\Plugin\StorePlugin" sortOrder="1" />
</type>
<type name="Airwallex\Payments\Logger\Handler">
<arguments>
<argument name="filesystem" xsi:type="object">Magento\Framework\Filesystem\Driver\File</argument>
</arguments>
</type>
<type name="Airwallex\Payments\Logger\Logger">
<arguments>
<argument name="name" xsi:type="string">Airwallex_Payments_Logger</argument>
<argument name="handlers" xsi:type="array">
<item name="system" xsi:type="object">Airwallex\Payments\Logger\Handler</item>
</argument>
</arguments>
</type>
<!-- Card Method -->
<virtualType name="AirwallexPaymentCardCountryValidator" type="Magento\Payment\Gateway\Validator\CountryValidator">
<arguments>
<argument name="config" xsi:type="object">AirwallexPaymentCardConfig</argument>
</arguments>
</virtualType>
<virtualType name="AirwallexPaymentCardValidatorPool" type="Magento\Payment\Gateway\Validator\ValidatorPool">
<arguments>
<argument name="validators" xsi:type="array">
<item name="country" xsi:type="string">AirwallexPaymentCardCountryValidator</item>
</argument>
</arguments>
</virtualType>
<virtualType name="AirwallexPaymentCardConfig" type="Magento\Payment\Gateway\Config\Config">
<arguments>
<argument name="methodCode" xsi:type="const">Airwallex\Payments\Model\Methods\CardMethod::CODE</argument>
</arguments>
</virtualType>
<virtualType name="AirwallexPaymentCardConfigValueHandler" type="Magento\Payment\Gateway\Config\ConfigValueHandler">
<arguments>
<argument name="configInterface" xsi:type="object">AirwallexPaymentCardConfig</argument>
</arguments>
</virtualType>
<virtualType name="AirwallexPaymentCardValueHandlerPool" type="Magento\Payment\Gateway\Config\ValueHandlerPool">
<arguments>
<argument name="handlers" xsi:type="array">
<item name="default" xsi:type="string">AirwallexPaymentCardConfigValueHandler</item>
</argument>
</arguments>
</virtualType>
<virtualType name="AirwallexPaymentsCardsGatewayFacade" type="Airwallex\Payments\Model\Methods\CardMethod">
<arguments>
<argument name="eventManager" xsi:type="object">Magento\Framework\Event\ManagerInterface</argument>
<argument name="valueHandlerPool" xsi:type="object">AirwallexPaymentCardValueHandlerPool</argument>
<argument name="paymentDataObjectFactory" xsi:type="object">Magento\Payment\Gateway\Data\PaymentDataObjectFactory</argument>
<argument name="code" xsi:type="const">Airwallex\Payments\Model\Methods\CardMethod::CODE</argument>
<argument name="formBlockType" xsi:type="string">Magento\Payment\Block\Form</argument>
<argument name="infoBlockType" xsi:type="string">Magento\Payment\Block\Info</argument>
<argument name="logger" xsi:type="object">Airwallex\Payments\Logger\Logger</argument>
<argument name="validatorPool" xsi:type="object">AirwallexPaymentCardValidatorPool</argument>
</arguments>
</virtualType>
<!-- Wechat Method -->
<virtualType name="AirwallexPaymentWechatCountryValidator" type="Magento\Payment\Gateway\Validator\CountryValidator">
<arguments>
<argument name="config" xsi:type="object">AirwallexPaymentWechatConfig</argument>
</arguments>
</virtualType>
<virtualType name="AirwallexPaymentsWechatValidatorPool" type="Magento\Payment\Gateway\Validator\ValidatorPool">
<arguments>
<argument name="validators" xsi:type="array">
<item name="country" xsi:type="string">AirwallexPaymentWechatCountryValidator</item>
</argument>
</arguments>
</virtualType>
<virtualType name="AirwallexPaymentWechatConfig" type="Magento\Payment\Gateway\Config\Config">
<arguments>
<argument name="methodCode" xsi:type="const">Airwallex\Payments\Model\Methods\WechatMethod::CODE</argument>
</arguments>
</virtualType>
<virtualType name="AirwallexPaymentWechatConfigValueHandler" type="Magento\Payment\Gateway\Config\ConfigValueHandler">
<arguments>
<argument name="configInterface" xsi:type="object">AirwallexPaymentWechatConfig</argument>
</arguments>
</virtualType>
<virtualType name="AirwallexPaymentWechatValueHandlerPool" type="Magento\Payment\Gateway\Config\ValueHandlerPool">
<arguments>
<argument name="handlers" xsi:type="array">
<item name="default" xsi:type="string">AirwallexPaymentWechatConfigValueHandler</item>
</argument>
</arguments>
</virtualType>
<virtualType name="AirwallexPaymentsWechatGatewayFacade" type="Airwallex\Payments\Model\Methods\WechatMethod">
<arguments>
<argument name="eventManager" xsi:type="object">Magento\Framework\Event\ManagerInterface</argument>
<argument name="valueHandlerPool" xsi:type="object">AirwallexPaymentWechatValueHandlerPool</argument>
<argument name="paymentDataObjectFactory" xsi:type="object">Magento\Payment\Gateway\Data\PaymentDataObjectFactory</argument>
<argument name="code" xsi:type="const">Airwallex\Payments\Model\Methods\WechatMethod::CODE</argument>
<argument name="formBlockType" xsi:type="string">Magento\Payment\Block\Form</argument>
<argument name="infoBlockType" xsi:type="string">Magento\Payment\Block\Info</argument>
<argument name="logger" xsi:type="object">Airwallex\Payments\Logger\Logger</argument>
<argument name="validatorPool" xsi:type="object">AirwallexPaymentsWechatValidatorPool</argument>
</arguments>
</virtualType>
<!-- AlipayCN Method -->
<virtualType name="AirwallexPaymentAlipayCNCountryValidator" type="Magento\Payment\Gateway\Validator\CountryValidator">
<arguments>
<argument name="config" xsi:type="object">AirwallexPaymentAlipayCNConfig</argument>
</arguments>
</virtualType>
<virtualType name="AirwallexPaymentsAlipayCNValidatorPool" type="Magento\Payment\Gateway\Validator\ValidatorPool">
<arguments>
<argument name="validators" xsi:type="array">
<item name="country" xsi:type="string">AirwallexPaymentAlipayCNCountryValidator</item>
</argument>
</arguments>
</virtualType>
<virtualType name="AirwallexPaymentAlipayCNConfig" type="Magento\Payment\Gateway\Config\Config">
<arguments>
<argument name="methodCode" xsi:type="const">Airwallex\Payments\Model\Methods\RedirectMethod::ALIPAYCN_CODE</argument>
</arguments>
</virtualType>
<virtualType name="AirwallexPaymentAlipayCNConfigValueHandler" type="Magento\Payment\Gateway\Config\ConfigValueHandler">
<arguments>
<argument name="configInterface" xsi:type="object">AirwallexPaymentAlipayCNConfig</argument>
</arguments>
</virtualType>
<virtualType name="AirwallexPaymentAlipayCNValueHandlerPool" type="Magento\Payment\Gateway\Config\ValueHandlerPool">
<arguments>
<argument name="handlers" xsi:type="array">
<item name="default" xsi:type="string">AirwallexPaymentAlipayCNConfigValueHandler</item>
</argument>
</arguments>
</virtualType>
<virtualType name="AirwallexPaymentsAlipayCNGatewayFacade" type="Airwallex\Payments\Model\Methods\RedirectMethod">
<arguments>
<argument name="eventManager" xsi:type="object">Magento\Framework\Event\ManagerInterface</argument>
<argument name="valueHandlerPool" xsi:type="object">AirwallexPaymentAlipayCNValueHandlerPool</argument>
<argument name="paymentDataObjectFactory" xsi:type="object">Magento\Payment\Gateway\Data\PaymentDataObjectFactory</argument>
<argument name="code" xsi:type="const">Airwallex\Payments\Model\Methods\RedirectMethod::ALIPAYCN_CODE</argument>
<argument name="formBlockType" xsi:type="string">Magento\Payment\Block\Form</argument>
<argument name="infoBlockType" xsi:type="string">Magento\Payment\Block\Info</argument>
<argument name="logger" xsi:type="object">Airwallex\Payments\Logger\Logger</argument>
<argument name="validatorPool" xsi:type="object">AirwallexPaymentsAlipayCNValidatorPool</argument>
</arguments>
</virtualType>
<!-- Dana Method -->
<virtualType name="AirwallexPaymentDanaCountryValidator" type="Magento\Payment\Gateway\Validator\CountryValidator">
<arguments>
<argument name="config" xsi:type="object">AirwallexPaymentDanaConfig</argument>
</arguments>
</virtualType>
<virtualType name="AirwallexPaymentsDanaValidatorPool" type="Magento\Payment\Gateway\Validator\ValidatorPool">
<arguments>
<argument name="validators" xsi:type="array">
<item name="country" xsi:type="string">AirwallexPaymentDanaCountryValidator</item>
</argument>
</arguments>
</virtualType>
<virtualType name="AirwallexPaymentDanaConfig" type="Magento\Payment\Gateway\Config\Config">
<arguments>
<argument name="methodCode" xsi:type="const">Airwallex\Payments\Model\Methods\RedirectMethod::DANA_CODE</argument>
</arguments>
</virtualType>
<virtualType name="AirwallexPaymentDanaConfigValueHandler" type="Magento\Payment\Gateway\Config\ConfigValueHandler">
<arguments>
<argument name="configInterface" xsi:type="object">AirwallexPaymentDanaConfig</argument>
</arguments>
</virtualType>
<virtualType name="AirwallexPaymentDanaValueHandlerPool" type="Magento\Payment\Gateway\Config\ValueHandlerPool">
<arguments>
<argument name="handlers" xsi:type="array">
<item name="default" xsi:type="string">AirwallexPaymentDanaConfigValueHandler</item>
</argument>
</arguments>
</virtualType>
<virtualType name="AirwallexPaymentsDanaGatewayFacade" type="Airwallex\Payments\Model\Methods\RedirectMethod">
<arguments>
<argument name="eventManager" xsi:type="object">Magento\Framework\Event\ManagerInterface</argument>
<argument name="valueHandlerPool" xsi:type="object">AirwallexPaymentDanaValueHandlerPool</argument>
<argument name="paymentDataObjectFactory" xsi:type="object">Magento\Payment\Gateway\Data\PaymentDataObjectFactory</argument>
<argument name="code" xsi:type="const">Airwallex\Payments\Model\Methods\RedirectMethod::DANA_CODE</argument>
<argument name="formBlockType" xsi:type="string">Magento\Payment\Block\Form</argument>
<argument name="infoBlockType" xsi:type="string">Magento\Payment\Block\Info</argument>
<argument name="logger" xsi:type="object">Airwallex\Payments\Logger\Logger</argument>
<argument name="validatorPool" xsi:type="object">AirwallexPaymentsDanaValidatorPool</argument>
</arguments>
</virtualType>
<!-- AlipayHK Method -->
<virtualType name="AirwallexPaymentAlipayHKCountryValidator" type="Magento\Payment\Gateway\Validator\CountryValidator">
<arguments>
<argument name="config" xsi:type="object">AirwallexPaymentAlipayHKConfig</argument>
</arguments>
</virtualType>
<virtualType name="AirwallexPaymentsAlipayHKValidatorPool" type="Magento\Payment\Gateway\Validator\ValidatorPool">
<arguments>
<argument name="validators" xsi:type="array">
<item name="country" xsi:type="string">AirwallexPaymentAlipayHKCountryValidator</item>
</argument>
</arguments>
</virtualType>
<virtualType name="AirwallexPaymentAlipayHKConfig" type="Magento\Payment\Gateway\Config\Config">
<arguments>
<argument name="methodCode" xsi:type="const">Airwallex\Payments\Model\Methods\RedirectMethod::ALIPAYHK_CODE</argument>
</arguments>
</virtualType>
<virtualType name="AirwallexPaymentAlipayHKConfigValueHandler" type="Magento\Payment\Gateway\Config\ConfigValueHandler">
<arguments>
<argument name="configInterface" xsi:type="object">AirwallexPaymentAlipayHKConfig</argument>
</arguments>
</virtualType>
<virtualType name="AirwallexPaymentAlipayHKValueHandlerPool" type="Magento\Payment\Gateway\Config\ValueHandlerPool">
<arguments>
<argument name="handlers" xsi:type="array">
<item name="default" xsi:type="string">AirwallexPaymentAlipayHKConfigValueHandler</item>
</argument>
</arguments>
</virtualType>
<virtualType name="AirwallexPaymentsAlipayHKGatewayFacade" type="Airwallex\Payments\Model\Methods\RedirectMethod">
<arguments>
<argument name="eventManager" xsi:type="object">Magento\Framework\Event\ManagerInterface</argument>
<argument name="valueHandlerPool" xsi:type="object">AirwallexPaymentAlipayHKValueHandlerPool</argument>
<argument name="paymentDataObjectFactory" xsi:type="object">Magento\Payment\Gateway\Data\PaymentDataObjectFactory</argument>
<argument name="code" xsi:type="const">Airwallex\Payments\Model\Methods\RedirectMethod::ALIPAYHK_CODE</argument>
<argument name="formBlockType" xsi:type="string">Magento\Payment\Block\Form</argument>
<argument name="infoBlockType" xsi:type="string">Magento\Payment\Block\Info</argument>
<argument name="logger" xsi:type="object">Airwallex\Payments\Logger\Logger</argument>
<argument name="validatorPool" xsi:type="object">AirwallexPaymentsAlipayHKValidatorPool</argument>
</arguments>
</virtualType>
<!-- GCash Method -->
<virtualType name="AirwallexPaymentGCashCountryValidator" type="Magento\Payment\Gateway\Validator\CountryValidator">
<arguments>
<argument name="config" xsi:type="object">AirwallexPaymentGCashConfig</argument>
</arguments>
</virtualType>
<virtualType name="AirwallexPaymentsGCashValidatorPool" type="Magento\Payment\Gateway\Validator\ValidatorPool">
<arguments>
<argument name="validators" xsi:type="array">
<item name="country" xsi:type="string">AirwallexPaymentGCashCountryValidator</item>
</argument>
</arguments>
</virtualType>
<virtualType name="AirwallexPaymentGCashConfig" type="Magento\Payment\Gateway\Config\Config">
<arguments>
<argument name="methodCode" xsi:type="const">Airwallex\Payments\Model\Methods\RedirectMethod::GCASH_CODE</argument>
</arguments>
</virtualType>
<virtualType name="AirwallexPaymentGCashConfigValueHandler" type="Magento\Payment\Gateway\Config\ConfigValueHandler">
<arguments>
<argument name="configInterface" xsi:type="object">AirwallexPaymentGCashConfig</argument>
</arguments>
</virtualType>
<virtualType name="AirwallexPaymentGCashValueHandlerPool" type="Magento\Payment\Gateway\Config\ValueHandlerPool">
<arguments>
<argument name="handlers" xsi:type="array">
<item name="default" xsi:type="string">AirwallexPaymentGCashConfigValueHandler</item>
</argument>
</arguments>
</virtualType>
<virtualType name="AirwallexPaymentsGCashGatewayFacade" type="Airwallex\Payments\Model\Methods\RedirectMethod">
<arguments>
<argument name="eventManager" xsi:type="object">Magento\Framework\Event\ManagerInterface</argument>
<argument name="valueHandlerPool" xsi:type="object">AirwallexPaymentGCashValueHandlerPool</argument>
<argument name="paymentDataObjectFactory" xsi:type="object">Magento\Payment\Gateway\Data\PaymentDataObjectFactory</argument>
<argument name="code" xsi:type="const">Airwallex\Payments\Model\Methods\RedirectMethod::GCASH_CODE</argument>
<argument name="formBlockType" xsi:type="string">Magento\Payment\Block\Form</argument>
<argument name="infoBlockType" xsi:type="string">Magento\Payment\Block\Info</argument>
<argument name="logger" xsi:type="object">Airwallex\Payments\Logger\Logger</argument>
<argument name="validatorPool" xsi:type="object">AirwallexPaymentsGCashValidatorPool</argument>
</arguments>
</virtualType>
<!-- Kakao Method -->
<virtualType name="AirwallexPaymentKakaoCountryValidator" type="Magento\Payment\Gateway\Validator\CountryValidator">
<arguments>
<argument name="config" xsi:type="object">AirwallexPaymentKakaoConfig</argument>
</arguments>
</virtualType>
<virtualType name="AirwallexPaymentsKakaoValidatorPool" type="Magento\Payment\Gateway\Validator\ValidatorPool">
<arguments>
<argument name="validators" xsi:type="array">
<item name="country" xsi:type="string">AirwallexPaymentKakaoCountryValidator</item>
</argument>
</arguments>
</virtualType>
<virtualType name="AirwallexPaymentKakaoConfig" type="Magento\Payment\Gateway\Config\Config">
<arguments>
<argument name="methodCode" xsi:type="const">Airwallex\Payments\Model\Methods\RedirectMethod::KAKAO_CODE</argument>
</arguments>
</virtualType>
<virtualType name="AirwallexPaymentKakaoConfigValueHandler" type="Magento\Payment\Gateway\Config\ConfigValueHandler">
<arguments>
<argument name="configInterface" xsi:type="object">AirwallexPaymentKakaoConfig</argument>
</arguments>
</virtualType>
<virtualType name="AirwallexPaymentKakaoValueHandlerPool" type="Magento\Payment\Gateway\Config\ValueHandlerPool">
<arguments>
<argument name="handlers" xsi:type="array">
<item name="default" xsi:type="string">AirwallexPaymentKakaoConfigValueHandler</item>
</argument>
</arguments>
</virtualType>
<virtualType name="AirwallexPaymentsKakaoGatewayFacade" type="Airwallex\Payments\Model\Methods\RedirectMethod">
<arguments>
<argument name="eventManager" xsi:type="object">Magento\Framework\Event\ManagerInterface</argument>
<argument name="valueHandlerPool" xsi:type="object">AirwallexPaymentKakaoValueHandlerPool</argument>
<argument name="paymentDataObjectFactory" xsi:type="object">Magento\Payment\Gateway\Data\PaymentDataObjectFactory</argument>
<argument name="code" xsi:type="const">Airwallex\Payments\Model\Methods\RedirectMethod::KAKAO_CODE</argument>
<argument name="formBlockType" xsi:type="string">Magento\Payment\Block\Form</argument>
<argument name="infoBlockType" xsi:type="string">Magento\Payment\Block\Info</argument>
<argument name="logger" xsi:type="object">Airwallex\Payments\Logger\Logger</argument>
<argument name="validatorPool" xsi:type="object">AirwallexPaymentsKakaoValidatorPool</argument>
</arguments>
</virtualType>
<!-- TouchNGo Method -->
<virtualType name="AirwallexPaymentTouchNGoCountryValidator" type="Magento\Payment\Gateway\Validator\CountryValidator">
<arguments>
<argument name="config" xsi:type="object">AirwallexPaymentTouchNGoConfig</argument>
</arguments>
</virtualType>
<virtualType name="AirwallexPaymentsTouchNGoValidatorPool" type="Magento\Payment\Gateway\Validator\ValidatorPool">
<arguments>
<argument name="validators" xsi:type="array">
<item name="country" xsi:type="string">AirwallexPaymentTouchNGoCountryValidator</item>
</argument>
</arguments>
</virtualType>
<virtualType name="AirwallexPaymentTouchNGoConfig" type="Magento\Payment\Gateway\Config\Config">
<arguments>
<argument name="methodCode" xsi:type="const">Airwallex\Payments\Model\Methods\RedirectMethod::TOUCH_N_GO_CODE</argument>
</arguments>
</virtualType>
<virtualType name="AirwallexPaymentTouchNGoConfigValueHandler" type="Magento\Payment\Gateway\Config\ConfigValueHandler">
<arguments>
<argument name="configInterface" xsi:type="object">AirwallexPaymentTouchNGoConfig</argument>
</arguments>
</virtualType>
<virtualType name="AirwallexPaymentTouchNGoValueHandlerPool" type="Magento\Payment\Gateway\Config\ValueHandlerPool">
<arguments>
<argument name="handlers" xsi:type="array">
<item name="default" xsi:type="string">AirwallexPaymentTouchNGoConfigValueHandler</item>
</argument>
</arguments>
</virtualType>
<virtualType name="AirwallexPaymentsTouchNGoGatewayFacade" type="Airwallex\Payments\Model\Methods\RedirectMethod">
<arguments>
<argument name="eventManager" xsi:type="object">Magento\Framework\Event\ManagerInterface</argument>
<argument name="valueHandlerPool" xsi:type="object">AirwallexPaymentTouchNGoValueHandlerPool</argument>
<argument name="paymentDataObjectFactory" xsi:type="object">Magento\Payment\Gateway\Data\PaymentDataObjectFactory</argument>
<argument name="code" xsi:type="const">Airwallex\Payments\Model\Methods\RedirectMethod::TOUCH_N_GO_CODE</argument>
<argument name="formBlockType" xsi:type="string">Magento\Payment\Block\Form</argument>
<argument name="infoBlockType" xsi:type="string">Magento\Payment\Block\Info</argument>
<argument name="logger" xsi:type="object">Airwallex\Payments\Logger\Logger</argument>
<argument name="validatorPool" xsi:type="object">AirwallexPaymentsTouchNGoValidatorPool</argument>
</arguments>
</virtualType>
</config>
<?xml version="1.0"?>
<!--
/**
* This file is part of the Airwallex Payments module.
*
* DISCLAIMER
*
* Do not edit or add to this file if you wish to upgrade
* to newer versions in the future.
*
* @copyright Copyright (c) 2021 Magebit, Ltd. (https://magebit.com/)
* @license GNU General Public License ("GPL") v3.0
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
-->
<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:Event/etc/events.xsd">
<event name="sales_quote_add_item">
<observer name="after_add_quote_clear_saved_intent_from_cache" instance="Airwallex\Payments\Observer\ClearSavedIntent"/>
</event>
<event name="checkout_onepage_controller_success_action">
<observer name="quote_success_clear_saved_intent_from_cache" instance="Airwallex\Payments\Observer\ClearSavedIntent"/>
</event>
</config>
<?xml version="1.0"?>
<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:ObjectManager/etc/config.xsd">
<type name="Magento\Checkout\Model\CompositeConfigProvider">
<arguments>
<argument name="configProviders" xsi:type="array">
<item name="airwallex_payments_config_provider" xsi:type="object">Airwallex\Payments\Model\Ui\ConfigProvider</item>
</argument>
</arguments>
</type>
</config>
<?xml version="1.0"?>
<!--
/**
* This file is part of the Airwallex Payments module.
*
* DISCLAIMER
*
* Do not edit or add to this file if you wish to upgrade
* to newer versions in the future.
*
* @copyright Copyright (c) 2021 Magebit, Ltd. (https://magebit.com/)
* @license GNU General Public License ("GPL") v3.0
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
-->
<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:App/etc/routes.xsd">
<router id="standard">
<route id="airwallex_payments" frontName="airwallex">
<module name="Airwallex_Payments" />
</route>
</router>
</config>
<?xml version="1.0"?>
<!--
/**
* This file is part of the Airwallex Payments module.
*
* DISCLAIMER
*
* Do not edit or add to this file if you wish to upgrade
* to newer versions in the future.
*
* @copyright Copyright (c) 2021 Magebit, Ltd. (https://magebit.com/)
* @license GNU General Public License ("GPL") v3.0
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
-->
<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:Module/etc/module.xsd">
<module name="Airwallex_Payments" setup_version="1.2.2">
<sequence>
<module name="Magento_Sales"/>
<module name="Magento_Payment"/>
<module name="Magento_Checkout"/>
</sequence>
</module>
</config>
<?xml version="1.0"?>
<!--
/**
* This file is part of the Airwallex Payments module.
*
* DISCLAIMER
*
* Do not edit or add to this file if you wish to upgrade
* to newer versions in the future.
*
* @copyright Copyright (c) 2021 Magebit, Ltd. (https://magebit.com/)
* @license GNU General Public License ("GPL") v3.0
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
-->
<payment xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:module:Magento_Payment:etc/payment.xsd">
<methods>
<method name="airwallex_payments">
<allow_multiple_address>1</allow_multiple_address>
</method>
</methods>
</payment>
<?xml version="1.0"?>
<!--
/**
* This file is part of the Airwallex Payments module.
*
* DISCLAIMER
*
* Do not edit or add to this file if you wish to upgrade
* to newer versions in the future.
*
* @copyright Copyright (c) 2021 Magebit, Ltd. (https://magebit.com/)
* @license GNU General Public License ("GPL") v3.0
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
-->
<routes xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:module:Magento_Webapi:etc/webapi.xsd">
<route url="/V1/airwallex/payments/create_intent" method="POST">
<service class="Airwallex\Payments\Api\ServiceInterface" method="createIntent"/>
<resources>
<resource ref="anonymous"/>
</resources>
</route>
<route url="/V1/airwallex/payments/refresh_intent" method="POST">
<service class="Airwallex\Payments\Api\ServiceInterface" method="refreshIntent"/>
<resources>
<resource ref="anonymous"/>
</resources>
</route>
<route url="/V1/airwallex/payments/redirect_url" method="POST">
<service class="Airwallex\Payments\Api\ServiceInterface" method="redirectUrl"/>
<resources>
<resource ref="anonymous"/>
</resources>
</route>
</routes>
# Airwallex Payments
## Compatibility:
This module was tested on:
* Magento 2.4 @ PHP 7.4
## Installing/Getting started
```bash
composer require {futer_link}
```
Enable the module
```bash
bin/magento module:enable Airwallex_Payments
```
Module install
```bash
bin/magento setup:upgrade
```
Clean Magento Cache
```bash
bin/magento module:enable cache:flush
```
<?php
/**
* This file is part of the Airwallex Payments module.
*
* DISCLAIMER
*
* Do not edit or add to this file if you wish to upgrade
* to newer versions in the future.
*
* @copyright Copyright (c) 2021 Magebit, Ltd. (https://magebit.com/)
* @license GNU General Public License ("GPL") v3.0
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
\Magento\Framework\Component\ComponentRegistrar::register(
\Magento\Framework\Component\ComponentRegistrar::MODULE,
'Airwallex_Payments',
__DIR__
);
<?xml version="1.0"?>
<!--
/**
* This file is part of the Airwallex Payments module.
*
* DISCLAIMER
*
* Do not edit or add to this file if you wish to upgrade
* to newer versions in the future.
*
* @copyright Copyright (c) 2021 Magebit, Ltd. (https://magebit.com/)
* @license GNU General Public License ("GPL") v3.0
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
-->
<page xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:View/Layout/etc/page_configuration.xsd">
<head>
<css src="Airwallex_Payments::css/admin.css"/>
<script src="Airwallex_Payments::js/admin.js"/>
</head>
</page>
/**
* This file is part of the Airwallex Payments module.
*
* DISCLAIMER
*
* Do not edit or add to this file if you wish to upgrade
* to newer versions in the future.
*
* @copyright Copyright (c) 2021 Magebit, Ltd. (https://magebit.com/)
* @license GNU General Public License ("GPL") v3.0
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
.airwallex-admin-config .heading {
padding-left: 20rem;
background: url('../img/airwallex_logo.svg') no-repeat 0 50% / 18rem auto;
height: 40px;
}
.airwallex-admin-config .button-container {
float: right;
}
.airwallex-admin-config::after {
content: '';
clear: both;
display: table;
}
#payment_us_airwallex_payments {
float: left;
width: 100%;
}
<svg width="146" height="20" viewBox="0 0 175 24" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"><defs><path d="M150.743 11.045c2.213 0 3.066 1.354 3.185 2.533a.128.128 0 0 1-.128.14h-6.077a.128.128 0 0 1-.127-.144c.164-1.152 1.185-2.529 3.147-2.529zm3.331 7.496a.254.254 0 0 0-.207.105c-.548.772-1.44 1.248-2.772 1.248-1.835 0-3.428-1.206-3.6-2.915a.128.128 0 0 1 .127-.14h10.919c.031-.096.095-.828.095-1.497 0-5.092-3.036-8.116-7.957-8.116-4.122 0-7.925 3.246-7.925 8.339 0 5.316 3.899 8.435 8.277 8.435 3.957 0 6.464-2.214 7.277-4.89.005-.016.032-.116.062-.262a.255.255 0 0 0-.25-.307h-4.046zm9.655-3.057l-5.177-7.38a.255.255 0 0 1 .21-.401h5.09c.087 0 .167.043.215.115l2.66 4.05c.05.077.164.076.214-.002l2.599-4.045a.255.255 0 0 1 .215-.118h4.798c.208 0 .329.233.21.402l-5.108 7.186a.254.254 0 0 0-.001.293c1.672 2.38 3.583 5.13 5.298 7.537.12.169 0 .401-.208.401h-5.055a.256.256 0 0 1-.214-.114l-2.758-4.182a.128.128 0 0 0-.213 0c-.826 1.228-1.906 2.938-2.725 4.182a.255.255 0 0 1-.214.114h-4.712a.254.254 0 0 1-.21-.399l5.087-7.349a.254.254 0 0 0 0-.29zm-27.43 7.784V.733c0-.141.115-.255.256-.255h4.346c.141 0 .256.114.256.255v22.535c0 .14-.115.254-.256.254h-4.346a.255.255 0 0 1-.256-.254zm-7.158 0V.733c0-.141.115-.255.256-.255h4.346c.141 0 .255.114.255.255v22.535c0 .14-.114.254-.255.254h-4.346a.255.255 0 0 1-.256-.254zm-10.748-3.47c1.95 0 3.611-1.527 3.611-4.201 0-2.737-1.63-4.17-3.611-4.17-2.077 0-3.643 1.433-3.643 4.17 0 2.61 1.63 4.202 3.643 4.202zm3.643 1.687c-.703 1.528-2.3 2.483-4.282 2.483-4.666 0-7.893-3.533-7.893-8.403 0-4.71 3.036-8.34 7.733-8.34 2.844 0 4.09 1.56 4.41 2.292v-1.56c0-.14.114-.254.256-.254h4.186c.14 0 .255.114.255.255v15.31c0 .14-.114.254-.255.254h-4.183a.255.255 0 0 1-.255-.258c.008-.575.028-1.904.028-1.779zM99.496 7.878l2.911 8.818c.04.12.21.116.244-.005l2.487-8.802a.255.255 0 0 1 .246-.186h4.22c.173 0 .296.166.245.33l-4.763 15.31a.255.255 0 0 1-.244.18h-4.453a.256.256 0 0 1-.242-.174l-3.27-9.682c-.04-.116-.205-.115-.243 0l-3.21 9.68a.255.255 0 0 1-.242.175h-4.549a.256.256 0 0 1-.244-.178l-4.825-15.31a.255.255 0 0 1 .244-.331h4.508c.114 0 .215.076.246.186l2.487 8.774c.034.12.204.124.244.005l2.942-8.79a.256.256 0 0 1 .243-.175h4.775c.11 0 .209.07.243.175zm-17.25 4.287a.255.255 0 0 1-.299.251 7.027 7.027 0 0 0-1.235-.098c-1.95 0-3.707 1.146-3.707 4.297v6.653c0 .14-.114.254-.255.254h-4.346a.255.255 0 0 1-.256-.254V7.958c0-.14.114-.255.256-.255h4.186c.141 0 .255.114.255.255v1.878c.831-1.783 2.845-2.292 4.123-2.292.388 0 .776.042 1.079.108.117.026.199.13.199.249v4.264zM64.894 23.268V7.958c0-.14.115-.255.256-.255h4.346c.141 0 .256.114.256.255v15.31c0 .14-.115.254-.256.254H65.15a.255.255 0 0 1-.256-.254zM67.291.032c1.598 0 2.876 1.273 2.876 2.833 0 1.56-1.278 2.833-2.876 2.833-1.534 0-2.812-1.273-2.812-2.833 0-1.56 1.278-2.833 2.812-2.833zM49.417 14.355h5.136c.088 0 .15-.086.12-.169L52.137 6.9a.128.128 0 0 0-.242-.001l-2.597 7.287c-.03.082.032.17.12.17zm6.733 4.584h-8.395a.255.255 0 0 0-.24.17l-1.51 4.244a.255.255 0 0 1-.241.17H41.01a.255.255 0 0 1-.24-.345L49.11 1.12a.255.255 0 0 1 .239-.165h5.494c.106 0 .202.066.239.166l8.246 22.058a.255.255 0 0 1-.24.343h-4.947a.256.256 0 0 1-.241-.17l-1.51-4.243a.256.256 0 0 0-.24-.17z" id="2fc43a18-223c-4935-956e-db25b3626945"></path><linearGradient x1="0%" y1="0%" x2="100%" y2="100%" id="ace4ad29-baac-431d-9fca-59f45317042b"><stop stop-color="#FF4244" offset="0%"></stop><stop stop-color="#FF8E3C" offset="100%"></stop></linearGradient></defs><g fill="none" fill-rule="evenodd"><g><use fill="#000" xlink:href="#2fc43a18-223c-4935-956e-db25b3626945"></use><path d="M34.614 9.421a4.452 4.452 0 0 1 1.057 4.77l-2.347 6.376c-.616 1.674-2.02 2.969-3.755 3.307a4.882 4.882 0 0 1-4.732-1.69L10.763 5.322a.31.31 0 0 0-.528.093L5.656 17.8c-.095.256.157.504.407.402l5.619-2.295a2.481 2.481 0 0 1 3.296 1.546c.415 1.273-.283 2.648-1.512 3.15L6.126 23.6c-1.359.555-2.92.457-4.144-.36a4.461 4.461 0 0 1-1.704-5.26l5.41-14.628C6.329 1.618 7.789.394 9.594.078a5.025 5.025 0 0 1 4.768 1.755l8.078 9.68 7.43-3.035c1.651-.674 3.469-.313 4.744.943zm-4.285 4.862c.094-.256-.158-.504-.408-.401l-4.105 1.676 2.462 2.951a.31.31 0 0 0 .53-.093l1.52-4.133z" fill="url(#ace4ad29-baac-431d-9fca-59f45317042b)"></path></g></g></svg>
\ No newline at end of file
/* global Fieldset */
require(['jquery', 'prototype'], function ($) {
'use strict';
/**
* Open admin section
* @param id
* @param url
*/
window.toggleSolution = function (id, url) {
var doScroll = false;
var pos = false;
Fieldset.toggleCollapse(id, url);
if ($(this).hasClassName('open')) {
$$('.with-button button.button').each(function (anotherButton) {
if (anotherButton !== this && $(anotherButton).hasClassName('open')) {
$(anotherButton).click();
doScroll = true;
}
}.bind(this));
}
if (doScroll) {
pos = Element.cumulativeOffset($(this));
window.scrollTo(pos[0], pos[1] - 45);
}
};
});
<?xml version="1.0"?>
<!--
/**
* This file is part of the Airwallex Payments module.
*
* DISCLAIMER
*
* Do not edit or add to this file if you wish to upgrade
* to newer versions in the future.
*
* @copyright Copyright (c) 2021 Magebit, Ltd. (https://magebit.com/)
* @license GNU General Public License ("GPL") v3.0
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
-->
<page xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:View/Layout/etc/page_configuration.xsd">
<head>
<script src="https://checkout.airwallex.com/assets/elements.bundle.min.js" src_type="url" />
<css src="Airwallex_Payments::css/airwallex_payment.css" />
</head>
<body>
<referenceBlock name="checkout.root">
<arguments>
<argument name="jsLayout" xsi:type="array">
<item name="components" xsi:type="array">
<item name="checkout" xsi:type="array">
<item name="children" xsi:type="array">
<item name="steps" xsi:type="array">
<item name="children" xsi:type="array">
<item name="billing-step" xsi:type="array">
<item name="component" xsi:type="string">uiComponent</item>
<item name="children" xsi:type="array">
<item name="payment" xsi:type="array">
<item name="children" xsi:type="array">
<!-- Merge these payment methods into the list of available methods at the checkout -->
<item name="renders" xsi:type="array">
<item name="children" xsi:type="array">
<item name="airwallex_payments" xsi:type="array">
<item name="component" xsi:type="string">Airwallex_Payments/js/view/payment/payment</item>
<item name="methods" xsi:type="array">
<item name="airwallex_payments_card" xsi:type="array">
<item name="isBillingAddressRequired" xsi:type="boolean">true</item>
</item>
<item name="airwallex_payments_wechat" xsi:type="array">
<item name="isBillingAddressRequired" xsi:type="boolean">true</item>
</item>
<item name="airwallex_payments_alipaycn" xsi:type="array">
<item name="isBillingAddressRequired" xsi:type="boolean">true</item>
</item>
<item name="airwallex_payments_dana" xsi:type="array">
<item name="isBillingAddressRequired" xsi:type="boolean">true</item>
</item>
<item name="airwallex_payments_alipayhk" xsi:type="array">
<item name="isBillingAddressRequired" xsi:type="boolean">true</item>
</item>
<item name="airwallex_payments_gcash" xsi:type="array">
<item name="isBillingAddressRequired" xsi:type="boolean">true</item>
</item>
<item name="airwallex_payments_kakaopay" xsi:type="array">
<item name="isBillingAddressRequired" xsi:type="boolean">true</item>
</item>
<item name="airwallex_payments_tng" xsi:type="array">
<item name="isBillingAddressRequired" xsi:type="boolean">true</item>
</item>
</item>
</item>
</item>
</item>
</item>
</item>
</item>
</item>
</item>
</item>
</item>
</item>
</item>
</argument>
</arguments>
</referenceBlock>
</body>
</page>
/**
* This file is part of the Airwallex Payments module.
*
* DISCLAIMER
*
* Do not edit or add to this file if you wish to upgrade
* to newer versions in the future.
*
* @copyright Copyright (c) 2021 Magebit, Ltd. (https://magebit.com/)
* @license GNU General Public License ("GPL") v3.0
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
.airwallex-card {
border: 1px solid #612fff;
border-radius: 5px;
padding: 5px 10px;
box-shadow: #612fff 0 0 0 1px;
min-height: 40px;
display: flex;
justify-content: center;
align-items: center;
box-sizing: border-box;
margin-bottom: 15px;
}
.airwallex-card.error {
border: 1px solid red;
box-shadow: red 0 0 0 1px;
}
.airwallex-payment-frame {
width: 100%;
}
.airwallex-error {
margin-top: 5px;
color: red;
}
/**
* This file is part of the Airwallex Payments module.
*
* DISCLAIMER
*
* Do not edit or add to this file if you wish to upgrade
* to newer versions in the future.
*
* @copyright Copyright (c) 2021 Magebit, Ltd. (https://magebit.com/)
* @license GNU General Public License ("GPL") v3.0
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
/* global Airwallex */
define([
'jquery',
'ko',
'Magento_Checkout/js/view/payment/default',
'mage/url',
'Magento_Ui/js/model/messageList',
'mage/translate'
], function ($, ko, Component, url, globalMessageList) {
'use strict';
return Component.extend({
code: 'airwallex_payments_card',
type: undefined,
mountElement: undefined,
fonts: [{
src: 'https://checkout.airwallex.com/fonts/CircularXXWeb/CircularXXWeb-Regular.woff2',
family: 'AxLLCircular',
weight: 400,
}],
defaults: {
template: 'Airwallex_Payments/payment/card-method'
},
responseData: {},
readyLoaded: {},
intentId: ko.observable(),
amount: ko.observable(0),
initObservable: function () {
this._super();
this.isChecked.subscribe(function (method) {
if (method !== this.code) {
return;
}
if (!this.readyLoaded[method]) {
this.loadPayment();
}
}, this);
return this;
},
afterRender: function () {
if (this.isChecked() === this.code) {
this.loadPayment();
}
},
/**
* Get payment method data
*/
getData: function () {
let data = this._super();
data['additional_data'] = {
'intent_id': this.intentId(),
'amount': this.amount()
};
return data;
},
loadPayment: function () {
$('body').trigger('processStart');
if (this.type !== 'redirect') {
Airwallex.init({
env: window.checkoutConfig.payment.airwallex_payments.mode,
origin: window.location.origin,
fonts: this.fonts
});
this.initPayment();
this.readyLoaded[this.code] = true;
} else {
$('body').trigger('processStop');
}
},
paymentSuccess: function (intent) {
this.amount(intent.amount);
this.placeOrder();
},
intentConfiguration() {
return {
id: this.responseData.id,
client_secret: this.responseData.clientSecret
}
},
getElementConfiguration: function () {
return {
autoCapture: false,
intent: this.intentConfiguration()
};
},
initPayment: function () {
if(!this.intentConfiguration().id){
this.createIntent();
}
const airwallexElement = Airwallex.createElement(this.type, this.getElementConfiguration());
airwallexElement.mount(this.mountElement);
$('body').trigger('processStop');
window.addEventListener('onReady', function () {
$('body').trigger('processStop');
});
window.addEventListener('onSuccess', function (event) {
this.paymentSuccess(event.detail.intent);
}.bind(this));
window.addEventListener('onError', function (event) {
console.log(event.detail);
});
},
createIntent: function () {
const method = this.isChecked();
const payload = {
'method': method
}
$.ajax({
url: url.build('rest/V1/airwallex/payments/create_intent'),
method: 'POST',
contentType: 'application/json',
async:false,
data: JSON.stringify(payload),
success: function (result) {
this.responseData = JSON.parse(result);
this.intentId(this.responseData.id);
}.bind(this),
error: function () {
globalMessageList.addErrorMessage({
message: $.mage.__('An error occurred on the server. Please try to place the order again.'),
});
$('body').trigger('processStop');
}
});
},
refreshIntent: function () {
const payload = {
'intentId': this.intentConfiguration().id,
'method': this.isChecked()
}
$.ajax({
url: url.build('rest/V1/airwallex/payments/refresh_intent'),
method: 'POST',
contentType: 'application/json',
data: JSON.stringify(payload),
async:false,
success: function (result) {
this.responseData = JSON.parse(result);
this.intentId(this.responseData.id);
}.bind(this),
error: function () {
globalMessageList.addErrorMessage({
message: $.mage.__('An error occurred on the server. Please try to place the order again.'),
});
$('body').trigger('processStop');
}
});
}
});
});
/**
* This file is part of the Airwallex Payments module.
*
* DISCLAIMER
*
* Do not edit or add to this file if you wish to upgrade
* to newer versions in the future.
*
* @copyright Copyright (c) 2021 Magebit, Ltd. (https://magebit.com/)
* @license GNU General Public License ("GPL") v3.0
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
/* global Airwallex */
define([
'jquery',
'ko',
'Airwallex_Payments/js/view/payment/abstract-method',
'Magento_Checkout/js/model/quote',
], function ($, ko, Component, quote) {
'use strict';
return Component.extend({
code: 'airwallex_payments_card',
type: 'card',
mountElement: 'airwallex-payments-card-form',
cardElement: undefined,
validationError: ko.observable(),
defaults: {
template: 'Airwallex_Payments/payment/card-method'
},
getBillingInformation: function () {
const billingAddress = quote.billingAddress();
return {
address: {
city: billingAddress.city,
country_code: billingAddress.countryId,
postcode: billingAddress.postcode,
state: billingAddress.region,
street: billingAddress.street[0]
},
first_name: billingAddress.firstname,
last_name: billingAddress.lastname,
email: quote.guestEmail
}
},
initiateOrderPlacement: function () {
$('body').trigger('processStart');
this.createIntent();
const params = this.intentConfiguration();
params.billing = this.getBillingInformation();
params.element = this.cardElement;
this.validationError(undefined);
Airwallex
.confirmPaymentIntent(params)
.then(function (response) {
this.paymentSuccess(response);
$('body').trigger('processStop');
}.bind(this))
.catch(function (response) {
this.validationError(response.message);
$('body').trigger('processStop');
}.bind(this));
},
initPayment: function () {
this.cardElement = Airwallex.createElement(this.type, {
autoCapture: window.checkoutConfig.payment.airwallex_payments.cc_auto_capture
});
this.cardElement.mount(this.mountElement);
window.addEventListener('onReady', function () {
$('body').trigger('processStop');
}, {once: true});
}
});
});
/**
* This file is part of the Airwallex Payments module.
*
* DISCLAIMER
*
* Do not edit or add to this file if you wish to upgrade
* to newer versions in the future.
*
* @copyright Copyright (c) 2021 Magebit, Ltd. (https://magebit.com/)
* @license GNU General Public License ("GPL") v3.0
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
define(['Airwallex_Payments/js/view/payment/abstract-method',
'jquery',
'Magento_SalesRule/js/action/set-coupon-code',
'Magento_SalesRule/js/action/cancel-coupon'],
function (Component, $, setCouponCodeAction, cancelCouponAction) {
'use strict';
return Component.extend({
code: 'airwallex_payments_wechat',
type: 'wechat',
mountElement: 'airwallex-payments-wechat-form',
defaults: {
template: 'Airwallex_Payments/payment/wechat-method'
},
loadPayment: function() {
if (this.isChecked() === this.code) {
this._super();
setCouponCodeAction.registerSuccessCallback(this.reloadElement.bind(this));
cancelCouponAction.registerSuccessCallback(this.reloadElement.bind(this));
}
},
reloadElement: function() {
Airwallex.destroyElement('wechat');
this.refreshIntent();
this.initPayment();
}
});
});
/**
* This file is part of the Airwallex Payments module.
*
* DISCLAIMER
*
* Do not edit or add to this file if you wish to upgrade
* to newer versions in the future.
*
* @copyright Copyright (c) 2021 Magebit, Ltd. (https://magebit.com/)
* @license GNU General Public License ("GPL") v3.0
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
define([
'uiComponent',
'Magento_Checkout/js/model/payment/renderer-list'
], function (Component, rendererList) {
'use strict';
rendererList.push({
type: 'airwallex_payments_card',
component: 'Airwallex_Payments/js/view/payment/method-renderer/card-method'
});
rendererList.push({
type: 'airwallex_payments_wechat',
component: 'Airwallex_Payments/js/view/payment/method-renderer/wechat-method'
});
rendererList.push({
type: 'airwallex_payments_alipaycn',
component: 'Airwallex_Payments/js/view/payment/redirect-method'
});
rendererList.push({
type: 'airwallex_payments_dana',
component: 'Airwallex_Payments/js/view/payment/redirect-method'
});
rendererList.push({
type: 'airwallex_payments_alipayhk',
component: 'Airwallex_Payments/js/view/payment/redirect-method'
});
rendererList.push({
type: 'airwallex_payments_gcash',
component: 'Airwallex_Payments/js/view/payment/redirect-method'
});
rendererList.push({
type: 'airwallex_payments_kakaopay',
component: 'Airwallex_Payments/js/view/payment/redirect-method'
});
rendererList.push({
type: 'airwallex_payments_tng',
component: 'Airwallex_Payments/js/view/payment/redirect-method'
});
return Component.extend({});
});
/**
* This file is part of the Airwallex Payments module.
*
* DISCLAIMER
*
* Do not edit or add to this file if you wish to upgrade
* to newer versions in the future.
*
* @copyright Copyright (c) 2021 Magebit, Ltd. (https://magebit.com/)
* @license GNU General Public License ("GPL") v3.0
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
define([
'Airwallex_Payments/js/view/payment/abstract-method',
'jquery',
'mage/url',
'Magento_Ui/js/model/messageList',
'mage/translate'
], function (Component, $, url, globalMessageList, $t) {
'use strict';
return Component.extend({
type: 'redirect',
redirectAfterPlaceOrder: false,
defaults: {
template: 'Airwallex_Payments/payment/redirect-method'
},
initObservable: function () {
this.code = this.index;
return this._super();
},
placeOrder: function () {
this.createIntent();
this._super();
},
afterPlaceOrder: function () {
$.ajax({
url: url.build('rest/V1/airwallex/payments/redirect_url'),
method: 'POST',
contentType: 'application/json',
data: {},
beforeSend: function () {
$('body').trigger('processStart');
},
success: function (response) {
$.mage.redirect(response);
},
error: function (e) {
globalMessageList.addErrorMessage({
message: $t(e.responseJSON.message)
});
$('body').trigger('processStop');
}
});
}
});
});
<!--
/**
* This file is part of the Airwallex Payments module.
*
* DISCLAIMER
*
* Do not edit or add to this file if you wish to upgrade
* to newer versions in the future.
*
* @copyright Copyright (c) 2021 Magebit, Ltd. (https://magebit.com/)
* @license GNU General Public License ("GPL") v3.0
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
-->
<div class="payment-method airwallex-payments" data-bind="css: {'_active': (getCode() == isChecked())}">
<div class="payment-method-title field choice">
<input type="radio"
name="payment[method]"
class="radio"
data-bind="attr: {'id': getCode()}, value: getCode(), checked: isChecked, click: selectPaymentMethod, visible: isRadioButtonVisible()"/>
<label data-bind="attr: {'for': getCode()}" class="label"><span data-bind="text: getTitle()"></span></label>
</div>
<div class="payment-method-content">
<!-- ko foreach: getRegion('messages') -->
<!-- ko template: getTemplate() --><!-- /ko -->
<!--/ko-->
<div class="payment-method-billing-address">
<!-- ko foreach: $parent.getRegion(getBillingAddressFormName()) -->
<!-- ko template: getTemplate() --><!-- /ko -->
<!--/ko-->
</div>
<div class="checkout-agreements-block">
<!-- ko foreach: $parent.getRegion('before-place-order') -->
<!-- ko template: getTemplate() --><!-- /ko -->
<!--/ko-->
</div>
<div id='airwallex-payments-card-form' class="airwallex-payment-frame airwallex-card" data-bind="css: {'error': validationError}, afterRender: loadPayment"></div>
<p class="airwallex-error" data-bind="visible: validationError, text: validationError"></p>
<div class="actions-toolbar" id="actions-toolbar">
<div class="primary">
<button class="action primary checkout"
type="submit"
data-bind="
click: initiateOrderPlacement,
enable: (getCode() == isChecked())
"
disabled>
<span data-bind="text: $t('Place Order')"></span>
</button>
</div>
</div>
</div>
</div>
<!--
/**
* This file is part of the Airwallex Payments module.
*
* DISCLAIMER
*
* Do not edit or add to this file if you wish to upgrade
* to newer versions in the future.
*
* @copyright Copyright (c) 2021 Magebit, Ltd. (https://magebit.com/)
* @license GNU General Public License ("GPL") v3.0
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
-->
<div class="payment-method airwallex-payments" data-bind="css: {'_active': (getCode() == isChecked())}">
<div class="payment-method-title field choice">
<input type="radio"
name="payment[method]"
class="radio"
data-bind="attr: {'id': getCode()}, value: getCode(), checked: isChecked, click: selectPaymentMethod, visible: isRadioButtonVisible()"/>
<label data-bind="attr: {'for': getCode()}" class="label"><span data-bind="text: getTitle()"></span></label>
</div>
<div class="payment-method-content">
<!-- ko foreach: getRegion('messages') -->
<!-- ko template: getTemplate() --><!-- /ko -->
<!--/ko-->
<div class="payment-method-billing-address">
<!-- ko foreach: $parent.getRegion(getBillingAddressFormName()) -->
<!-- ko template: getTemplate() --><!-- /ko -->
<!--/ko-->
</div>
<div class="checkout-agreements-block">
<!-- ko foreach: $parent.getRegion('before-place-order') -->
<!-- ko template: getTemplate() --><!-- /ko -->
<!--/ko-->
</div>
<div class="actions-toolbar" id="actions-toolbar">
<div class="primary">
<button class="action primary checkout"
type="submit"
data-bind="
click: placeOrder,
enable: (getCode() == isChecked())
"
disabled>
<span data-bind="text: $t('Place Order')"></span>
</button>
</div>
</div>
</div>
</div>
<!--
/**
* This file is part of the Airwallex Payments module.
*
* DISCLAIMER
*
* Do not edit or add to this file if you wish to upgrade
* to newer versions in the future.
*
* @copyright Copyright (c) 2021 Magebit, Ltd. (https://magebit.com/)
* @license GNU General Public License ("GPL") v3.0
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
-->
<div class="payment-method airwallex-payments" data-bind="css: {'_active': (getCode() == isChecked())}">
<div class="payment-method-title field choice">
<input type="radio"
name="payment[method]"
class="radio"
data-bind="attr: {'id': getCode()}, value: getCode(), checked: isChecked, click: selectPaymentMethod, visible: isRadioButtonVisible()"/>
<label data-bind="attr: {'for': getCode()}" class="label"><span data-bind="text: getTitle()"></span></label>
</div>
<div class="payment-method-content">
<!-- ko foreach: getRegion('messages') -->
<!-- ko template: getTemplate() --><!-- /ko -->
<!--/ko-->
<div class="payment-method-billing-address">
<!-- ko foreach: $parent.getRegion(getBillingAddressFormName()) -->
<!-- ko template: getTemplate() --><!-- /ko -->
<!--/ko-->
</div>
<div class="checkout-agreements-block">
<!-- ko foreach: $parent.getRegion('before-place-order') -->
<!-- ko template: getTemplate() --><!-- /ko -->
<!--/ko-->
</div>
<div id="airwallex-payments-wechat-form" class="airwallex-payment-frame" data-bind="afterRender: loadPayment"></div>
</div>
</div>
......@@ -48,6 +48,7 @@ return array(
'Credis_Module' => $vendorDir . '/colinmollenhour/credis/Module.php',
'Credis_Sentinel' => $vendorDir . '/colinmollenhour/credis/Sentinel.php',
'JsonException' => $vendorDir . '/symfony/polyfill-php73/Resources/stubs/JsonException.php',
'Mobile_Detect' => $vendorDir . '/mobiledetect/mobiledetectlib/Mobile_Detect.php',
'Normalizer' => $vendorDir . '/symfony/polyfill-intl-normalizer/Resources/stubs/Normalizer.php',
'PHPUnit\\Exception' => $vendorDir . '/phpunit/phpunit/src/Exception.php',
'PHPUnit\\Framework\\Assert' => $vendorDir . '/phpunit/phpunit/src/Framework/Assert.php',
......
......@@ -128,6 +128,7 @@ return array(
'103e25fab6e1520b3d5716d51befc8a8' => $vendorDir . '/swissup/module-breeze-integrations/registration.php',
'cbb1b03512ba520311d1592006f0c299' => $vendorDir . '/swissup/theme-frontend-breeze-blank/registration.php',
'940abd8fb01ee76a36b44f35dcf9783b' => $vendorDir . '/weew/helpers-array/src/array.php',
'b598380463d27491e4810196bf363d15' => $vendorDir . '/airwallex/payments-plugin-magento/registration.php',
'8592c7b0947d8a0965a9e8c3d16f9c24' => $vendorDir . '/elasticsearch/elasticsearch/src/autoload.php',
'eda65932675b68b5aee4503e0762d64d' => $vendorDir . '/magento/magento2-functional-testing-framework/src/Magento/FunctionalTestingFramework/_bootstrap.php',
'88ede69c0babb90b8d3e9e7a95ad0eb5' => $vendorDir . '/mageside/module-subscribe-at-checkout/registration.php',
......
......@@ -15,6 +15,7 @@ return array(
'MagentoHackathon\\Composer\\Magento' => array($vendorDir . '/magento/magento-composer-installer/src'),
'Less' => array($vendorDir . '/wikimedia/less.php/lib'),
'JShrink' => array($vendorDir . '/tedivm/jshrink/src'),
'Detection' => array($vendorDir . '/mobiledetect/mobiledetectlib/namespaced'),
'Cm\\RedisSession\\' => array($vendorDir . '/colinmollenhour/php-redis-session-abstract/src'),
'Behat\\Gherkin' => array($vendorDir . '/behat/gherkin/src'),
'' => array($baseDir . '/app/code', $baseDir . '/generated/code'),
......
......@@ -162,5 +162,6 @@ return array(
'Base64Url\\' => array($vendorDir . '/spomky-labs/base64url/src'),
'Aws\\' => array($vendorDir . '/aws/aws-sdk-php/src'),
'Assert\\' => array($vendorDir . '/beberlei/assert/lib/Assert'),
'Airwallex\\Payments\\' => array($vendorDir . '/airwallex/payments-plugin-magento'),
'AESKW\\' => array($vendorDir . '/spomky-labs/aes-key-wrap/src'),
);
......@@ -129,6 +129,7 @@ class ComposerStaticInitb71ce7c407b65980cf51508f463c8dcf
'103e25fab6e1520b3d5716d51befc8a8' => __DIR__ . '/..' . '/swissup/module-breeze-integrations/registration.php',
'cbb1b03512ba520311d1592006f0c299' => __DIR__ . '/..' . '/swissup/theme-frontend-breeze-blank/registration.php',
'940abd8fb01ee76a36b44f35dcf9783b' => __DIR__ . '/..' . '/weew/helpers-array/src/array.php',
'b598380463d27491e4810196bf363d15' => __DIR__ . '/..' . '/airwallex/payments-plugin-magento/registration.php',
'8592c7b0947d8a0965a9e8c3d16f9c24' => __DIR__ . '/..' . '/elasticsearch/elasticsearch/src/autoload.php',
'eda65932675b68b5aee4503e0762d64d' => __DIR__ . '/..' . '/magento/magento2-functional-testing-framework/src/Magento/FunctionalTestingFramework/_bootstrap.php',
'88ede69c0babb90b8d3e9e7a95ad0eb5' => __DIR__ . '/..' . '/mageside/module-subscribe-at-checkout/registration.php',
......@@ -351,6 +352,7 @@ class ComposerStaticInitb71ce7c407b65980cf51508f463c8dcf
array (
'Aws\\' => 4,
'Assert\\' => 7,
'Airwallex\\Payments\\' => 19,
'AESKW\\' => 6,
),
);
......@@ -997,6 +999,10 @@ class ComposerStaticInitb71ce7c407b65980cf51508f463c8dcf
array (
0 => __DIR__ . '/..' . '/beberlei/assert/lib/Assert',
),
'Airwallex\\Payments\\' =>
array (
0 => __DIR__ . '/..' . '/airwallex/payments-plugin-magento',
),
'AESKW\\' =>
array (
0 => __DIR__ . '/..' . '/spomky-labs/aes-key-wrap/src',
......@@ -1064,6 +1070,13 @@ class ComposerStaticInitb71ce7c407b65980cf51508f463c8dcf
0 => __DIR__ . '/..' . '/tedivm/jshrink/src',
),
),
'D' =>
array (
'Detection' =>
array (
0 => __DIR__ . '/..' . '/mobiledetect/mobiledetectlib/namespaced',
),
),
'C' =>
array (
'Cm\\RedisSession\\' =>
......@@ -1128,6 +1141,7 @@ class ComposerStaticInitb71ce7c407b65980cf51508f463c8dcf
'Credis_Module' => __DIR__ . '/..' . '/colinmollenhour/credis/Module.php',
'Credis_Sentinel' => __DIR__ . '/..' . '/colinmollenhour/credis/Sentinel.php',
'JsonException' => __DIR__ . '/..' . '/symfony/polyfill-php73/Resources/stubs/JsonException.php',
'Mobile_Detect' => __DIR__ . '/..' . '/mobiledetect/mobiledetectlib/Mobile_Detect.php',
'Normalizer' => __DIR__ . '/..' . '/symfony/polyfill-intl-normalizer/Resources/stubs/Normalizer.php',
'PHPUnit\\Exception' => __DIR__ . '/..' . '/phpunit/phpunit/src/Exception.php',
'PHPUnit\\Framework\\Assert' => __DIR__ . '/..' . '/phpunit/phpunit/src/Framework/Assert.php',
......
{
"packages": [
{
"name": "airwallex/payments-plugin-magento",
"version": "1.2.2",
"version_normalized": "1.2.2.0",
"source": {
"type": "git",
"url": "https://github.com/airwallex/paymentacceptance-plugin-magento.git",
"reference": "38119a84cc0f9998d8c0d3b9b3e2f87a31dea8c7"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/airwallex/paymentacceptance-plugin-magento/zipball/38119a84cc0f9998d8c0d3b9b3e2f87a31dea8c7",
"reference": "38119a84cc0f9998d8c0d3b9b3e2f87a31dea8c7",
"shasum": "",
"mirrors": [
{
"url": "https://mirrors.aliyun.com/composer/dists/%package%/%reference%.%type%",
"preferred": true
}
]
},
"require": {
"ext-json": "*",
"mobiledetect/mobiledetectlib": "^2.8"
},
"time": "2022-06-01T09:48:45+00:00",
"type": "magento2-module",
"installation-source": "dist",
"autoload": {
"files": [
"registration.php"
],
"psr-4": {
"Airwallex\\Payments\\": ""
}
},
"notification-url": "https://packagist.org/downloads/",
"support": {
"issues": "https://github.com/airwallex/paymentacceptance-plugin-magento/issues",
"source": "https://github.com/airwallex/paymentacceptance-plugin-magento/tree/1.2.2"
},
"install-path": "../airwallex/payments-plugin-magento"
},
{
"name": "allure-framework/allure-codeception",
"version": "1.5.2",
"version_normalized": "1.5.2.0",
......@@ -6630,6 +6673,71 @@
"install-path": "../mageside/module-subscribe-at-checkout"
},
{
"name": "mobiledetect/mobiledetectlib",
"version": "2.8.39",
"version_normalized": "2.8.39.0",
"source": {
"type": "git",
"url": "https://github.com/serbanghita/Mobile-Detect.git",
"reference": "0fd6753003fc870f6e229bae869cc1337c99bc45"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/serbanghita/Mobile-Detect/zipball/0fd6753003fc870f6e229bae869cc1337c99bc45",
"reference": "0fd6753003fc870f6e229bae869cc1337c99bc45",
"shasum": "",
"mirrors": [
{
"url": "https://mirrors.aliyun.com/composer/dists/%package%/%reference%.%type%",
"preferred": true
}
]
},
"require": {
"php": ">=5.0.0"
},
"require-dev": {
"phpunit/phpunit": "~4.8.35||~5.7"
},
"time": "2022-02-17T19:24:25+00:00",
"type": "library",
"installation-source": "dist",
"autoload": {
"psr-0": {
"Detection": "namespaced/"
},
"classmap": [
"Mobile_Detect.php"
]
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Serban Ghita",
"email": "serbanghita@gmail.com",
"homepage": "http://mobiledetect.net",
"role": "Developer"
}
],
"description": "Mobile_Detect is a lightweight PHP class for detecting mobile devices. It uses the User-Agent string combined with specific HTTP headers to detect the mobile environment.",
"homepage": "https://github.com/serbanghita/Mobile-Detect",
"keywords": [
"detect mobile devices",
"mobile",
"mobile detect",
"mobile detector",
"php mobile detect"
],
"support": {
"issues": "https://github.com/serbanghita/Mobile-Detect/issues",
"source": "https://github.com/serbanghita/Mobile-Detect/tree/2.8.39"
},
"install-path": "../mobiledetect/mobiledetectlib"
},
{
"name": "monolog/monolog",
"version": "1.27.1",
"version_normalized": "1.27.1.0",
......
......@@ -3,13 +3,22 @@
'name' => 'magento/magento2ce',
'pretty_version' => 'dev-master',
'version' => 'dev-master',
'reference' => '3c246f4d042423fc0b5148733380e3e2b9c7d64d',
'reference' => '2e6888fd835e9bf29c26ecb13cab664e7a994ade',
'type' => 'project',
'install_path' => __DIR__ . '/../../',
'aliases' => array(),
'dev' => true,
),
'versions' => array(
'airwallex/payments-plugin-magento' => array(
'pretty_version' => '1.2.2',
'version' => '1.2.2.0',
'reference' => '38119a84cc0f9998d8c0d3b9b3e2f87a31dea8c7',
'type' => 'magento2-module',
'install_path' => __DIR__ . '/../airwallex/payments-plugin-magento',
'aliases' => array(),
'dev_requirement' => false,
),
'allure-framework/allure-codeception' => array(
'pretty_version' => '1.5.2',
'version' => '1.5.2.0',
......@@ -940,7 +949,7 @@
'magento/magento2ce' => array(
'pretty_version' => 'dev-master',
'version' => 'dev-master',
'reference' => '3c246f4d042423fc0b5148733380e3e2b9c7d64d',
'reference' => '2e6888fd835e9bf29c26ecb13cab664e7a994ade',
'type' => 'project',
'install_path' => __DIR__ . '/../../',
'aliases' => array(),
......@@ -2224,6 +2233,15 @@
'aliases' => array(),
'dev_requirement' => false,
),
'mobiledetect/mobiledetectlib' => array(
'pretty_version' => '2.8.39',
'version' => '2.8.39.0',
'reference' => '0fd6753003fc870f6e229bae869cc1337c99bc45',
'type' => 'library',
'install_path' => __DIR__ . '/../mobiledetect/mobiledetectlib',
'aliases' => array(),
'dev_requirement' => false,
),
'monolog/monolog' => array(
'pretty_version' => '1.27.1',
'version' => '1.27.1.0',
......
MIT License
Copyright (c) 2021 Şerban Ghiţă, Nick Ilyin and contributors.
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
{"version":"2.8.39","headerMatch":{"HTTP_ACCEPT":{"matches":["application\/x-obml2d","application\/vnd.rim.html","text\/vnd.wap.wml","application\/vnd.wap.xhtml+xml"]},"HTTP_X_WAP_PROFILE":null,"HTTP_X_WAP_CLIENTID":null,"HTTP_WAP_CONNECTION":null,"HTTP_PROFILE":null,"HTTP_X_OPERAMINI_PHONE_UA":null,"HTTP_X_NOKIA_GATEWAY_ID":null,"HTTP_X_ORANGE_ID":null,"HTTP_X_VODAFONE_3GPDPCONTEXT":null,"HTTP_X_HUAWEI_USERID":null,"HTTP_UA_OS":null,"HTTP_X_MOBILE_GATEWAY":null,"HTTP_X_ATT_DEVICEID":null,"HTTP_UA_CPU":{"matches":["ARM"]}},"uaHttpHeaders":["HTTP_USER_AGENT","HTTP_X_OPERAMINI_PHONE_UA","HTTP_X_DEVICE_USER_AGENT","HTTP_X_ORIGINAL_USER_AGENT","HTTP_X_SKYFIRE_PHONE","HTTP_X_BOLT_PHONE_UA","HTTP_DEVICE_STOCK_UA","HTTP_X_UCBROWSER_DEVICE_UA"],"uaMatch":{"phones":{"iPhone":"\\biPhone\\b|\\biPod\\b","BlackBerry":"BlackBerry|\\bBB10\\b|rim[0-9]+|\\b(BBA100|BBB100|BBD100|BBE100|BBF100|STH100)\\b-[0-9]+","Pixel":"; \\bPixel\\b","HTC":"HTC|HTC.*(Sensation|Evo|Vision|Explorer|6800|8100|8900|A7272|S510e|C110e|Legend|Desire|T8282)|APX515CKT|Qtek9090|APA9292KT|HD_mini|Sensation.*Z710e|PG86100|Z715e|Desire.*(A8181|HD)|ADR6200|ADR6400L|ADR6425|001HT|Inspire 4G|Android.*\\bEVO\\b|T-Mobile G1|Z520m|Android [0-9.]+; Pixel","Nexus":"Nexus One|Nexus S|Galaxy.*Nexus|Android.*Nexus.*Mobile|Nexus 4|Nexus 5|Nexus 5X|Nexus 6","Dell":"Dell[;]? (Streak|Aero|Venue|Venue Pro|Flash|Smoke|Mini 3iX)|XCD28|XCD35|\\b001DL\\b|\\b101DL\\b|\\bGS01\\b","Motorola":"Motorola|DROIDX|DROID BIONIC|\\bDroid\\b.*Build|Android.*Xoom|HRI39|MOT-|A1260|A1680|A555|A853|A855|A953|A955|A956|Motorola.*ELECTRIFY|Motorola.*i1|i867|i940|MB200|MB300|MB501|MB502|MB508|MB511|MB520|MB525|MB526|MB611|MB612|MB632|MB810|MB855|MB860|MB861|MB865|MB870|ME501|ME502|ME511|ME525|ME600|ME632|ME722|ME811|ME860|ME863|ME865|MT620|MT710|MT716|MT720|MT810|MT870|MT917|Motorola.*TITANIUM|WX435|WX445|XT300|XT301|XT311|XT316|XT317|XT319|XT320|XT390|XT502|XT530|XT531|XT532|XT535|XT603|XT610|XT611|XT615|XT681|XT701|XT702|XT711|XT720|XT800|XT806|XT860|XT862|XT875|XT882|XT883|XT894|XT901|XT907|XT909|XT910|XT912|XT928|XT926|XT915|XT919|XT925|XT1021|\\bMoto E\\b|XT1068|XT1092|XT1052","Samsung":"\\bSamsung\\b|SM-G950F|SM-G955F|SM-G9250|GT-19300|SGH-I337|BGT-S5230|GT-B2100|GT-B2700|GT-B2710|GT-B3210|GT-B3310|GT-B3410|GT-B3730|GT-B3740|GT-B5510|GT-B5512|GT-B5722|GT-B6520|GT-B7300|GT-B7320|GT-B7330|GT-B7350|GT-B7510|GT-B7722|GT-B7800|GT-C3010|GT-C3011|GT-C3060|GT-C3200|GT-C3212|GT-C3212I|GT-C3262|GT-C3222|GT-C3300|GT-C3300K|GT-C3303|GT-C3303K|GT-C3310|GT-C3322|GT-C3330|GT-C3350|GT-C3500|GT-C3510|GT-C3530|GT-C3630|GT-C3780|GT-C5010|GT-C5212|GT-C6620|GT-C6625|GT-C6712|GT-E1050|GT-E1070|GT-E1075|GT-E1080|GT-E1081|GT-E1085|GT-E1087|GT-E1100|GT-E1107|GT-E1110|GT-E1120|GT-E1125|GT-E1130|GT-E1160|GT-E1170|GT-E1175|GT-E1180|GT-E1182|GT-E1200|GT-E1210|GT-E1225|GT-E1230|GT-E1390|GT-E2100|GT-E2120|GT-E2121|GT-E2152|GT-E2220|GT-E2222|GT-E2230|GT-E2232|GT-E2250|GT-E2370|GT-E2550|GT-E2652|GT-E3210|GT-E3213|GT-I5500|GT-I5503|GT-I5700|GT-I5800|GT-I5801|GT-I6410|GT-I6420|GT-I7110|GT-I7410|GT-I7500|GT-I8000|GT-I8150|GT-I8160|GT-I8190|GT-I8320|GT-I8330|GT-I8350|GT-I8530|GT-I8700|GT-I8703|GT-I8910|GT-I9000|GT-I9001|GT-I9003|GT-I9010|GT-I9020|GT-I9023|GT-I9070|GT-I9082|GT-I9100|GT-I9103|GT-I9220|GT-I9250|GT-I9300|GT-I9305|GT-I9500|GT-I9505|GT-M3510|GT-M5650|GT-M7500|GT-M7600|GT-M7603|GT-M8800|GT-M8910|GT-N7000|GT-S3110|GT-S3310|GT-S3350|GT-S3353|GT-S3370|GT-S3650|GT-S3653|GT-S3770|GT-S3850|GT-S5210|GT-S5220|GT-S5229|GT-S5230|GT-S5233|GT-S5250|GT-S5253|GT-S5260|GT-S5263|GT-S5270|GT-S5300|GT-S5330|GT-S5350|GT-S5360|GT-S5363|GT-S5369|GT-S5380|GT-S5380D|GT-S5560|GT-S5570|GT-S5600|GT-S5603|GT-S5610|GT-S5620|GT-S5660|GT-S5670|GT-S5690|GT-S5750|GT-S5780|GT-S5830|GT-S5839|GT-S6102|GT-S6500|GT-S7070|GT-S7200|GT-S7220|GT-S7230|GT-S7233|GT-S7250|GT-S7500|GT-S7530|GT-S7550|GT-S7562|GT-S7710|GT-S8000|GT-S8003|GT-S8500|GT-S8530|GT-S8600|SCH-A310|SCH-A530|SCH-A570|SCH-A610|SCH-A630|SCH-A650|SCH-A790|SCH-A795|SCH-A850|SCH-A870|SCH-A890|SCH-A930|SCH-A950|SCH-A970|SCH-A990|SCH-I100|SCH-I110|SCH-I400|SCH-I405|SCH-I500|SCH-I510|SCH-I515|SCH-I600|SCH-I730|SCH-I760|SCH-I770|SCH-I830|SCH-I910|SCH-I920|SCH-I959|SCH-LC11|SCH-N150|SCH-N300|SCH-R100|SCH-R300|SCH-R351|SCH-R400|SCH-R410|SCH-T300|SCH-U310|SCH-U320|SCH-U350|SCH-U360|SCH-U365|SCH-U370|SCH-U380|SCH-U410|SCH-U430|SCH-U450|SCH-U460|SCH-U470|SCH-U490|SCH-U540|SCH-U550|SCH-U620|SCH-U640|SCH-U650|SCH-U660|SCH-U700|SCH-U740|SCH-U750|SCH-U810|SCH-U820|SCH-U900|SCH-U940|SCH-U960|SCS-26UC|SGH-A107|SGH-A117|SGH-A127|SGH-A137|SGH-A157|SGH-A167|SGH-A177|SGH-A187|SGH-A197|SGH-A227|SGH-A237|SGH-A257|SGH-A437|SGH-A517|SGH-A597|SGH-A637|SGH-A657|SGH-A667|SGH-A687|SGH-A697|SGH-A707|SGH-A717|SGH-A727|SGH-A737|SGH-A747|SGH-A767|SGH-A777|SGH-A797|SGH-A817|SGH-A827|SGH-A837|SGH-A847|SGH-A867|SGH-A877|SGH-A887|SGH-A897|SGH-A927|SGH-B100|SGH-B130|SGH-B200|SGH-B220|SGH-C100|SGH-C110|SGH-C120|SGH-C130|SGH-C140|SGH-C160|SGH-C170|SGH-C180|SGH-C200|SGH-C207|SGH-C210|SGH-C225|SGH-C230|SGH-C417|SGH-C450|SGH-D307|SGH-D347|SGH-D357|SGH-D407|SGH-D415|SGH-D780|SGH-D807|SGH-D980|SGH-E105|SGH-E200|SGH-E315|SGH-E316|SGH-E317|SGH-E335|SGH-E590|SGH-E635|SGH-E715|SGH-E890|SGH-F300|SGH-F480|SGH-I200|SGH-I300|SGH-I320|SGH-I550|SGH-I577|SGH-I600|SGH-I607|SGH-I617|SGH-I627|SGH-I637|SGH-I677|SGH-I700|SGH-I717|SGH-I727|SGH-i747M|SGH-I777|SGH-I780|SGH-I827|SGH-I847|SGH-I857|SGH-I896|SGH-I897|SGH-I900|SGH-I907|SGH-I917|SGH-I927|SGH-I937|SGH-I997|SGH-J150|SGH-J200|SGH-L170|SGH-L700|SGH-M110|SGH-M150|SGH-M200|SGH-N105|SGH-N500|SGH-N600|SGH-N620|SGH-N625|SGH-N700|SGH-N710|SGH-P107|SGH-P207|SGH-P300|SGH-P310|SGH-P520|SGH-P735|SGH-P777|SGH-Q105|SGH-R210|SGH-R220|SGH-R225|SGH-S105|SGH-S307|SGH-T109|SGH-T119|SGH-T139|SGH-T209|SGH-T219|SGH-T229|SGH-T239|SGH-T249|SGH-T259|SGH-T309|SGH-T319|SGH-T329|SGH-T339|SGH-T349|SGH-T359|SGH-T369|SGH-T379|SGH-T409|SGH-T429|SGH-T439|SGH-T459|SGH-T469|SGH-T479|SGH-T499|SGH-T509|SGH-T519|SGH-T539|SGH-T559|SGH-T589|SGH-T609|SGH-T619|SGH-T629|SGH-T639|SGH-T659|SGH-T669|SGH-T679|SGH-T709|SGH-T719|SGH-T729|SGH-T739|SGH-T746|SGH-T749|SGH-T759|SGH-T769|SGH-T809|SGH-T819|SGH-T839|SGH-T919|SGH-T929|SGH-T939|SGH-T959|SGH-T989|SGH-U100|SGH-U200|SGH-U800|SGH-V205|SGH-V206|SGH-X100|SGH-X105|SGH-X120|SGH-X140|SGH-X426|SGH-X427|SGH-X475|SGH-X495|SGH-X497|SGH-X507|SGH-X600|SGH-X610|SGH-X620|SGH-X630|SGH-X700|SGH-X820|SGH-X890|SGH-Z130|SGH-Z150|SGH-Z170|SGH-ZX10|SGH-ZX20|SHW-M110|SPH-A120|SPH-A400|SPH-A420|SPH-A460|SPH-A500|SPH-A560|SPH-A600|SPH-A620|SPH-A660|SPH-A700|SPH-A740|SPH-A760|SPH-A790|SPH-A800|SPH-A820|SPH-A840|SPH-A880|SPH-A900|SPH-A940|SPH-A960|SPH-D600|SPH-D700|SPH-D710|SPH-D720|SPH-I300|SPH-I325|SPH-I330|SPH-I350|SPH-I500|SPH-I600|SPH-I700|SPH-L700|SPH-M100|SPH-M220|SPH-M240|SPH-M300|SPH-M305|SPH-M320|SPH-M330|SPH-M350|SPH-M360|SPH-M370|SPH-M380|SPH-M510|SPH-M540|SPH-M550|SPH-M560|SPH-M570|SPH-M580|SPH-M610|SPH-M620|SPH-M630|SPH-M800|SPH-M810|SPH-M850|SPH-M900|SPH-M910|SPH-M920|SPH-M930|SPH-N100|SPH-N200|SPH-N240|SPH-N300|SPH-N400|SPH-Z400|SWC-E100|SCH-i909|GT-N7100|GT-N7105|SCH-I535|SM-N900A|SGH-I317|SGH-T999L|GT-S5360B|GT-I8262|GT-S6802|GT-S6312|GT-S6310|GT-S5312|GT-S5310|GT-I9105|GT-I8510|GT-S6790N|SM-G7105|SM-N9005|GT-S5301|GT-I9295|GT-I9195|SM-C101|GT-S7392|GT-S7560|GT-B7610|GT-I5510|GT-S7582|GT-S7530E|GT-I8750|SM-G9006V|SM-G9008V|SM-G9009D|SM-G900A|SM-G900D|SM-G900F|SM-G900H|SM-G900I|SM-G900J|SM-G900K|SM-G900L|SM-G900M|SM-G900P|SM-G900R4|SM-G900S|SM-G900T|SM-G900V|SM-G900W8|SHV-E160K|SCH-P709|SCH-P729|SM-T2558|GT-I9205|SM-G9350|SM-J120F|SM-G920F|SM-G920V|SM-G930F|SM-N910C|SM-A310F|GT-I9190|SM-J500FN|SM-G903F|SM-J330F|SM-G610F|SM-G981B|SM-G892A|SM-A530F|SM-G988N","LG":"\\bLG\\b;|LG[- ]?(C800|C900|E400|E610|E900|E-900|F160|F180K|F180L|F180S|730|855|L160|LS740|LS840|LS970|LU6200|MS690|MS695|MS770|MS840|MS870|MS910|P500|P700|P705|VM696|AS680|AS695|AX840|C729|E970|GS505|272|C395|E739BK|E960|L55C|L75C|LS696|LS860|P769BK|P350|P500|P509|P870|UN272|US730|VS840|VS950|LN272|LN510|LS670|LS855|LW690|MN270|MN510|P509|P769|P930|UN200|UN270|UN510|UN610|US670|US740|US760|UX265|UX840|VN271|VN530|VS660|VS700|VS740|VS750|VS910|VS920|VS930|VX9200|VX11000|AX840A|LW770|P506|P925|P999|E612|D955|D802|MS323|M257)|LM-G710","Sony":"SonyST|SonyLT|SonyEricsson|SonyEricssonLT15iv|LT18i|E10i|LT28h|LT26w|SonyEricssonMT27i|C5303|C6902|C6903|C6906|C6943|D2533|SOV34|601SO|F8332","Asus":"Asus.*Galaxy|PadFone.*Mobile|ASUS_Z01QD","Xiaomi":"^(?!.*\\bx11\\b).*xiaomi.*$|POCOPHONE F1|\\bMI\\b 8|\\bMi\\b 10|Redmi Note 9S|Redmi 5A|Redmi Note 5A Prime|Redmi Note 7 Pro|N2G47H|M2001J2G|M2001J2I|M1805E10A|M2004J11G|M1902F1G|M2002J9G|M2004J19G|M2003J6A1G|M2012K11C","NokiaLumia":"Lumia [0-9]{3,4}","Micromax":"Micromax.*\\b(A210|A92|A88|A72|A111|A110Q|A115|A116|A110|A90S|A26|A51|A35|A54|A25|A27|A89|A68|A65|A57|A90)\\b","Palm":"PalmSource|Palm","Vertu":"Vertu|Vertu.*Ltd|Vertu.*Ascent|Vertu.*Ayxta|Vertu.*Constellation(F|Quest)?|Vertu.*Monika|Vertu.*Signature","Pantech":"PANTECH|IM-A850S|IM-A840S|IM-A830L|IM-A830K|IM-A830S|IM-A820L|IM-A810K|IM-A810S|IM-A800S|IM-T100K|IM-A725L|IM-A780L|IM-A775C|IM-A770K|IM-A760S|IM-A750K|IM-A740S|IM-A730S|IM-A720L|IM-A710K|IM-A690L|IM-A690S|IM-A650S|IM-A630K|IM-A600S|VEGA PTL21|PT003|P8010|ADR910L|P6030|P6020|P9070|P4100|P9060|P5000|CDM8992|TXT8045|ADR8995|IS11PT|P2030|P6010|P8000|PT002|IS06|CDM8999|P9050|PT001|TXT8040|P2020|P9020|P2000|P7040|P7000|C790","Fly":"IQ230|IQ444|IQ450|IQ440|IQ442|IQ441|IQ245|IQ256|IQ236|IQ255|IQ235|IQ245|IQ275|IQ240|IQ285|IQ280|IQ270|IQ260|IQ250","Wiko":"KITE 4G|HIGHWAY|GETAWAY|STAIRWAY|DARKSIDE|DARKFULL|DARKNIGHT|DARKMOON|SLIDE|WAX 4G|RAINBOW|BLOOM|SUNSET|GOA(?!nna)|LENNY|BARRY|IGGY|OZZY|CINK FIVE|CINK PEAX|CINK PEAX 2|CINK SLIM|CINK SLIM 2|CINK +|CINK KING|CINK PEAX|CINK SLIM|SUBLIM","iMobile":"i-mobile (IQ|i-STYLE|idea|ZAA|Hitz)","SimValley":"\\b(SP-80|XT-930|SX-340|XT-930|SX-310|SP-360|SP60|SPT-800|SP-120|SPT-800|SP-140|SPX-5|SPX-8|SP-100|SPX-8|SPX-12)\\b","Wolfgang":"AT-B24D|AT-AS50HD|AT-AS40W|AT-AS55HD|AT-AS45q2|AT-B26D|AT-AS50Q","Alcatel":"Alcatel","Nintendo":"Nintendo (3DS|Switch)","Amoi":"Amoi","INQ":"INQ","OnePlus":"ONEPLUS","GenericPhone":"Tapatalk|PDA;|SAGEM|\\bmmp\\b|pocket|\\bpsp\\b|symbian|Smartphone|smartfon|treo|up.browser|up.link|vodafone|\\bwap\\b|nokia|Series40|Series60|S60|SonyEricsson|N900|MAUI.*WAP.*Browser"},"tablets":{"iPad":"iPad|iPad.*Mobile","NexusTablet":"Android.*Nexus[\\s]+(7|9|10)","GoogleTablet":"Android.*Pixel C","SamsungTablet":"SAMSUNG.*Tablet|Galaxy.*Tab|SC-01C|GT-P1000|GT-P1003|GT-P1010|GT-P3105|GT-P6210|GT-P6800|GT-P6810|GT-P7100|GT-P7300|GT-P7310|GT-P7500|GT-P7510|SCH-I800|SCH-I815|SCH-I905|SGH-I957|SGH-I987|SGH-T849|SGH-T859|SGH-T869|SPH-P100|GT-P3100|GT-P3108|GT-P3110|GT-P5100|GT-P5110|GT-P6200|GT-P7320|GT-P7511|GT-N8000|GT-P8510|SGH-I497|SPH-P500|SGH-T779|SCH-I705|SCH-I915|GT-N8013|GT-P3113|GT-P5113|GT-P8110|GT-N8010|GT-N8005|GT-N8020|GT-P1013|GT-P6201|GT-P7501|GT-N5100|GT-N5105|GT-N5110|SHV-E140K|SHV-E140L|SHV-E140S|SHV-E150S|SHV-E230K|SHV-E230L|SHV-E230S|SHW-M180K|SHW-M180L|SHW-M180S|SHW-M180W|SHW-M300W|SHW-M305W|SHW-M380K|SHW-M380S|SHW-M380W|SHW-M430W|SHW-M480K|SHW-M480S|SHW-M480W|SHW-M485W|SHW-M486W|SHW-M500W|GT-I9228|SCH-P739|SCH-I925|GT-I9200|GT-P5200|GT-P5210|GT-P5210X|SM-T311|SM-T310|SM-T310X|SM-T210|SM-T210R|SM-T211|SM-P600|SM-P601|SM-P605|SM-P900|SM-P901|SM-T217|SM-T217A|SM-T217S|SM-P6000|SM-T3100|SGH-I467|XE500|SM-T110|GT-P5220|GT-I9200X|GT-N5110X|GT-N5120|SM-P905|SM-T111|SM-T2105|SM-T315|SM-T320|SM-T320X|SM-T321|SM-T520|SM-T525|SM-T530NU|SM-T230NU|SM-T330NU|SM-T900|XE500T1C|SM-P605V|SM-P905V|SM-T337V|SM-T537V|SM-T707V|SM-T807V|SM-P600X|SM-P900X|SM-T210X|SM-T230|SM-T230X|SM-T325|GT-P7503|SM-T531|SM-T330|SM-T530|SM-T705|SM-T705C|SM-T535|SM-T331|SM-T800|SM-T700|SM-T537|SM-T807|SM-P907A|SM-T337A|SM-T537A|SM-T707A|SM-T807A|SM-T237|SM-T807P|SM-P607T|SM-T217T|SM-T337T|SM-T807T|SM-T116NQ|SM-T116BU|SM-P550|SM-T350|SM-T550|SM-T9000|SM-P9000|SM-T705Y|SM-T805|GT-P3113|SM-T710|SM-T810|SM-T815|SM-T360|SM-T533|SM-T113|SM-T335|SM-T715|SM-T560|SM-T670|SM-T677|SM-T377|SM-T567|SM-T357T|SM-T555|SM-T561|SM-T713|SM-T719|SM-T813|SM-T819|SM-T580|SM-T355Y?|SM-T280|SM-T817A|SM-T820|SM-W700|SM-P580|SM-T587|SM-P350|SM-P555M|SM-P355M|SM-T113NU|SM-T815Y|SM-T585|SM-T285|SM-T825|SM-W708|SM-T835|SM-T830|SM-T837V|SM-T720|SM-T510|SM-T387V|SM-P610|SM-T290|SM-T515|SM-T590|SM-T595|SM-T725|SM-T817P|SM-P585N0|SM-T395|SM-T295|SM-T865|SM-P610N|SM-P615|SM-T970|SM-T380|SM-T5950|SM-T905|SM-T231|SM-T500|SM-T860|SM-T536","Kindle":"Kindle|Silk.*Accelerated|Android.*\\b(KFOT|KFTT|KFJWI|KFJWA|KFOTE|KFSOWI|KFTHWI|KFTHWA|KFAPWI|KFAPWA|WFJWAE|KFSAWA|KFSAWI|KFASWI|KFARWI|KFFOWI|KFGIWI|KFMEWI)\\b|Android.*Silk\/[0-9.]+ like Chrome\/[0-9.]+ (?!Mobile)","SurfaceTablet":"Windows NT [0-9.]+; ARM;.*(Tablet|ARMBJS)","HPTablet":"HP Slate (7|8|10)|HP ElitePad 900|hp-tablet|EliteBook.*Touch|HP 8|Slate 21|HP SlateBook 10","AsusTablet":"^.*PadFone((?!Mobile).)*$|Transformer|TF101|TF101G|TF300T|TF300TG|TF300TL|TF700T|TF700KL|TF701T|TF810C|ME171|ME301T|ME302C|ME371MG|ME370T|ME372MG|ME172V|ME173X|ME400C|Slider SL101|\\bK00F\\b|\\bK00C\\b|\\bK00E\\b|\\bK00L\\b|TX201LA|ME176C|ME102A|\\bM80TA\\b|ME372CL|ME560CG|ME372CG|ME302KL| K01A | K010 | K011 | K017 | K01E |ME572C|ME103K|ME170C|ME171C|\\bME70C\\b|ME581C|ME581CL|ME8510C|ME181C|P01Y|PO1MA|P01Z|\\bP027\\b|\\bP024\\b|\\bP00C\\b","BlackBerryTablet":"PlayBook|RIM Tablet","HTCtablet":"HTC_Flyer_P512|HTC Flyer|HTC Jetstream|HTC-P715a|HTC EVO View 4G|PG41200|PG09410","MotorolaTablet":"xoom|sholest|MZ615|MZ605|MZ505|MZ601|MZ602|MZ603|MZ604|MZ606|MZ607|MZ608|MZ609|MZ615|MZ616|MZ617","NookTablet":"Android.*Nook|NookColor|nook browser|BNRV200|BNRV200A|BNTV250|BNTV250A|BNTV400|BNTV600|LogicPD Zoom2","AcerTablet":"Android.*; \\b(A100|A101|A110|A200|A210|A211|A500|A501|A510|A511|A700|A701|W500|W500P|W501|W501P|W510|W511|W700|G100|G100W|B1-A71|B1-710|B1-711|A1-810|A1-811|A1-830)\\b|W3-810|\\bA3-A10\\b|\\bA3-A11\\b|\\bA3-A20\\b|\\bA3-A30|A3-A40","ToshibaTablet":"Android.*(AT100|AT105|AT200|AT205|AT270|AT275|AT300|AT305|AT1S5|AT500|AT570|AT700|AT830)|TOSHIBA.*FOLIO","LGTablet":"\\bL-06C|LG-V909|LG-V900|LG-V700|LG-V510|LG-V500|LG-V410|LG-V400|LG-VK810\\b","FujitsuTablet":"Android.*\\b(F-01D|F-02F|F-05E|F-10D|M532|Q572)\\b","PrestigioTablet":"PMP3170B|PMP3270B|PMP3470B|PMP7170B|PMP3370B|PMP3570C|PMP5870C|PMP3670B|PMP5570C|PMP5770D|PMP3970B|PMP3870C|PMP5580C|PMP5880D|PMP5780D|PMP5588C|PMP7280C|PMP7280C3G|PMP7280|PMP7880D|PMP5597D|PMP5597|PMP7100D|PER3464|PER3274|PER3574|PER3884|PER5274|PER5474|PMP5097CPRO|PMP5097|PMP7380D|PMP5297C|PMP5297C_QUAD|PMP812E|PMP812E3G|PMP812F|PMP810E|PMP880TD|PMT3017|PMT3037|PMT3047|PMT3057|PMT7008|PMT5887|PMT5001|PMT5002","LenovoTablet":"Lenovo TAB|Idea(Tab|Pad)( A1|A10| K1|)|ThinkPad([ ]+)?Tablet|YT3-850M|YT3-X90L|YT3-X90F|YT3-X90X|Lenovo.*(S2109|S2110|S5000|S6000|K3011|A3000|A3500|A1000|A2107|A2109|A1107|A5500|A7600|B6000|B8000|B8080)(-|)(FL|F|HV|H|)|TB-X103F|TB-X304X|TB-X304F|TB-X304L|TB-X505F|TB-X505L|TB-X505X|TB-X605F|TB-X605L|TB-8703F|TB-8703X|TB-8703N|TB-8704N|TB-8704F|TB-8704X|TB-8704V|TB-7304F|TB-7304I|TB-7304X|Tab2A7-10F|Tab2A7-20F|TB2-X30L|YT3-X50L|YT3-X50F|YT3-X50M|YT-X705F|YT-X703F|YT-X703L|YT-X705L|YT-X705X|TB2-X30F|TB2-X30L|TB2-X30M|A2107A-F|A2107A-H|TB3-730F|TB3-730M|TB3-730X|TB-7504F|TB-7504X|TB-X704F|TB-X104F|TB3-X70F|TB-X705F|TB-8504F|TB3-X70L|TB3-710F|TB-X704L|TB-J606F|TB-X606F|TB-X306X","DellTablet":"Venue 11|Venue 8|Venue 7|Dell Streak 10|Dell Streak 7","XiaomiTablet":"21051182G","YarvikTablet":"Android.*\\b(TAB210|TAB211|TAB224|TAB250|TAB260|TAB264|TAB310|TAB360|TAB364|TAB410|TAB411|TAB420|TAB424|TAB450|TAB460|TAB461|TAB464|TAB465|TAB467|TAB468|TAB07-100|TAB07-101|TAB07-150|TAB07-151|TAB07-152|TAB07-200|TAB07-201-3G|TAB07-210|TAB07-211|TAB07-212|TAB07-214|TAB07-220|TAB07-400|TAB07-485|TAB08-150|TAB08-200|TAB08-201-3G|TAB08-201-30|TAB09-100|TAB09-211|TAB09-410|TAB10-150|TAB10-201|TAB10-211|TAB10-400|TAB10-410|TAB13-201|TAB274EUK|TAB275EUK|TAB374EUK|TAB462EUK|TAB474EUK|TAB9-200)\\b","MedionTablet":"Android.*\\bOYO\\b|LIFE.*(P9212|P9514|P9516|S9512)|LIFETAB","ArnovaTablet":"97G4|AN10G2|AN7bG3|AN7fG3|AN8G3|AN8cG3|AN7G3|AN9G3|AN7dG3|AN7dG3ST|AN7dG3ChildPad|AN10bG3|AN10bG3DT|AN9G2","IntensoTablet":"INM8002KP|INM1010FP|INM805ND|Intenso Tab|TAB1004","IRUTablet":"M702pro","MegafonTablet":"MegaFon V9|\\bZTE V9\\b|Android.*\\bMT7A\\b","EbodaTablet":"E-Boda (Supreme|Impresspeed|Izzycomm|Essential)","AllViewTablet":"Allview.*(Viva|Alldro|City|Speed|All TV|Frenzy|Quasar|Shine|TX1|AX1|AX2)","ArchosTablet":"\\b(101G9|80G9|A101IT)\\b|Qilive 97R|Archos5|\\bARCHOS (70|79|80|90|97|101|FAMILYPAD|)(b|c|)(G10| Cobalt| TITANIUM(HD|)| Xenon| Neon|XSK| 2| XS 2| PLATINUM| CARBON|GAMEPAD)\\b","AinolTablet":"NOVO7|NOVO8|NOVO10|Novo7Aurora|Novo7Basic|NOVO7PALADIN|novo9-Spark","NokiaLumiaTablet":"Lumia 2520","SonyTablet":"Sony.*Tablet|Xperia Tablet|Sony Tablet S|SO-03E|SGPT12|SGPT13|SGPT114|SGPT121|SGPT122|SGPT123|SGPT111|SGPT112|SGPT113|SGPT131|SGPT132|SGPT133|SGPT211|SGPT212|SGPT213|SGP311|SGP312|SGP321|EBRD1101|EBRD1102|EBRD1201|SGP351|SGP341|SGP511|SGP512|SGP521|SGP541|SGP551|SGP621|SGP641|SGP612|SOT31|SGP771|SGP611|SGP612|SGP712","PhilipsTablet":"\\b(PI2010|PI3000|PI3100|PI3105|PI3110|PI3205|PI3210|PI3900|PI4010|PI7000|PI7100)\\b","CubeTablet":"Android.*(K8GT|U9GT|U10GT|U16GT|U17GT|U18GT|U19GT|U20GT|U23GT|U30GT)|CUBE U8GT","CobyTablet":"MID1042|MID1045|MID1125|MID1126|MID7012|MID7014|MID7015|MID7034|MID7035|MID7036|MID7042|MID7048|MID7127|MID8042|MID8048|MID8127|MID9042|MID9740|MID9742|MID7022|MID7010","MIDTablet":"M9701|M9000|M9100|M806|M1052|M806|T703|MID701|MID713|MID710|MID727|MID760|MID830|MID728|MID933|MID125|MID810|MID732|MID120|MID930|MID800|MID731|MID900|MID100|MID820|MID735|MID980|MID130|MID833|MID737|MID960|MID135|MID860|MID736|MID140|MID930|MID835|MID733|MID4X10","MSITablet":"MSI \\b(Primo 73K|Primo 73L|Primo 81L|Primo 77|Primo 93|Primo 75|Primo 76|Primo 73|Primo 81|Primo 91|Primo 90|Enjoy 71|Enjoy 7|Enjoy 10)\\b","SMiTTablet":"Android.*(\\bMID\\b|MID-560|MTV-T1200|MTV-PND531|MTV-P1101|MTV-PND530)","RockChipTablet":"Android.*(RK2818|RK2808A|RK2918|RK3066)|RK2738|RK2808A","FlyTablet":"IQ310|Fly Vision","bqTablet":"Android.*(bq)?.*\\b(Elcano|Curie|Edison|Maxwell|Kepler|Pascal|Tesla|Hypatia|Platon|Newton|Livingstone|Cervantes|Avant|Aquaris ([E|M]10|M8))\\b|Maxwell.*Lite|Maxwell.*Plus","HuaweiTablet":"MediaPad|MediaPad 7 Youth|IDEOS S7|S7-201c|S7-202u|S7-101|S7-103|S7-104|S7-105|S7-106|S7-201|S7-Slim|M2-A01L|BAH-L09|BAH-W09|AGS-L09|CMR-AL19|KOB2-L09","NecTablet":"\\bN-06D|\\bN-08D","PantechTablet":"Pantech.*P4100","BronchoTablet":"Broncho.*(N701|N708|N802|a710)","VersusTablet":"TOUCHPAD.*[78910]|\\bTOUCHTAB\\b","ZyncTablet":"z1000|Z99 2G|z930|z990|z909|Z919|z900","PositivoTablet":"TB07STA|TB10STA|TB07FTA|TB10FTA","NabiTablet":"Android.*\\bNabi","KoboTablet":"Kobo Touch|\\bK080\\b|\\bVox\\b Build|\\bArc\\b Build","DanewTablet":"DSlide.*\\b(700|701R|702|703R|704|802|970|971|972|973|974|1010|1012)\\b","TexetTablet":"NaviPad|TB-772A|TM-7045|TM-7055|TM-9750|TM-7016|TM-7024|TM-7026|TM-7041|TM-7043|TM-7047|TM-8041|TM-9741|TM-9747|TM-9748|TM-9751|TM-7022|TM-7021|TM-7020|TM-7011|TM-7010|TM-7023|TM-7025|TM-7037W|TM-7038W|TM-7027W|TM-9720|TM-9725|TM-9737W|TM-1020|TM-9738W|TM-9740|TM-9743W|TB-807A|TB-771A|TB-727A|TB-725A|TB-719A|TB-823A|TB-805A|TB-723A|TB-715A|TB-707A|TB-705A|TB-709A|TB-711A|TB-890HD|TB-880HD|TB-790HD|TB-780HD|TB-770HD|TB-721HD|TB-710HD|TB-434HD|TB-860HD|TB-840HD|TB-760HD|TB-750HD|TB-740HD|TB-730HD|TB-722HD|TB-720HD|TB-700HD|TB-500HD|TB-470HD|TB-431HD|TB-430HD|TB-506|TB-504|TB-446|TB-436|TB-416|TB-146SE|TB-126SE","PlaystationTablet":"Playstation.*(Portable|Vita)","TrekstorTablet":"ST10416-1|VT10416-1|ST70408-1|ST702xx-1|ST702xx-2|ST80208|ST97216|ST70104-2|VT10416-2|ST10216-2A|SurfTab","PyleAudioTablet":"\\b(PTBL10CEU|PTBL10C|PTBL72BC|PTBL72BCEU|PTBL7CEU|PTBL7C|PTBL92BC|PTBL92BCEU|PTBL9CEU|PTBL9CUK|PTBL9C)\\b","AdvanTablet":"Android.* \\b(E3A|T3X|T5C|T5B|T3E|T3C|T3B|T1J|T1F|T2A|T1H|T1i|E1C|T1-E|T5-A|T4|E1-B|T2Ci|T1-B|T1-D|O1-A|E1-A|T1-A|T3A|T4i)\\b ","DanyTechTablet":"Genius Tab G3|Genius Tab S2|Genius Tab Q3|Genius Tab G4|Genius Tab Q4|Genius Tab G-II|Genius TAB GII|Genius TAB GIII|Genius Tab S1","GalapadTablet":"Android [0-9.]+; [a-z-]+; \\bG1\\b","MicromaxTablet":"Funbook|Micromax.*\\b(P250|P560|P360|P362|P600|P300|P350|P500|P275)\\b","KarbonnTablet":"Android.*\\b(A39|A37|A34|ST8|ST10|ST7|Smart Tab3|Smart Tab2)\\b","AllFineTablet":"Fine7 Genius|Fine7 Shine|Fine7 Air|Fine8 Style|Fine9 More|Fine10 Joy|Fine11 Wide","PROSCANTablet":"\\b(PEM63|PLT1023G|PLT1041|PLT1044|PLT1044G|PLT1091|PLT4311|PLT4311PL|PLT4315|PLT7030|PLT7033|PLT7033D|PLT7035|PLT7035D|PLT7044K|PLT7045K|PLT7045KB|PLT7071KG|PLT7072|PLT7223G|PLT7225G|PLT7777G|PLT7810K|PLT7849G|PLT7851G|PLT7852G|PLT8015|PLT8031|PLT8034|PLT8036|PLT8080K|PLT8082|PLT8088|PLT8223G|PLT8234G|PLT8235G|PLT8816K|PLT9011|PLT9045K|PLT9233G|PLT9735|PLT9760G|PLT9770G)\\b","YONESTablet":"BQ1078|BC1003|BC1077|RK9702|BC9730|BC9001|IT9001|BC7008|BC7010|BC708|BC728|BC7012|BC7030|BC7027|BC7026","ChangJiaTablet":"TPC7102|TPC7103|TPC7105|TPC7106|TPC7107|TPC7201|TPC7203|TPC7205|TPC7210|TPC7708|TPC7709|TPC7712|TPC7110|TPC8101|TPC8103|TPC8105|TPC8106|TPC8203|TPC8205|TPC8503|TPC9106|TPC9701|TPC97101|TPC97103|TPC97105|TPC97106|TPC97111|TPC97113|TPC97203|TPC97603|TPC97809|TPC97205|TPC10101|TPC10103|TPC10106|TPC10111|TPC10203|TPC10205|TPC10503","GUTablet":"TX-A1301|TX-M9002|Q702|kf026","PointOfViewTablet":"TAB-P506|TAB-navi-7-3G-M|TAB-P517|TAB-P-527|TAB-P701|TAB-P703|TAB-P721|TAB-P731N|TAB-P741|TAB-P825|TAB-P905|TAB-P925|TAB-PR945|TAB-PL1015|TAB-P1025|TAB-PI1045|TAB-P1325|TAB-PROTAB[0-9]+|TAB-PROTAB25|TAB-PROTAB26|TAB-PROTAB27|TAB-PROTAB26XL|TAB-PROTAB2-IPS9|TAB-PROTAB30-IPS9|TAB-PROTAB25XXL|TAB-PROTAB26-IPS10|TAB-PROTAB30-IPS10","OvermaxTablet":"OV-(SteelCore|NewBase|Basecore|Baseone|Exellen|Quattor|EduTab|Solution|ACTION|BasicTab|TeddyTab|MagicTab|Stream|TB-08|TB-09)|Qualcore 1027","HCLTablet":"HCL.*Tablet|Connect-3G-2.0|Connect-2G-2.0|ME Tablet U1|ME Tablet U2|ME Tablet G1|ME Tablet X1|ME Tablet Y2|ME Tablet Sync","DPSTablet":"DPS Dream 9|DPS Dual 7","VistureTablet":"V97 HD|i75 3G|Visture V4( HD)?|Visture V5( HD)?|Visture V10","CrestaTablet":"CTP(-)?810|CTP(-)?818|CTP(-)?828|CTP(-)?838|CTP(-)?888|CTP(-)?978|CTP(-)?980|CTP(-)?987|CTP(-)?988|CTP(-)?989","MediatekTablet":"\\bMT8125|MT8389|MT8135|MT8377\\b","ConcordeTablet":"Concorde([ ]+)?Tab|ConCorde ReadMan","GoCleverTablet":"GOCLEVER TAB|A7GOCLEVER|M1042|M7841|M742|R1042BK|R1041|TAB A975|TAB A7842|TAB A741|TAB A741L|TAB M723G|TAB M721|TAB A1021|TAB I921|TAB R721|TAB I720|TAB T76|TAB R70|TAB R76.2|TAB R106|TAB R83.2|TAB M813G|TAB I721|GCTA722|TAB I70|TAB I71|TAB S73|TAB R73|TAB R74|TAB R93|TAB R75|TAB R76.1|TAB A73|TAB A93|TAB A93.2|TAB T72|TAB R83|TAB R974|TAB R973|TAB A101|TAB A103|TAB A104|TAB A104.2|R105BK|M713G|A972BK|TAB A971|TAB R974.2|TAB R104|TAB R83.3|TAB A1042","ModecomTablet":"FreeTAB 9000|FreeTAB 7.4|FreeTAB 7004|FreeTAB 7800|FreeTAB 2096|FreeTAB 7.5|FreeTAB 1014|FreeTAB 1001 |FreeTAB 8001|FreeTAB 9706|FreeTAB 9702|FreeTAB 7003|FreeTAB 7002|FreeTAB 1002|FreeTAB 7801|FreeTAB 1331|FreeTAB 1004|FreeTAB 8002|FreeTAB 8014|FreeTAB 9704|FreeTAB 1003","VoninoTablet":"\\b(Argus[ _]?S|Diamond[ _]?79HD|Emerald[ _]?78E|Luna[ _]?70C|Onyx[ _]?S|Onyx[ _]?Z|Orin[ _]?HD|Orin[ _]?S|Otis[ _]?S|SpeedStar[ _]?S|Magnet[ _]?M9|Primus[ _]?94[ _]?3G|Primus[ _]?94HD|Primus[ _]?QS|Android.*\\bQ8\\b|Sirius[ _]?EVO[ _]?QS|Sirius[ _]?QS|Spirit[ _]?S)\\b","ECSTablet":"V07OT2|TM105A|S10OT1|TR10CS1","StorexTablet":"eZee[_']?(Tab|Go)[0-9]+|TabLC7|Looney Tunes Tab","VodafoneTablet":"SmartTab([ ]+)?[0-9]+|SmartTabII10|SmartTabII7|VF-1497|VFD 1400","EssentielBTablet":"Smart[ ']?TAB[ ]+?[0-9]+|Family[ ']?TAB2","RossMoorTablet":"RM-790|RM-997|RMD-878G|RMD-974R|RMT-705A|RMT-701|RME-601|RMT-501|RMT-711","iMobileTablet":"i-mobile i-note","TolinoTablet":"tolino tab [0-9.]+|tolino shine","AudioSonicTablet":"\\bC-22Q|T7-QC|T-17B|T-17P\\b","AMPETablet":"Android.* A78 ","SkkTablet":"Android.* (SKYPAD|PHOENIX|CYCLOPS)","TecnoTablet":"TECNO P9|TECNO DP8D","JXDTablet":"Android.* \\b(F3000|A3300|JXD5000|JXD3000|JXD2000|JXD300B|JXD300|S5800|S7800|S602b|S5110b|S7300|S5300|S602|S603|S5100|S5110|S601|S7100a|P3000F|P3000s|P101|P200s|P1000m|P200m|P9100|P1000s|S6600b|S908|P1000|P300|S18|S6600|S9100)\\b","iJoyTablet":"Tablet (Spirit 7|Essentia|Galatea|Fusion|Onix 7|Landa|Titan|Scooby|Deox|Stella|Themis|Argon|Unique 7|Sygnus|Hexen|Finity 7|Cream|Cream X2|Jade|Neon 7|Neron 7|Kandy|Scape|Saphyr 7|Rebel|Biox|Rebel|Rebel 8GB|Myst|Draco 7|Myst|Tab7-004|Myst|Tadeo Jones|Tablet Boing|Arrow|Draco Dual Cam|Aurix|Mint|Amity|Revolution|Finity 9|Neon 9|T9w|Amity 4GB Dual Cam|Stone 4GB|Stone 8GB|Andromeda|Silken|X2|Andromeda II|Halley|Flame|Saphyr 9,7|Touch 8|Planet|Triton|Unique 10|Hexen 10|Memphis 4GB|Memphis 8GB|Onix 10)","FX2Tablet":"FX2 PAD7|FX2 PAD10","XoroTablet":"KidsPAD 701|PAD[ ]?712|PAD[ ]?714|PAD[ ]?716|PAD[ ]?717|PAD[ ]?718|PAD[ ]?720|PAD[ ]?721|PAD[ ]?722|PAD[ ]?790|PAD[ ]?792|PAD[ ]?900|PAD[ ]?9715D|PAD[ ]?9716DR|PAD[ ]?9718DR|PAD[ ]?9719QR|PAD[ ]?9720QR|TelePAD1030|Telepad1032|TelePAD730|TelePAD731|TelePAD732|TelePAD735Q|TelePAD830|TelePAD9730|TelePAD795|MegaPAD 1331|MegaPAD 1851|MegaPAD 2151","ViewsonicTablet":"ViewPad 10pi|ViewPad 10e|ViewPad 10s|ViewPad E72|ViewPad7|ViewPad E100|ViewPad 7e|ViewSonic VB733|VB100a","VerizonTablet":"QTAQZ3|QTAIR7|QTAQTZ3|QTASUN1|QTASUN2|QTAXIA1","OdysTablet":"LOOX|XENO10|ODYS[ -](Space|EVO|Xpress|NOON)|\\bXELIO\\b|Xelio10Pro|XELIO7PHONETAB|XELIO10EXTREME|XELIOPT2|NEO_QUAD10","CaptivaTablet":"CAPTIVA PAD","IconbitTablet":"NetTAB|NT-3702|NT-3702S|NT-3702S|NT-3603P|NT-3603P|NT-0704S|NT-0704S|NT-3805C|NT-3805C|NT-0806C|NT-0806C|NT-0909T|NT-0909T|NT-0907S|NT-0907S|NT-0902S|NT-0902S","TeclastTablet":"T98 4G|\\bP80\\b|\\bX90HD\\b|X98 Air|X98 Air 3G|\\bX89\\b|P80 3G|\\bX80h\\b|P98 Air|\\bX89HD\\b|P98 3G|\\bP90HD\\b|P89 3G|X98 3G|\\bP70h\\b|P79HD 3G|G18d 3G|\\bP79HD\\b|\\bP89s\\b|\\bA88\\b|\\bP10HD\\b|\\bP19HD\\b|G18 3G|\\bP78HD\\b|\\bA78\\b|\\bP75\\b|G17s 3G|G17h 3G|\\bP85t\\b|\\bP90\\b|\\bP11\\b|\\bP98t\\b|\\bP98HD\\b|\\bG18d\\b|\\bP85s\\b|\\bP11HD\\b|\\bP88s\\b|\\bA80HD\\b|\\bA80se\\b|\\bA10h\\b|\\bP89\\b|\\bP78s\\b|\\bG18\\b|\\bP85\\b|\\bA70h\\b|\\bA70\\b|\\bG17\\b|\\bP18\\b|\\bA80s\\b|\\bA11s\\b|\\bP88HD\\b|\\bA80h\\b|\\bP76s\\b|\\bP76h\\b|\\bP98\\b|\\bA10HD\\b|\\bP78\\b|\\bP88\\b|\\bA11\\b|\\bA10t\\b|\\bP76a\\b|\\bP76t\\b|\\bP76e\\b|\\bP85HD\\b|\\bP85a\\b|\\bP86\\b|\\bP75HD\\b|\\bP76v\\b|\\bA12\\b|\\bP75a\\b|\\bA15\\b|\\bP76Ti\\b|\\bP81HD\\b|\\bA10\\b|\\bT760VE\\b|\\bT720HD\\b|\\bP76\\b|\\bP73\\b|\\bP71\\b|\\bP72\\b|\\bT720SE\\b|\\bC520Ti\\b|\\bT760\\b|\\bT720VE\\b|T720-3GE|T720-WiFi","OndaTablet":"\\b(V975i|Vi30|VX530|V701|Vi60|V701s|Vi50|V801s|V719|Vx610w|VX610W|V819i|Vi10|VX580W|Vi10|V711s|V813|V811|V820w|V820|Vi20|V711|VI30W|V712|V891w|V972|V819w|V820w|Vi60|V820w|V711|V813s|V801|V819|V975s|V801|V819|V819|V818|V811|V712|V975m|V101w|V961w|V812|V818|V971|V971s|V919|V989|V116w|V102w|V973|Vi40)\\b[\\s]+|V10 \\b4G\\b","JaytechTablet":"TPC-PA762","BlaupunktTablet":"Endeavour 800NG|Endeavour 1010","DigmaTablet":"\\b(iDx10|iDx9|iDx8|iDx7|iDxD7|iDxD8|iDsQ8|iDsQ7|iDsQ8|iDsD10|iDnD7|3TS804H|iDsQ11|iDj7|iDs10)\\b","EvolioTablet":"ARIA_Mini_wifi|Aria[ _]Mini|Evolio X10|Evolio X7|Evolio X8|\\bEvotab\\b|\\bNeura\\b","LavaTablet":"QPAD E704|\\bIvoryS\\b|E-TAB IVORY|\\bE-TAB\\b","AocTablet":"MW0811|MW0812|MW0922|MTK8382|MW1031|MW0831|MW0821|MW0931|MW0712","MpmanTablet":"MP11 OCTA|MP10 OCTA|MPQC1114|MPQC1004|MPQC994|MPQC974|MPQC973|MPQC804|MPQC784|MPQC780|\\bMPG7\\b|MPDCG75|MPDCG71|MPDC1006|MP101DC|MPDC9000|MPDC905|MPDC706HD|MPDC706|MPDC705|MPDC110|MPDC100|MPDC99|MPDC97|MPDC88|MPDC8|MPDC77|MP709|MID701|MID711|MID170|MPDC703|MPQC1010","CelkonTablet":"CT695|CT888|CT[\\s]?910|CT7 Tab|CT9 Tab|CT3 Tab|CT2 Tab|CT1 Tab|C820|C720|\\bCT-1\\b","WolderTablet":"miTab \\b(DIAMOND|SPACE|BROOKLYN|NEO|FLY|MANHATTAN|FUNK|EVOLUTION|SKY|GOCAR|IRON|GENIUS|POP|MINT|EPSILON|BROADWAY|JUMP|HOP|LEGEND|NEW AGE|LINE|ADVANCE|FEEL|FOLLOW|LIKE|LINK|LIVE|THINK|FREEDOM|CHICAGO|CLEVELAND|BALTIMORE-GH|IOWA|BOSTON|SEATTLE|PHOENIX|DALLAS|IN 101|MasterChef)\\b","MediacomTablet":"M-MPI10C3G|M-SP10EG|M-SP10EGP|M-SP10HXAH|M-SP7HXAH|M-SP10HXBH|M-SP8HXAH|M-SP8MXA","MiTablet":"\\bMI PAD\\b|\\bHM NOTE 1W\\b","NibiruTablet":"Nibiru M1|Nibiru Jupiter One","NexoTablet":"NEXO NOVA|NEXO 10|NEXO AVIO|NEXO FREE|NEXO GO|NEXO EVO|NEXO 3G|NEXO SMART|NEXO KIDDO|NEXO MOBI","LeaderTablet":"TBLT10Q|TBLT10I|TBL-10WDKB|TBL-10WDKBO2013|TBL-W230V2|TBL-W450|TBL-W500|SV572|TBLT7I|TBA-AC7-8G|TBLT79|TBL-8W16|TBL-10W32|TBL-10WKB|TBL-W100","UbislateTablet":"UbiSlate[\\s]?7C","PocketBookTablet":"Pocketbook","KocasoTablet":"\\b(TB-1207)\\b","HisenseTablet":"\\b(F5281|E2371)\\b","Hudl":"Hudl HT7S3|Hudl 2","TelstraTablet":"T-Hub2","GenericTablet":"Android.*\\b97D\\b|Tablet(?!.*PC)|BNTV250A|MID-WCDMA|LogicPD Zoom2|\\bA7EB\\b|CatNova8|A1_07|CT704|CT1002|\\bM721\\b|rk30sdk|\\bEVOTAB\\b|M758A|ET904|ALUMIUM10|Smartfren Tab|Endeavour 1010|Tablet-PC-4|Tagi Tab|\\bM6pro\\b|CT1020W|arc 10HD|\\bTP750\\b|\\bQTAQZ3\\b|WVT101|TM1088|KT107"},"browsers":{"Chrome":"\\bCrMo\\b|CriOS.*Mobile|Android.*Chrome\/[.0-9]* Mobile","Dolfin":"\\bDolfin\\b","Opera":"Opera.*Mini|Opera.*Mobi|Android.*Opera|Mobile.*OPR\/[0-9.]+$|Coast\/[0-9.]+","Skyfire":"Skyfire","Edge":"EdgiOS.*Mobile|Mobile Safari\/[.0-9]* Edge","IE":"IEMobile|MSIEMobile","Firefox":"fennec|firefox.*maemo|(Mobile|Tablet).*Firefox|Firefox.*Mobile|FxiOS.*Mobile","Bolt":"bolt","TeaShark":"teashark","Blazer":"Blazer","Safari":"Version((?!\\bEdgiOS\\b).)*Mobile.*Safari|Safari.*Mobile|MobileSafari","WeChat":"\\bMicroMessenger\\b","UCBrowser":"UC.*Browser|UCWEB","baiduboxapp":"baiduboxapp","baidubrowser":"baidubrowser","DiigoBrowser":"DiigoBrowser","Mercury":"\\bMercury\\b","ObigoBrowser":"Obigo","NetFront":"NF-Browser","GenericBrowser":"NokiaBrowser|OviBrowser|OneBrowser|TwonkyBeamBrowser|SEMC.*Browser|FlyFlow|Minimo|NetFront|Novarra-Vision|MQQBrowser|MicroMessenger","PaleMoon":"Android.*PaleMoon|Mobile.*PaleMoon"},"os":{"AndroidOS":"Android","BlackBerryOS":"blackberry|\\bBB10\\b|rim tablet os","PalmOS":"PalmOS|avantgo|blazer|elaine|hiptop|palm|plucker|xiino","SymbianOS":"Symbian|SymbOS|Series60|Series40|SYB-[0-9]+|\\bS60\\b","WindowsMobileOS":"Windows CE.*(PPC|Smartphone|Mobile|[0-9]{3}x[0-9]{3})|Windows Mobile|Windows Phone [0-9.]+|WCE;","WindowsPhoneOS":"Windows Phone 10.0|Windows Phone 8.1|Windows Phone 8.0|Windows Phone OS|XBLWP7|ZuneWP7|Windows NT 6.[23]; ARM;","iOS":"\\biPhone.*Mobile|\\biPod|\\biPad|AppleCoreMedia","iPadOS":"CPU OS 13","SailfishOS":"Sailfish","MeeGoOS":"MeeGo","MaemoOS":"Maemo","JavaOS":"J2ME\/|\\bMIDP\\b|\\bCLDC\\b","webOS":"webOS|hpwOS","badaOS":"\\bBada\\b","BREWOS":"BREW"},"utilities":{"Bot":"Googlebot|facebookexternalhit|Google-AMPHTML|s~amp-validator|AdsBot-Google|Google Keyword Suggestion|Facebot|YandexBot|YandexMobileBot|bingbot|ia_archiver|AhrefsBot|Ezooms|GSLFbot|WBSearchBot|Twitterbot|TweetmemeBot|Twikle|PaperLiBot|Wotbox|UnwindFetchor|Exabot|MJ12bot|YandexImages|TurnitinBot|Pingdom|contentkingapp|AspiegelBot","MobileBot":"Googlebot-Mobile|AdsBot-Google-Mobile|YahooSeeker\/M1A1-R2D2","DesktopMode":"WPDesktop","TV":"SonyDTV|HbbTV","WebKit":"(webkit)[ \/]([\\w.]+)","Console":"\\b(Nintendo|Nintendo WiiU|Nintendo 3DS|Nintendo Switch|PLAYSTATION|Xbox)\\b","Watch":"SM-V700"}}}
\ No newline at end of file
<?php
/**
* Mobile Detect Library
* Motto: "Every business should have a mobile detection script to detect mobile readers"
*
* Mobile_Detect is a lightweight PHP class for detecting mobile devices (including tablets).
* It uses the User-Agent string combined with specific HTTP headers to detect the mobile environment.
*
* Homepage: http://mobiledetect.net
* GitHub: https://github.com/serbanghita/Mobile-Detect
* README: https://github.com/serbanghita/Mobile-Detect/blob/master/README.md
* CONTRIBUTING: https://github.com/serbanghita/Mobile-Detect/blob/master/docs/CONTRIBUTING.md
* KNOWN LIMITATIONS: https://github.com/serbanghita/Mobile-Detect/blob/master/docs/KNOWN_LIMITATIONS.md
* EXAMPLES: https://github.com/serbanghita/Mobile-Detect/wiki/Code-examples
*
* @license https://github.com/serbanghita/Mobile-Detect/blob/master/LICENSE
* @author Serban Ghita <serbanghita@gmail.com>
* @author Nick Ilyin <nick.ilyin@gmail.com>
* Original author: Victor Stanciu <vic.stanciu@gmail.com>
*
* @version 2.8.39
*
* Auto-generated isXXXX() magic methods.
* php -a examples/dump_magic_methods.php
*
* @method bool isiPhone()
* @method bool isBlackBerry()
* @method bool isPixel()
* @method bool isHTC()
* @method bool isNexus()
* @method bool isDell()
* @method bool isMotorola()
* @method bool isSamsung()
* @method bool isLG()
* @method bool isSony()
* @method bool isAsus()
* @method bool isXiaomi()
* @method bool isNokiaLumia()
* @method bool isMicromax()
* @method bool isPalm()
* @method bool isVertu()
* @method bool isPantech()
* @method bool isFly()
* @method bool isWiko()
* @method bool isiMobile()
* @method bool isSimValley()
* @method bool isWolfgang()
* @method bool isAlcatel()
* @method bool isNintendo()
* @method bool isAmoi()
* @method bool isINQ()
* @method bool isOnePlus()
* @method bool isGenericPhone()
* @method bool isiPad()
* @method bool isNexusTablet()
* @method bool isGoogleTablet()
* @method bool isSamsungTablet()
* @method bool isKindle()
* @method bool isSurfaceTablet()
* @method bool isHPTablet()
* @method bool isAsusTablet()
* @method bool isBlackBerryTablet()
* @method bool isHTCtablet()
* @method bool isMotorolaTablet()
* @method bool isNookTablet()
* @method bool isAcerTablet()
* @method bool isToshibaTablet()
* @method bool isLGTablet()
* @method bool isFujitsuTablet()
* @method bool isPrestigioTablet()
* @method bool isLenovoTablet()
* @method bool isDellTablet()
* @method bool isYarvikTablet()
* @method bool isMedionTablet()
* @method bool isArnovaTablet()
* @method bool isIntensoTablet()
* @method bool isIRUTablet()
* @method bool isMegafonTablet()
* @method bool isEbodaTablet()
* @method bool isAllViewTablet()
* @method bool isArchosTablet()
* @method bool isAinolTablet()
* @method bool isNokiaLumiaTablet()
* @method bool isSonyTablet()
* @method bool isPhilipsTablet()
* @method bool isCubeTablet()
* @method bool isCobyTablet()
* @method bool isMIDTablet()
* @method bool isMSITablet()
* @method bool isSMiTTablet()
* @method bool isRockChipTablet()
* @method bool isFlyTablet()
* @method bool isbqTablet()
* @method bool isHuaweiTablet()
* @method bool isNecTablet()
* @method bool isPantechTablet()
* @method bool isBronchoTablet()
* @method bool isVersusTablet()
* @method bool isZyncTablet()
* @method bool isPositivoTablet()
* @method bool isNabiTablet()
* @method bool isKoboTablet()
* @method bool isDanewTablet()
* @method bool isTexetTablet()
* @method bool isPlaystationTablet()
* @method bool isTrekstorTablet()
* @method bool isPyleAudioTablet()
* @method bool isAdvanTablet()
* @method bool isDanyTechTablet()
* @method bool isGalapadTablet()
* @method bool isMicromaxTablet()
* @method bool isKarbonnTablet()
* @method bool isAllFineTablet()
* @method bool isPROSCANTablet()
* @method bool isYONESTablet()
* @method bool isChangJiaTablet()
* @method bool isGUTablet()
* @method bool isPointOfViewTablet()
* @method bool isOvermaxTablet()
* @method bool isHCLTablet()
* @method bool isDPSTablet()
* @method bool isVistureTablet()
* @method bool isCrestaTablet()
* @method bool isMediatekTablet()
* @method bool isConcordeTablet()
* @method bool isGoCleverTablet()
* @method bool isModecomTablet()
* @method bool isVoninoTablet()
* @method bool isECSTablet()
* @method bool isStorexTablet()
* @method bool isVodafoneTablet()
* @method bool isEssentielBTablet()
* @method bool isRossMoorTablet()
* @method bool isiMobileTablet()
* @method bool isTolinoTablet()
* @method bool isAudioSonicTablet()
* @method bool isAMPETablet()
* @method bool isSkkTablet()
* @method bool isTecnoTablet()
* @method bool isJXDTablet()
* @method bool isiJoyTablet()
* @method bool isFX2Tablet()
* @method bool isXoroTablet()
* @method bool isViewsonicTablet()
* @method bool isVerizonTablet()
* @method bool isOdysTablet()
* @method bool isCaptivaTablet()
* @method bool isIconbitTablet()
* @method bool isTeclastTablet()
* @method bool isOndaTablet()
* @method bool isJaytechTablet()
* @method bool isBlaupunktTablet()
* @method bool isDigmaTablet()
* @method bool isEvolioTablet()
* @method bool isLavaTablet()
* @method bool isAocTablet()
* @method bool isMpmanTablet()
* @method bool isCelkonTablet()
* @method bool isWolderTablet()
* @method bool isMediacomTablet()
* @method bool isMiTablet()
* @method bool isNibiruTablet()
* @method bool isNexoTablet()
* @method bool isLeaderTablet()
* @method bool isUbislateTablet()
* @method bool isPocketBookTablet()
* @method bool isKocasoTablet()
* @method bool isHisenseTablet()
* @method bool isHudl()
* @method bool isTelstraTablet()
* @method bool isGenericTablet()
* @method bool isAndroidOS()
* @method bool isBlackBerryOS()
* @method bool isPalmOS()
* @method bool isSymbianOS()
* @method bool isWindowsMobileOS()
* @method bool isWindowsPhoneOS()
* @method bool isiOS()
* @method bool isiPadOS()
* @method bool isSailfishOS()
* @method bool isMeeGoOS()
* @method bool isMaemoOS()
* @method bool isJavaOS()
* @method bool iswebOS()
* @method bool isbadaOS()
* @method bool isBREWOS()
* @method bool isChrome()
* @method bool isDolfin()
* @method bool isOpera()
* @method bool isSkyfire()
* @method bool isEdge()
* @method bool isIE()
* @method bool isFirefox()
* @method bool isBolt()
* @method bool isTeaShark()
* @method bool isBlazer()
* @method bool isSafari()
* @method bool isWeChat()
* @method bool isUCBrowser()
* @method bool isbaiduboxapp()
* @method bool isbaidubrowser()
* @method bool isDiigoBrowser()
* @method bool isMercury()
* @method bool isObigoBrowser()
* @method bool isNetFront()
* @method bool isGenericBrowser()
* @method bool isPaleMoon()
* @method bool isBot()
* @method bool isMobileBot()
* @method bool isDesktopMode()
* @method bool isTV()
* @method bool isWebKit()
* @method bool isConsole()
* @method bool isWatch()
*/
class Mobile_Detect
{
/**
* Mobile detection type.
*
* @deprecated since version 2.6.9
*/
const DETECTION_TYPE_MOBILE = 'mobile';
/**
* Extended detection type.
*
* @deprecated since version 2.6.9
*/
const DETECTION_TYPE_EXTENDED = 'extended';
/**
* A frequently used regular expression to extract version #s.
*
* @deprecated since version 2.6.9
*/
const VER = '([\w._\+]+)';
/**
* Top-level device.
*/
const MOBILE_GRADE_A = 'A';
/**
* Mid-level device.
*/
const MOBILE_GRADE_B = 'B';
/**
* Low-level device.
*/
const MOBILE_GRADE_C = 'C';
/**
* Stores the version number of the current release.
*/
const VERSION = '2.8.39';
/**
* A type for the version() method indicating a string return value.
*/
const VERSION_TYPE_STRING = 'text';
/**
* A type for the version() method indicating a float return value.
*/
const VERSION_TYPE_FLOAT = 'float';
/**
* A cache for resolved matches
* @var array
*/
protected $cache = array();
/**
* The User-Agent HTTP header is stored in here.
* @var string
*/
protected $userAgent = null;
/**
* HTTP headers in the PHP-flavor. So HTTP_USER_AGENT and SERVER_SOFTWARE.
* @var array
*/
protected $httpHeaders = array();
/**
* CloudFront headers. E.g. CloudFront-Is-Desktop-Viewer, CloudFront-Is-Mobile-Viewer & CloudFront-Is-Tablet-Viewer.
* @var array
*/
protected $cloudfrontHeaders = array();
/**
* The matching Regex.
* This is good for debug.
* @var string
*/
protected $matchingRegex = null;
/**
* The matches extracted from the regex expression.
* This is good for debug.
*
* @var string
*/
protected $matchesArray = null;
/**
* The detection type, using self::DETECTION_TYPE_MOBILE or self::DETECTION_TYPE_EXTENDED.
*
* @deprecated since version 2.6.9
*
* @var string
*/
protected $detectionType = self::DETECTION_TYPE_MOBILE;
/**
* HTTP headers that trigger the 'isMobile' detection
* to be true.
*
* @var array
*/
protected static $mobileHeaders = array(
'HTTP_ACCEPT' => array('matches' => array(
// Opera Mini; @reference: http://dev.opera.com/articles/view/opera-binary-markup-language/
'application/x-obml2d',
// BlackBerry devices.
'application/vnd.rim.html',
'text/vnd.wap.wml',
'application/vnd.wap.xhtml+xml'
)),
'HTTP_X_WAP_PROFILE' => null,
'HTTP_X_WAP_CLIENTID' => null,
'HTTP_WAP_CONNECTION' => null,
'HTTP_PROFILE' => null,
// Reported by Opera on Nokia devices (eg. C3).
'HTTP_X_OPERAMINI_PHONE_UA' => null,
'HTTP_X_NOKIA_GATEWAY_ID' => null,
'HTTP_X_ORANGE_ID' => null,
'HTTP_X_VODAFONE_3GPDPCONTEXT' => null,
'HTTP_X_HUAWEI_USERID' => null,
// Reported by Windows Smartphones.
'HTTP_UA_OS' => null,
// Reported by Verizon, Vodafone proxy system.
'HTTP_X_MOBILE_GATEWAY' => null,
// Seen this on HTC Sensation. SensationXE_Beats_Z715e.
'HTTP_X_ATT_DEVICEID' => null,
// Seen this on a HTC.
'HTTP_UA_CPU' => array('matches' => array('ARM')),
);
/**
* List of mobile devices (phones).
*
* @var array
*/
protected static $phoneDevices = array(
'iPhone' => '\biPhone\b|\biPod\b', // |\biTunes
'BlackBerry' => 'BlackBerry|\bBB10\b|rim[0-9]+|\b(BBA100|BBB100|BBD100|BBE100|BBF100|STH100)\b-[0-9]+',
'Pixel' => '; \bPixel\b',
'HTC' => 'HTC|HTC.*(Sensation|Evo|Vision|Explorer|6800|8100|8900|A7272|S510e|C110e|Legend|Desire|T8282)|APX515CKT|Qtek9090|APA9292KT|HD_mini|Sensation.*Z710e|PG86100|Z715e|Desire.*(A8181|HD)|ADR6200|ADR6400L|ADR6425|001HT|Inspire 4G|Android.*\bEVO\b|T-Mobile G1|Z520m|Android [0-9.]+; Pixel',
'Nexus' => 'Nexus One|Nexus S|Galaxy.*Nexus|Android.*Nexus.*Mobile|Nexus 4|Nexus 5|Nexus 5X|Nexus 6',
// @todo: Is 'Dell Streak' a tablet or a phone? ;)
'Dell' => 'Dell[;]? (Streak|Aero|Venue|Venue Pro|Flash|Smoke|Mini 3iX)|XCD28|XCD35|\b001DL\b|\b101DL\b|\bGS01\b',
'Motorola' => 'Motorola|DROIDX|DROID BIONIC|\bDroid\b.*Build|Android.*Xoom|HRI39|MOT-|A1260|A1680|A555|A853|A855|A953|A955|A956|Motorola.*ELECTRIFY|Motorola.*i1|i867|i940|MB200|MB300|MB501|MB502|MB508|MB511|MB520|MB525|MB526|MB611|MB612|MB632|MB810|MB855|MB860|MB861|MB865|MB870|ME501|ME502|ME511|ME525|ME600|ME632|ME722|ME811|ME860|ME863|ME865|MT620|MT710|MT716|MT720|MT810|MT870|MT917|Motorola.*TITANIUM|WX435|WX445|XT300|XT301|XT311|XT316|XT317|XT319|XT320|XT390|XT502|XT530|XT531|XT532|XT535|XT603|XT610|XT611|XT615|XT681|XT701|XT702|XT711|XT720|XT800|XT806|XT860|XT862|XT875|XT882|XT883|XT894|XT901|XT907|XT909|XT910|XT912|XT928|XT926|XT915|XT919|XT925|XT1021|\bMoto E\b|XT1068|XT1092|XT1052',
'Samsung' => '\bSamsung\b|SM-G950F|SM-G955F|SM-G9250|GT-19300|SGH-I337|BGT-S5230|GT-B2100|GT-B2700|GT-B2710|GT-B3210|GT-B3310|GT-B3410|GT-B3730|GT-B3740|GT-B5510|GT-B5512|GT-B5722|GT-B6520|GT-B7300|GT-B7320|GT-B7330|GT-B7350|GT-B7510|GT-B7722|GT-B7800|GT-C3010|GT-C3011|GT-C3060|GT-C3200|GT-C3212|GT-C3212I|GT-C3262|GT-C3222|GT-C3300|GT-C3300K|GT-C3303|GT-C3303K|GT-C3310|GT-C3322|GT-C3330|GT-C3350|GT-C3500|GT-C3510|GT-C3530|GT-C3630|GT-C3780|GT-C5010|GT-C5212|GT-C6620|GT-C6625|GT-C6712|GT-E1050|GT-E1070|GT-E1075|GT-E1080|GT-E1081|GT-E1085|GT-E1087|GT-E1100|GT-E1107|GT-E1110|GT-E1120|GT-E1125|GT-E1130|GT-E1160|GT-E1170|GT-E1175|GT-E1180|GT-E1182|GT-E1200|GT-E1210|GT-E1225|GT-E1230|GT-E1390|GT-E2100|GT-E2120|GT-E2121|GT-E2152|GT-E2220|GT-E2222|GT-E2230|GT-E2232|GT-E2250|GT-E2370|GT-E2550|GT-E2652|GT-E3210|GT-E3213|GT-I5500|GT-I5503|GT-I5700|GT-I5800|GT-I5801|GT-I6410|GT-I6420|GT-I7110|GT-I7410|GT-I7500|GT-I8000|GT-I8150|GT-I8160|GT-I8190|GT-I8320|GT-I8330|GT-I8350|GT-I8530|GT-I8700|GT-I8703|GT-I8910|GT-I9000|GT-I9001|GT-I9003|GT-I9010|GT-I9020|GT-I9023|GT-I9070|GT-I9082|GT-I9100|GT-I9103|GT-I9220|GT-I9250|GT-I9300|GT-I9305|GT-I9500|GT-I9505|GT-M3510|GT-M5650|GT-M7500|GT-M7600|GT-M7603|GT-M8800|GT-M8910|GT-N7000|GT-S3110|GT-S3310|GT-S3350|GT-S3353|GT-S3370|GT-S3650|GT-S3653|GT-S3770|GT-S3850|GT-S5210|GT-S5220|GT-S5229|GT-S5230|GT-S5233|GT-S5250|GT-S5253|GT-S5260|GT-S5263|GT-S5270|GT-S5300|GT-S5330|GT-S5350|GT-S5360|GT-S5363|GT-S5369|GT-S5380|GT-S5380D|GT-S5560|GT-S5570|GT-S5600|GT-S5603|GT-S5610|GT-S5620|GT-S5660|GT-S5670|GT-S5690|GT-S5750|GT-S5780|GT-S5830|GT-S5839|GT-S6102|GT-S6500|GT-S7070|GT-S7200|GT-S7220|GT-S7230|GT-S7233|GT-S7250|GT-S7500|GT-S7530|GT-S7550|GT-S7562|GT-S7710|GT-S8000|GT-S8003|GT-S8500|GT-S8530|GT-S8600|SCH-A310|SCH-A530|SCH-A570|SCH-A610|SCH-A630|SCH-A650|SCH-A790|SCH-A795|SCH-A850|SCH-A870|SCH-A890|SCH-A930|SCH-A950|SCH-A970|SCH-A990|SCH-I100|SCH-I110|SCH-I400|SCH-I405|SCH-I500|SCH-I510|SCH-I515|SCH-I600|SCH-I730|SCH-I760|SCH-I770|SCH-I830|SCH-I910|SCH-I920|SCH-I959|SCH-LC11|SCH-N150|SCH-N300|SCH-R100|SCH-R300|SCH-R351|SCH-R400|SCH-R410|SCH-T300|SCH-U310|SCH-U320|SCH-U350|SCH-U360|SCH-U365|SCH-U370|SCH-U380|SCH-U410|SCH-U430|SCH-U450|SCH-U460|SCH-U470|SCH-U490|SCH-U540|SCH-U550|SCH-U620|SCH-U640|SCH-U650|SCH-U660|SCH-U700|SCH-U740|SCH-U750|SCH-U810|SCH-U820|SCH-U900|SCH-U940|SCH-U960|SCS-26UC|SGH-A107|SGH-A117|SGH-A127|SGH-A137|SGH-A157|SGH-A167|SGH-A177|SGH-A187|SGH-A197|SGH-A227|SGH-A237|SGH-A257|SGH-A437|SGH-A517|SGH-A597|SGH-A637|SGH-A657|SGH-A667|SGH-A687|SGH-A697|SGH-A707|SGH-A717|SGH-A727|SGH-A737|SGH-A747|SGH-A767|SGH-A777|SGH-A797|SGH-A817|SGH-A827|SGH-A837|SGH-A847|SGH-A867|SGH-A877|SGH-A887|SGH-A897|SGH-A927|SGH-B100|SGH-B130|SGH-B200|SGH-B220|SGH-C100|SGH-C110|SGH-C120|SGH-C130|SGH-C140|SGH-C160|SGH-C170|SGH-C180|SGH-C200|SGH-C207|SGH-C210|SGH-C225|SGH-C230|SGH-C417|SGH-C450|SGH-D307|SGH-D347|SGH-D357|SGH-D407|SGH-D415|SGH-D780|SGH-D807|SGH-D980|SGH-E105|SGH-E200|SGH-E315|SGH-E316|SGH-E317|SGH-E335|SGH-E590|SGH-E635|SGH-E715|SGH-E890|SGH-F300|SGH-F480|SGH-I200|SGH-I300|SGH-I320|SGH-I550|SGH-I577|SGH-I600|SGH-I607|SGH-I617|SGH-I627|SGH-I637|SGH-I677|SGH-I700|SGH-I717|SGH-I727|SGH-i747M|SGH-I777|SGH-I780|SGH-I827|SGH-I847|SGH-I857|SGH-I896|SGH-I897|SGH-I900|SGH-I907|SGH-I917|SGH-I927|SGH-I937|SGH-I997|SGH-J150|SGH-J200|SGH-L170|SGH-L700|SGH-M110|SGH-M150|SGH-M200|SGH-N105|SGH-N500|SGH-N600|SGH-N620|SGH-N625|SGH-N700|SGH-N710|SGH-P107|SGH-P207|SGH-P300|SGH-P310|SGH-P520|SGH-P735|SGH-P777|SGH-Q105|SGH-R210|SGH-R220|SGH-R225|SGH-S105|SGH-S307|SGH-T109|SGH-T119|SGH-T139|SGH-T209|SGH-T219|SGH-T229|SGH-T239|SGH-T249|SGH-T259|SGH-T309|SGH-T319|SGH-T329|SGH-T339|SGH-T349|SGH-T359|SGH-T369|SGH-T379|SGH-T409|SGH-T429|SGH-T439|SGH-T459|SGH-T469|SGH-T479|SGH-T499|SGH-T509|SGH-T519|SGH-T539|SGH-T559|SGH-T589|SGH-T609|SGH-T619|SGH-T629|SGH-T639|SGH-T659|SGH-T669|SGH-T679|SGH-T709|SGH-T719|SGH-T729|SGH-T739|SGH-T746|SGH-T749|SGH-T759|SGH-T769|SGH-T809|SGH-T819|SGH-T839|SGH-T919|SGH-T929|SGH-T939|SGH-T959|SGH-T989|SGH-U100|SGH-U200|SGH-U800|SGH-V205|SGH-V206|SGH-X100|SGH-X105|SGH-X120|SGH-X140|SGH-X426|SGH-X427|SGH-X475|SGH-X495|SGH-X497|SGH-X507|SGH-X600|SGH-X610|SGH-X620|SGH-X630|SGH-X700|SGH-X820|SGH-X890|SGH-Z130|SGH-Z150|SGH-Z170|SGH-ZX10|SGH-ZX20|SHW-M110|SPH-A120|SPH-A400|SPH-A420|SPH-A460|SPH-A500|SPH-A560|SPH-A600|SPH-A620|SPH-A660|SPH-A700|SPH-A740|SPH-A760|SPH-A790|SPH-A800|SPH-A820|SPH-A840|SPH-A880|SPH-A900|SPH-A940|SPH-A960|SPH-D600|SPH-D700|SPH-D710|SPH-D720|SPH-I300|SPH-I325|SPH-I330|SPH-I350|SPH-I500|SPH-I600|SPH-I700|SPH-L700|SPH-M100|SPH-M220|SPH-M240|SPH-M300|SPH-M305|SPH-M320|SPH-M330|SPH-M350|SPH-M360|SPH-M370|SPH-M380|SPH-M510|SPH-M540|SPH-M550|SPH-M560|SPH-M570|SPH-M580|SPH-M610|SPH-M620|SPH-M630|SPH-M800|SPH-M810|SPH-M850|SPH-M900|SPH-M910|SPH-M920|SPH-M930|SPH-N100|SPH-N200|SPH-N240|SPH-N300|SPH-N400|SPH-Z400|SWC-E100|SCH-i909|GT-N7100|GT-N7105|SCH-I535|SM-N900A|SGH-I317|SGH-T999L|GT-S5360B|GT-I8262|GT-S6802|GT-S6312|GT-S6310|GT-S5312|GT-S5310|GT-I9105|GT-I8510|GT-S6790N|SM-G7105|SM-N9005|GT-S5301|GT-I9295|GT-I9195|SM-C101|GT-S7392|GT-S7560|GT-B7610|GT-I5510|GT-S7582|GT-S7530E|GT-I8750|SM-G9006V|SM-G9008V|SM-G9009D|SM-G900A|SM-G900D|SM-G900F|SM-G900H|SM-G900I|SM-G900J|SM-G900K|SM-G900L|SM-G900M|SM-G900P|SM-G900R4|SM-G900S|SM-G900T|SM-G900V|SM-G900W8|SHV-E160K|SCH-P709|SCH-P729|SM-T2558|GT-I9205|SM-G9350|SM-J120F|SM-G920F|SM-G920V|SM-G930F|SM-N910C|SM-A310F|GT-I9190|SM-J500FN|SM-G903F|SM-J330F|SM-G610F|SM-G981B|SM-G892A|SM-A530F|SM-G988N',
'LG' => '\bLG\b;|LG[- ]?(C800|C900|E400|E610|E900|E-900|F160|F180K|F180L|F180S|730|855|L160|LS740|LS840|LS970|LU6200|MS690|MS695|MS770|MS840|MS870|MS910|P500|P700|P705|VM696|AS680|AS695|AX840|C729|E970|GS505|272|C395|E739BK|E960|L55C|L75C|LS696|LS860|P769BK|P350|P500|P509|P870|UN272|US730|VS840|VS950|LN272|LN510|LS670|LS855|LW690|MN270|MN510|P509|P769|P930|UN200|UN270|UN510|UN610|US670|US740|US760|UX265|UX840|VN271|VN530|VS660|VS700|VS740|VS750|VS910|VS920|VS930|VX9200|VX11000|AX840A|LW770|P506|P925|P999|E612|D955|D802|MS323|M257)|LM-G710',
'Sony' => 'SonyST|SonyLT|SonyEricsson|SonyEricssonLT15iv|LT18i|E10i|LT28h|LT26w|SonyEricssonMT27i|C5303|C6902|C6903|C6906|C6943|D2533|SOV34|601SO|F8332',
'Asus' => 'Asus.*Galaxy|PadFone.*Mobile|ASUS_Z01QD',
'Xiaomi' => '^(?!.*\bx11\b).*xiaomi.*$|POCOPHONE F1|\bMI\b 8|\bMi\b 10|Redmi Note 9S|Redmi 5A|Redmi Note 5A Prime|Redmi Note 7 Pro|N2G47H|M2001J2G|M2001J2I|M1805E10A|M2004J11G|M1902F1G|M2002J9G|M2004J19G|M2003J6A1G|M2012K11C',
'NokiaLumia' => 'Lumia [0-9]{3,4}',
// http://www.micromaxinfo.com/mobiles/smartphones
// Added because the codes might conflict with Acer Tablets.
'Micromax' => 'Micromax.*\b(A210|A92|A88|A72|A111|A110Q|A115|A116|A110|A90S|A26|A51|A35|A54|A25|A27|A89|A68|A65|A57|A90)\b',
// @todo Complete the regex.
'Palm' => 'PalmSource|Palm', // avantgo|blazer|elaine|hiptop|plucker|xiino ;
'Vertu' => 'Vertu|Vertu.*Ltd|Vertu.*Ascent|Vertu.*Ayxta|Vertu.*Constellation(F|Quest)?|Vertu.*Monika|Vertu.*Signature', // Just for fun ;)
// http://www.pantech.co.kr/en/prod/prodList.do?gbrand=VEGA (PANTECH)
// Most of the VEGA devices are legacy. PANTECH seem to be newer devices based on Android.
'Pantech' => 'PANTECH|IM-A850S|IM-A840S|IM-A830L|IM-A830K|IM-A830S|IM-A820L|IM-A810K|IM-A810S|IM-A800S|IM-T100K|IM-A725L|IM-A780L|IM-A775C|IM-A770K|IM-A760S|IM-A750K|IM-A740S|IM-A730S|IM-A720L|IM-A710K|IM-A690L|IM-A690S|IM-A650S|IM-A630K|IM-A600S|VEGA PTL21|PT003|P8010|ADR910L|P6030|P6020|P9070|P4100|P9060|P5000|CDM8992|TXT8045|ADR8995|IS11PT|P2030|P6010|P8000|PT002|IS06|CDM8999|P9050|PT001|TXT8040|P2020|P9020|P2000|P7040|P7000|C790',
// http://www.fly-phone.com/devices/smartphones/ ; Included only smartphones.
'Fly' => 'IQ230|IQ444|IQ450|IQ440|IQ442|IQ441|IQ245|IQ256|IQ236|IQ255|IQ235|IQ245|IQ275|IQ240|IQ285|IQ280|IQ270|IQ260|IQ250',
// http://fr.wikomobile.com
'Wiko' => 'KITE 4G|HIGHWAY|GETAWAY|STAIRWAY|DARKSIDE|DARKFULL|DARKNIGHT|DARKMOON|SLIDE|WAX 4G|RAINBOW|BLOOM|SUNSET|GOA(?!nna)|LENNY|BARRY|IGGY|OZZY|CINK FIVE|CINK PEAX|CINK PEAX 2|CINK SLIM|CINK SLIM 2|CINK +|CINK KING|CINK PEAX|CINK SLIM|SUBLIM',
'iMobile' => 'i-mobile (IQ|i-STYLE|idea|ZAA|Hitz)',
// Added simvalley mobile just for fun. They have some interesting devices.
// http://www.simvalley.fr/telephonie---gps-_22_telephonie-mobile_telephones_.html
'SimValley' => '\b(SP-80|XT-930|SX-340|XT-930|SX-310|SP-360|SP60|SPT-800|SP-120|SPT-800|SP-140|SPX-5|SPX-8|SP-100|SPX-8|SPX-12)\b',
// Wolfgang - a brand that is sold by Aldi supermarkets.
// http://www.wolfgangmobile.com/
'Wolfgang' => 'AT-B24D|AT-AS50HD|AT-AS40W|AT-AS55HD|AT-AS45q2|AT-B26D|AT-AS50Q',
'Alcatel' => 'Alcatel',
'Nintendo' => 'Nintendo (3DS|Switch)',
// http://en.wikipedia.org/wiki/Amoi
'Amoi' => 'Amoi',
// http://en.wikipedia.org/wiki/INQ
'INQ' => 'INQ',
'OnePlus' => 'ONEPLUS',
// @Tapatalk is a mobile app; http://support.tapatalk.com/threads/smf-2-0-2-os-and-browser-detection-plugin-and-tapatalk.15565/#post-79039
'GenericPhone' => 'Tapatalk|PDA;|SAGEM|\bmmp\b|pocket|\bpsp\b|symbian|Smartphone|smartfon|treo|up.browser|up.link|vodafone|\bwap\b|nokia|Series40|Series60|S60|SonyEricsson|N900|MAUI.*WAP.*Browser',
);
/**
* List of tablet devices.
*
* @var array
*/
protected static $tabletDevices = array(
// @todo: check for mobile friendly emails topic.
'iPad' => 'iPad|iPad.*Mobile',
// Removed |^.*Android.*Nexus(?!(?:Mobile).)*$
// @see #442
// @todo Merge NexusTablet into GoogleTablet.
'NexusTablet' => 'Android.*Nexus[\s]+(7|9|10)',
// https://en.wikipedia.org/wiki/Pixel_C
'GoogleTablet' => 'Android.*Pixel C',
'SamsungTablet' => 'SAMSUNG.*Tablet|Galaxy.*Tab|SC-01C|GT-P1000|GT-P1003|GT-P1010|GT-P3105|GT-P6210|GT-P6800|GT-P6810|GT-P7100|GT-P7300|GT-P7310|GT-P7500|GT-P7510|SCH-I800|SCH-I815|SCH-I905|SGH-I957|SGH-I987|SGH-T849|SGH-T859|SGH-T869|SPH-P100|GT-P3100|GT-P3108|GT-P3110|GT-P5100|GT-P5110|GT-P6200|GT-P7320|GT-P7511|GT-N8000|GT-P8510|SGH-I497|SPH-P500|SGH-T779|SCH-I705|SCH-I915|GT-N8013|GT-P3113|GT-P5113|GT-P8110|GT-N8010|GT-N8005|GT-N8020|GT-P1013|GT-P6201|GT-P7501|GT-N5100|GT-N5105|GT-N5110|SHV-E140K|SHV-E140L|SHV-E140S|SHV-E150S|SHV-E230K|SHV-E230L|SHV-E230S|SHW-M180K|SHW-M180L|SHW-M180S|SHW-M180W|SHW-M300W|SHW-M305W|SHW-M380K|SHW-M380S|SHW-M380W|SHW-M430W|SHW-M480K|SHW-M480S|SHW-M480W|SHW-M485W|SHW-M486W|SHW-M500W|GT-I9228|SCH-P739|SCH-I925|GT-I9200|GT-P5200|GT-P5210|GT-P5210X|SM-T311|SM-T310|SM-T310X|SM-T210|SM-T210R|SM-T211|SM-P600|SM-P601|SM-P605|SM-P900|SM-P901|SM-T217|SM-T217A|SM-T217S|SM-P6000|SM-T3100|SGH-I467|XE500|SM-T110|GT-P5220|GT-I9200X|GT-N5110X|GT-N5120|SM-P905|SM-T111|SM-T2105|SM-T315|SM-T320|SM-T320X|SM-T321|SM-T520|SM-T525|SM-T530NU|SM-T230NU|SM-T330NU|SM-T900|XE500T1C|SM-P605V|SM-P905V|SM-T337V|SM-T537V|SM-T707V|SM-T807V|SM-P600X|SM-P900X|SM-T210X|SM-T230|SM-T230X|SM-T325|GT-P7503|SM-T531|SM-T330|SM-T530|SM-T705|SM-T705C|SM-T535|SM-T331|SM-T800|SM-T700|SM-T537|SM-T807|SM-P907A|SM-T337A|SM-T537A|SM-T707A|SM-T807A|SM-T237|SM-T807P|SM-P607T|SM-T217T|SM-T337T|SM-T807T|SM-T116NQ|SM-T116BU|SM-P550|SM-T350|SM-T550|SM-T9000|SM-P9000|SM-T705Y|SM-T805|GT-P3113|SM-T710|SM-T810|SM-T815|SM-T360|SM-T533|SM-T113|SM-T335|SM-T715|SM-T560|SM-T670|SM-T677|SM-T377|SM-T567|SM-T357T|SM-T555|SM-T561|SM-T713|SM-T719|SM-T813|SM-T819|SM-T580|SM-T355Y?|SM-T280|SM-T817A|SM-T820|SM-W700|SM-P580|SM-T587|SM-P350|SM-P555M|SM-P355M|SM-T113NU|SM-T815Y|SM-T585|SM-T285|SM-T825|SM-W708|SM-T835|SM-T830|SM-T837V|SM-T720|SM-T510|SM-T387V|SM-P610|SM-T290|SM-T515|SM-T590|SM-T595|SM-T725|SM-T817P|SM-P585N0|SM-T395|SM-T295|SM-T865|SM-P610N|SM-P615|SM-T970|SM-T380|SM-T5950|SM-T905|SM-T231|SM-T500|SM-T860|SM-T536', // SCH-P709|SCH-P729|SM-T2558|GT-I9205 - Samsung Mega - treat them like a regular phone.
// http://docs.aws.amazon.com/silk/latest/developerguide/user-agent.html
'Kindle' => 'Kindle|Silk.*Accelerated|Android.*\b(KFOT|KFTT|KFJWI|KFJWA|KFOTE|KFSOWI|KFTHWI|KFTHWA|KFAPWI|KFAPWA|WFJWAE|KFSAWA|KFSAWI|KFASWI|KFARWI|KFFOWI|KFGIWI|KFMEWI)\b|Android.*Silk/[0-9.]+ like Chrome/[0-9.]+ (?!Mobile)',
// Only the Surface tablets with Windows RT are considered mobile.
// http://msdn.microsoft.com/en-us/library/ie/hh920767(v=vs.85).aspx
'SurfaceTablet' => 'Windows NT [0-9.]+; ARM;.*(Tablet|ARMBJS)',
// http://shopping1.hp.com/is-bin/INTERSHOP.enfinity/WFS/WW-USSMBPublicStore-Site/en_US/-/USD/ViewStandardCatalog-Browse?CatalogCategoryID=JfIQ7EN5lqMAAAEyDcJUDwMT
'HPTablet' => 'HP Slate (7|8|10)|HP ElitePad 900|hp-tablet|EliteBook.*Touch|HP 8|Slate 21|HP SlateBook 10',
// Watch out for PadFone, see #132.
// http://www.asus.com/de/Tablets_Mobile/Memo_Pad_Products/
'AsusTablet' => '^.*PadFone((?!Mobile).)*$|Transformer|TF101|TF101G|TF300T|TF300TG|TF300TL|TF700T|TF700KL|TF701T|TF810C|ME171|ME301T|ME302C|ME371MG|ME370T|ME372MG|ME172V|ME173X|ME400C|Slider SL101|\bK00F\b|\bK00C\b|\bK00E\b|\bK00L\b|TX201LA|ME176C|ME102A|\bM80TA\b|ME372CL|ME560CG|ME372CG|ME302KL| K01A | K010 | K011 | K017 | K01E |ME572C|ME103K|ME170C|ME171C|\bME70C\b|ME581C|ME581CL|ME8510C|ME181C|P01Y|PO1MA|P01Z|\bP027\b|\bP024\b|\bP00C\b',
'BlackBerryTablet' => 'PlayBook|RIM Tablet',
'HTCtablet' => 'HTC_Flyer_P512|HTC Flyer|HTC Jetstream|HTC-P715a|HTC EVO View 4G|PG41200|PG09410',
'MotorolaTablet' => 'xoom|sholest|MZ615|MZ605|MZ505|MZ601|MZ602|MZ603|MZ604|MZ606|MZ607|MZ608|MZ609|MZ615|MZ616|MZ617',
'NookTablet' => 'Android.*Nook|NookColor|nook browser|BNRV200|BNRV200A|BNTV250|BNTV250A|BNTV400|BNTV600|LogicPD Zoom2',
// http://www.acer.ro/ac/ro/RO/content/drivers
// http://www.packardbell.co.uk/pb/en/GB/content/download (Packard Bell is part of Acer)
// http://us.acer.com/ac/en/US/content/group/tablets
// http://www.acer.de/ac/de/DE/content/models/tablets/
// Can conflict with Micromax and Motorola phones codes.
'AcerTablet' => 'Android.*; \b(A100|A101|A110|A200|A210|A211|A500|A501|A510|A511|A700|A701|W500|W500P|W501|W501P|W510|W511|W700|G100|G100W|B1-A71|B1-710|B1-711|A1-810|A1-811|A1-830)\b|W3-810|\bA3-A10\b|\bA3-A11\b|\bA3-A20\b|\bA3-A30|A3-A40',
// http://eu.computers.toshiba-europe.com/innovation/family/Tablets/1098744/banner_id/tablet_footerlink/
// http://us.toshiba.com/tablets/tablet-finder
// http://www.toshiba.co.jp/regza/tablet/
'ToshibaTablet' => 'Android.*(AT100|AT105|AT200|AT205|AT270|AT275|AT300|AT305|AT1S5|AT500|AT570|AT700|AT830)|TOSHIBA.*FOLIO',
// http://www.nttdocomo.co.jp/english/service/developer/smart_phone/technical_info/spec/index.html
// http://www.lg.com/us/tablets
'LGTablet' => '\bL-06C|LG-V909|LG-V900|LG-V700|LG-V510|LG-V500|LG-V410|LG-V400|LG-VK810\b',
'FujitsuTablet' => 'Android.*\b(F-01D|F-02F|F-05E|F-10D|M532|Q572)\b',
// Prestigio Tablets http://www.prestigio.com/support
'PrestigioTablet' => 'PMP3170B|PMP3270B|PMP3470B|PMP7170B|PMP3370B|PMP3570C|PMP5870C|PMP3670B|PMP5570C|PMP5770D|PMP3970B|PMP3870C|PMP5580C|PMP5880D|PMP5780D|PMP5588C|PMP7280C|PMP7280C3G|PMP7280|PMP7880D|PMP5597D|PMP5597|PMP7100D|PER3464|PER3274|PER3574|PER3884|PER5274|PER5474|PMP5097CPRO|PMP5097|PMP7380D|PMP5297C|PMP5297C_QUAD|PMP812E|PMP812E3G|PMP812F|PMP810E|PMP880TD|PMT3017|PMT3037|PMT3047|PMT3057|PMT7008|PMT5887|PMT5001|PMT5002',
// http://support.lenovo.com/en_GB/downloads/default.page?#
'LenovoTablet' => 'Lenovo TAB|Idea(Tab|Pad)( A1|A10| K1|)|ThinkPad([ ]+)?Tablet|YT3-850M|YT3-X90L|YT3-X90F|YT3-X90X|Lenovo.*(S2109|S2110|S5000|S6000|K3011|A3000|A3500|A1000|A2107|A2109|A1107|A5500|A7600|B6000|B8000|B8080)(-|)(FL|F|HV|H|)|TB-X103F|TB-X304X|TB-X304F|TB-X304L|TB-X505F|TB-X505L|TB-X505X|TB-X605F|TB-X605L|TB-8703F|TB-8703X|TB-8703N|TB-8704N|TB-8704F|TB-8704X|TB-8704V|TB-7304F|TB-7304I|TB-7304X|Tab2A7-10F|Tab2A7-20F|TB2-X30L|YT3-X50L|YT3-X50F|YT3-X50M|YT-X705F|YT-X703F|YT-X703L|YT-X705L|YT-X705X|TB2-X30F|TB2-X30L|TB2-X30M|A2107A-F|A2107A-H|TB3-730F|TB3-730M|TB3-730X|TB-7504F|TB-7504X|TB-X704F|TB-X104F|TB3-X70F|TB-X705F|TB-8504F|TB3-X70L|TB3-710F|TB-X704L|TB-J606F|TB-X606F|TB-X306X',
// http://www.dell.com/support/home/us/en/04/Products/tab_mob/tablets
'DellTablet' => 'Venue 11|Venue 8|Venue 7|Dell Streak 10|Dell Streak 7',
'XiaomiTablet' => '21051182G',
// http://www.yarvik.com/en/matrix/tablets/
'YarvikTablet' => 'Android.*\b(TAB210|TAB211|TAB224|TAB250|TAB260|TAB264|TAB310|TAB360|TAB364|TAB410|TAB411|TAB420|TAB424|TAB450|TAB460|TAB461|TAB464|TAB465|TAB467|TAB468|TAB07-100|TAB07-101|TAB07-150|TAB07-151|TAB07-152|TAB07-200|TAB07-201-3G|TAB07-210|TAB07-211|TAB07-212|TAB07-214|TAB07-220|TAB07-400|TAB07-485|TAB08-150|TAB08-200|TAB08-201-3G|TAB08-201-30|TAB09-100|TAB09-211|TAB09-410|TAB10-150|TAB10-201|TAB10-211|TAB10-400|TAB10-410|TAB13-201|TAB274EUK|TAB275EUK|TAB374EUK|TAB462EUK|TAB474EUK|TAB9-200)\b',
'MedionTablet' => 'Android.*\bOYO\b|LIFE.*(P9212|P9514|P9516|S9512)|LIFETAB',
'ArnovaTablet' => '97G4|AN10G2|AN7bG3|AN7fG3|AN8G3|AN8cG3|AN7G3|AN9G3|AN7dG3|AN7dG3ST|AN7dG3ChildPad|AN10bG3|AN10bG3DT|AN9G2',
// http://www.intenso.de/kategorie_en.php?kategorie=33
// @todo: http://www.nbhkdz.com/read/b8e64202f92a2df129126bff.html - investigate
'IntensoTablet' => 'INM8002KP|INM1010FP|INM805ND|Intenso Tab|TAB1004',
// IRU.ru Tablets http://www.iru.ru/catalog/soho/planetable/
'IRUTablet' => 'M702pro',
'MegafonTablet' => 'MegaFon V9|\bZTE V9\b|Android.*\bMT7A\b',
// http://www.e-boda.ro/tablete-pc.html
'EbodaTablet' => 'E-Boda (Supreme|Impresspeed|Izzycomm|Essential)',
// http://www.allview.ro/produse/droseries/lista-tablete-pc/
'AllViewTablet' => 'Allview.*(Viva|Alldro|City|Speed|All TV|Frenzy|Quasar|Shine|TX1|AX1|AX2)',
// http://wiki.archosfans.com/index.php?title=Main_Page
// @note Rewrite the regex format after we add more UAs.
'ArchosTablet' => '\b(101G9|80G9|A101IT)\b|Qilive 97R|Archos5|\bARCHOS (70|79|80|90|97|101|FAMILYPAD|)(b|c|)(G10| Cobalt| TITANIUM(HD|)| Xenon| Neon|XSK| 2| XS 2| PLATINUM| CARBON|GAMEPAD)\b',
// http://www.ainol.com/plugin.php?identifier=ainol&module=product
'AinolTablet' => 'NOVO7|NOVO8|NOVO10|Novo7Aurora|Novo7Basic|NOVO7PALADIN|novo9-Spark',
'NokiaLumiaTablet' => 'Lumia 2520',
// @todo: inspect http://esupport.sony.com/US/p/select-system.pl?DIRECTOR=DRIVER
// Readers http://www.atsuhiro-me.net/ebook/sony-reader/sony-reader-web-browser
// http://www.sony.jp/support/tablet/
'SonyTablet' => 'Sony.*Tablet|Xperia Tablet|Sony Tablet S|SO-03E|SGPT12|SGPT13|SGPT114|SGPT121|SGPT122|SGPT123|SGPT111|SGPT112|SGPT113|SGPT131|SGPT132|SGPT133|SGPT211|SGPT212|SGPT213|SGP311|SGP312|SGP321|EBRD1101|EBRD1102|EBRD1201|SGP351|SGP341|SGP511|SGP512|SGP521|SGP541|SGP551|SGP621|SGP641|SGP612|SOT31|SGP771|SGP611|SGP612|SGP712',
// http://www.support.philips.com/support/catalog/worldproducts.jsp?userLanguage=en&userCountry=cn&categoryid=3G_LTE_TABLET_SU_CN_CARE&title=3G%20tablets%20/%20LTE%20range&_dyncharset=UTF-8
'PhilipsTablet' => '\b(PI2010|PI3000|PI3100|PI3105|PI3110|PI3205|PI3210|PI3900|PI4010|PI7000|PI7100)\b',
// db + http://www.cube-tablet.com/buy-products.html
'CubeTablet' => 'Android.*(K8GT|U9GT|U10GT|U16GT|U17GT|U18GT|U19GT|U20GT|U23GT|U30GT)|CUBE U8GT',
// http://www.cobyusa.com/?p=pcat&pcat_id=3001
'CobyTablet' => 'MID1042|MID1045|MID1125|MID1126|MID7012|MID7014|MID7015|MID7034|MID7035|MID7036|MID7042|MID7048|MID7127|MID8042|MID8048|MID8127|MID9042|MID9740|MID9742|MID7022|MID7010',
// http://www.match.net.cn/products.asp
'MIDTablet' => 'M9701|M9000|M9100|M806|M1052|M806|T703|MID701|MID713|MID710|MID727|MID760|MID830|MID728|MID933|MID125|MID810|MID732|MID120|MID930|MID800|MID731|MID900|MID100|MID820|MID735|MID980|MID130|MID833|MID737|MID960|MID135|MID860|MID736|MID140|MID930|MID835|MID733|MID4X10',
// http://www.msi.com/support
// @todo Research the Windows Tablets.
'MSITablet' => 'MSI \b(Primo 73K|Primo 73L|Primo 81L|Primo 77|Primo 93|Primo 75|Primo 76|Primo 73|Primo 81|Primo 91|Primo 90|Enjoy 71|Enjoy 7|Enjoy 10)\b',
// @todo http://www.kyoceramobile.com/support/drivers/
// 'KyoceraTablet' => null,
// @todo http://intexuae.com/index.php/category/mobile-devices/tablets-products/
// 'IntextTablet' => null,
// http://pdadb.net/index.php?m=pdalist&list=SMiT (NoName Chinese Tablets)
// http://www.imp3.net/14/show.php?itemid=20454
'SMiTTablet' => 'Android.*(\bMID\b|MID-560|MTV-T1200|MTV-PND531|MTV-P1101|MTV-PND530)',
// http://www.rock-chips.com/index.php?do=prod&pid=2
'RockChipTablet' => 'Android.*(RK2818|RK2808A|RK2918|RK3066)|RK2738|RK2808A',
// http://www.fly-phone.com/devices/tablets/ ; http://www.fly-phone.com/service/
'FlyTablet' => 'IQ310|Fly Vision',
// http://www.bqreaders.com/gb/tablets-prices-sale.html
'bqTablet' => 'Android.*(bq)?.*\b(Elcano|Curie|Edison|Maxwell|Kepler|Pascal|Tesla|Hypatia|Platon|Newton|Livingstone|Cervantes|Avant|Aquaris ([E|M]10|M8))\b|Maxwell.*Lite|Maxwell.*Plus',
// http://www.huaweidevice.com/worldwide/productFamily.do?method=index&directoryId=5011&treeId=3290
// http://www.huaweidevice.com/worldwide/downloadCenter.do?method=index&directoryId=3372&treeId=0&tb=1&type=software (including legacy tablets)
'HuaweiTablet' => 'MediaPad|MediaPad 7 Youth|IDEOS S7|S7-201c|S7-202u|S7-101|S7-103|S7-104|S7-105|S7-106|S7-201|S7-Slim|M2-A01L|BAH-L09|BAH-W09|AGS-L09|CMR-AL19|KOB2-L09',
// Nec or Medias Tab
'NecTablet' => '\bN-06D|\bN-08D',
// Pantech Tablets: http://www.pantechusa.com/phones/
'PantechTablet' => 'Pantech.*P4100',
// Broncho Tablets: http://www.broncho.cn/ (hard to find)
'BronchoTablet' => 'Broncho.*(N701|N708|N802|a710)',
// http://versusuk.com/support.html
'VersusTablet' => 'TOUCHPAD.*[78910]|\bTOUCHTAB\b',
// http://www.zync.in/index.php/our-products/tablet-phablets
'ZyncTablet' => 'z1000|Z99 2G|z930|z990|z909|Z919|z900', // Removed "z999" because of https://github.com/serbanghita/Mobile-Detect/issues/717
// http://www.positivoinformatica.com.br/www/pessoal/tablet-ypy/
'PositivoTablet' => 'TB07STA|TB10STA|TB07FTA|TB10FTA',
// https://www.nabitablet.com/
'NabiTablet' => 'Android.*\bNabi',
'KoboTablet' => 'Kobo Touch|\bK080\b|\bVox\b Build|\bArc\b Build',
// French Danew Tablets http://www.danew.com/produits-tablette.php
'DanewTablet' => 'DSlide.*\b(700|701R|702|703R|704|802|970|971|972|973|974|1010|1012)\b',
// Texet Tablets and Readers http://www.texet.ru/tablet/
'TexetTablet' => 'NaviPad|TB-772A|TM-7045|TM-7055|TM-9750|TM-7016|TM-7024|TM-7026|TM-7041|TM-7043|TM-7047|TM-8041|TM-9741|TM-9747|TM-9748|TM-9751|TM-7022|TM-7021|TM-7020|TM-7011|TM-7010|TM-7023|TM-7025|TM-7037W|TM-7038W|TM-7027W|TM-9720|TM-9725|TM-9737W|TM-1020|TM-9738W|TM-9740|TM-9743W|TB-807A|TB-771A|TB-727A|TB-725A|TB-719A|TB-823A|TB-805A|TB-723A|TB-715A|TB-707A|TB-705A|TB-709A|TB-711A|TB-890HD|TB-880HD|TB-790HD|TB-780HD|TB-770HD|TB-721HD|TB-710HD|TB-434HD|TB-860HD|TB-840HD|TB-760HD|TB-750HD|TB-740HD|TB-730HD|TB-722HD|TB-720HD|TB-700HD|TB-500HD|TB-470HD|TB-431HD|TB-430HD|TB-506|TB-504|TB-446|TB-436|TB-416|TB-146SE|TB-126SE',
// Avoid detecting 'PLAYSTATION 3' as mobile.
'PlaystationTablet' => 'Playstation.*(Portable|Vita)',
// http://www.trekstor.de/surftabs.html
'TrekstorTablet' => 'ST10416-1|VT10416-1|ST70408-1|ST702xx-1|ST702xx-2|ST80208|ST97216|ST70104-2|VT10416-2|ST10216-2A|SurfTab',
// http://www.pyleaudio.com/Products.aspx?%2fproducts%2fPersonal-Electronics%2fTablets
'PyleAudioTablet' => '\b(PTBL10CEU|PTBL10C|PTBL72BC|PTBL72BCEU|PTBL7CEU|PTBL7C|PTBL92BC|PTBL92BCEU|PTBL9CEU|PTBL9CUK|PTBL9C)\b',
// http://www.advandigital.com/index.php?link=content-product&jns=JP001
// because of the short codenames we have to include whitespaces to reduce the possible conflicts.
'AdvanTablet' => 'Android.* \b(E3A|T3X|T5C|T5B|T3E|T3C|T3B|T1J|T1F|T2A|T1H|T1i|E1C|T1-E|T5-A|T4|E1-B|T2Ci|T1-B|T1-D|O1-A|E1-A|T1-A|T3A|T4i)\b ',
// http://www.danytech.com/category/tablet-pc
'DanyTechTablet' => 'Genius Tab G3|Genius Tab S2|Genius Tab Q3|Genius Tab G4|Genius Tab Q4|Genius Tab G-II|Genius TAB GII|Genius TAB GIII|Genius Tab S1',
// http://www.galapad.net/product.html ; https://github.com/serbanghita/Mobile-Detect/issues/761
'GalapadTablet' => 'Android [0-9.]+; [a-z-]+; \bG1\b',
// http://www.micromaxinfo.com/tablet/funbook
'MicromaxTablet' => 'Funbook|Micromax.*\b(P250|P560|P360|P362|P600|P300|P350|P500|P275)\b',
// http://www.karbonnmobiles.com/products_tablet.php
'KarbonnTablet' => 'Android.*\b(A39|A37|A34|ST8|ST10|ST7|Smart Tab3|Smart Tab2)\b',
// http://www.myallfine.com/Products.asp
'AllFineTablet' => 'Fine7 Genius|Fine7 Shine|Fine7 Air|Fine8 Style|Fine9 More|Fine10 Joy|Fine11 Wide',
// http://www.proscanvideo.com/products-search.asp?itemClass=TABLET&itemnmbr=
'PROSCANTablet' => '\b(PEM63|PLT1023G|PLT1041|PLT1044|PLT1044G|PLT1091|PLT4311|PLT4311PL|PLT4315|PLT7030|PLT7033|PLT7033D|PLT7035|PLT7035D|PLT7044K|PLT7045K|PLT7045KB|PLT7071KG|PLT7072|PLT7223G|PLT7225G|PLT7777G|PLT7810K|PLT7849G|PLT7851G|PLT7852G|PLT8015|PLT8031|PLT8034|PLT8036|PLT8080K|PLT8082|PLT8088|PLT8223G|PLT8234G|PLT8235G|PLT8816K|PLT9011|PLT9045K|PLT9233G|PLT9735|PLT9760G|PLT9770G)\b',
// http://www.yonesnav.com/products/products.php
'YONESTablet' => 'BQ1078|BC1003|BC1077|RK9702|BC9730|BC9001|IT9001|BC7008|BC7010|BC708|BC728|BC7012|BC7030|BC7027|BC7026',
// http://www.cjshowroom.com/eproducts.aspx?classcode=004001001
// China manufacturer makes tablets for different small brands (eg. http://www.zeepad.net/index.html)
'ChangJiaTablet' => 'TPC7102|TPC7103|TPC7105|TPC7106|TPC7107|TPC7201|TPC7203|TPC7205|TPC7210|TPC7708|TPC7709|TPC7712|TPC7110|TPC8101|TPC8103|TPC8105|TPC8106|TPC8203|TPC8205|TPC8503|TPC9106|TPC9701|TPC97101|TPC97103|TPC97105|TPC97106|TPC97111|TPC97113|TPC97203|TPC97603|TPC97809|TPC97205|TPC10101|TPC10103|TPC10106|TPC10111|TPC10203|TPC10205|TPC10503',
// http://www.gloryunion.cn/products.asp
// http://www.allwinnertech.com/en/apply/mobile.html
// http://www.ptcl.com.pk/pd_content.php?pd_id=284 (EVOTAB)
// @todo: Softwiner tablets?
// aka. Cute or Cool tablets. Not sure yet, must research to avoid collisions.
'GUTablet' => 'TX-A1301|TX-M9002|Q702|kf026', // A12R|D75A|D77|D79|R83|A95|A106C|R15|A75|A76|D71|D72|R71|R73|R77|D82|R85|D92|A97|D92|R91|A10F|A77F|W71F|A78F|W78F|W81F|A97F|W91F|W97F|R16G|C72|C73E|K72|K73|R96G
// http://www.pointofview-online.com/showroom.php?shop_mode=product_listing&category_id=118
'PointOfViewTablet' => 'TAB-P506|TAB-navi-7-3G-M|TAB-P517|TAB-P-527|TAB-P701|TAB-P703|TAB-P721|TAB-P731N|TAB-P741|TAB-P825|TAB-P905|TAB-P925|TAB-PR945|TAB-PL1015|TAB-P1025|TAB-PI1045|TAB-P1325|TAB-PROTAB[0-9]+|TAB-PROTAB25|TAB-PROTAB26|TAB-PROTAB27|TAB-PROTAB26XL|TAB-PROTAB2-IPS9|TAB-PROTAB30-IPS9|TAB-PROTAB25XXL|TAB-PROTAB26-IPS10|TAB-PROTAB30-IPS10',
// http://www.overmax.pl/pl/katalog-produktow,p8/tablety,c14/
// @todo: add more tests.
'OvermaxTablet' => 'OV-(SteelCore|NewBase|Basecore|Baseone|Exellen|Quattor|EduTab|Solution|ACTION|BasicTab|TeddyTab|MagicTab|Stream|TB-08|TB-09)|Qualcore 1027',
// http://hclmetablet.com/India/index.php
'HCLTablet' => 'HCL.*Tablet|Connect-3G-2.0|Connect-2G-2.0|ME Tablet U1|ME Tablet U2|ME Tablet G1|ME Tablet X1|ME Tablet Y2|ME Tablet Sync',
// http://www.edigital.hu/Tablet_es_e-book_olvaso/Tablet-c18385.html
'DPSTablet' => 'DPS Dream 9|DPS Dual 7',
// http://www.visture.com/index.asp
'VistureTablet' => 'V97 HD|i75 3G|Visture V4( HD)?|Visture V5( HD)?|Visture V10',
// http://www.mijncresta.nl/tablet
'CrestaTablet' => 'CTP(-)?810|CTP(-)?818|CTP(-)?828|CTP(-)?838|CTP(-)?888|CTP(-)?978|CTP(-)?980|CTP(-)?987|CTP(-)?988|CTP(-)?989',
// MediaTek - http://www.mediatek.com/_en/01_products/02_proSys.php?cata_sn=1&cata1_sn=1&cata2_sn=309
'MediatekTablet' => '\bMT8125|MT8389|MT8135|MT8377\b',
// Concorde tab
'ConcordeTablet' => 'Concorde([ ]+)?Tab|ConCorde ReadMan',
// GoClever Tablets - http://www.goclever.com/uk/products,c1/tablet,c5/
'GoCleverTablet' => 'GOCLEVER TAB|A7GOCLEVER|M1042|M7841|M742|R1042BK|R1041|TAB A975|TAB A7842|TAB A741|TAB A741L|TAB M723G|TAB M721|TAB A1021|TAB I921|TAB R721|TAB I720|TAB T76|TAB R70|TAB R76.2|TAB R106|TAB R83.2|TAB M813G|TAB I721|GCTA722|TAB I70|TAB I71|TAB S73|TAB R73|TAB R74|TAB R93|TAB R75|TAB R76.1|TAB A73|TAB A93|TAB A93.2|TAB T72|TAB R83|TAB R974|TAB R973|TAB A101|TAB A103|TAB A104|TAB A104.2|R105BK|M713G|A972BK|TAB A971|TAB R974.2|TAB R104|TAB R83.3|TAB A1042',
// Modecom Tablets - http://www.modecom.eu/tablets/portal/
'ModecomTablet' => 'FreeTAB 9000|FreeTAB 7.4|FreeTAB 7004|FreeTAB 7800|FreeTAB 2096|FreeTAB 7.5|FreeTAB 1014|FreeTAB 1001 |FreeTAB 8001|FreeTAB 9706|FreeTAB 9702|FreeTAB 7003|FreeTAB 7002|FreeTAB 1002|FreeTAB 7801|FreeTAB 1331|FreeTAB 1004|FreeTAB 8002|FreeTAB 8014|FreeTAB 9704|FreeTAB 1003',
// Vonino Tablets
'VoninoTablet' => '\b(Argus[ _]?S|Diamond[ _]?79HD|Emerald[ _]?78E|Luna[ _]?70C|Onyx[ _]?S|Onyx[ _]?Z|Orin[ _]?HD|Orin[ _]?S|Otis[ _]?S|SpeedStar[ _]?S|Magnet[ _]?M9|Primus[ _]?94[ _]?3G|Primus[ _]?94HD|Primus[ _]?QS|Android.*\bQ8\b|Sirius[ _]?EVO[ _]?QS|Sirius[ _]?QS|Spirit[ _]?S)\b',
// ECS Tablets - http://www.ecs.com.tw/ECSWebSite/Product/Product_Tablet_List.aspx?CategoryID=14&MenuID=107&childid=M_107&LanID=0
'ECSTablet' => 'V07OT2|TM105A|S10OT1|TR10CS1',
// Storex Tablets - http://storex.fr/espace_client/support.html
// @note: no need to add all the tablet codes since they are guided by the first regex.
'StorexTablet' => 'eZee[_\']?(Tab|Go)[0-9]+|TabLC7|Looney Tunes Tab',
// Generic Vodafone tablets.
'VodafoneTablet' => 'SmartTab([ ]+)?[0-9]+|SmartTabII10|SmartTabII7|VF-1497|VFD 1400',
// French tablets - Essentiel B http://www.boulanger.fr/tablette_tactile_e-book/tablette_tactile_essentiel_b/cl_68908.htm?multiChoiceToDelete=brand&mc_brand=essentielb
// Aka: http://www.essentielb.fr/
'EssentielBTablet' => 'Smart[ \']?TAB[ ]+?[0-9]+|Family[ \']?TAB2',
// Ross & Moor - http://ross-moor.ru/
'RossMoorTablet' => 'RM-790|RM-997|RMD-878G|RMD-974R|RMT-705A|RMT-701|RME-601|RMT-501|RMT-711',
// i-mobile http://product.i-mobilephone.com/Mobile_Device
'iMobileTablet' => 'i-mobile i-note',
// http://www.tolino.de/de/vergleichen/
'TolinoTablet' => 'tolino tab [0-9.]+|tolino shine',
// AudioSonic - a Kmart brand
// http://www.kmart.com.au/webapp/wcs/stores/servlet/Search?langId=-1&storeId=10701&catalogId=10001&categoryId=193001&pageSize=72&currentPage=1&searchCategory=193001%2b4294965664&sortBy=p_MaxPrice%7c1
'AudioSonicTablet' => '\bC-22Q|T7-QC|T-17B|T-17P\b',
// AMPE Tablets - http://www.ampe.com.my/product-category/tablets/
// @todo: add them gradually to avoid conflicts.
'AMPETablet' => 'Android.* A78 ',
// Skk Mobile - http://skkmobile.com.ph/product_tablets.php
'SkkTablet' => 'Android.* (SKYPAD|PHOENIX|CYCLOPS)',
// Tecno Mobile (only tablet) - http://www.tecno-mobile.com/index.php/product?filterby=smart&list_order=all&page=1
'TecnoTablet' => 'TECNO P9|TECNO DP8D',
// JXD (consoles & tablets) - http://jxd.hk/products.asp?selectclassid=009008&clsid=3
'JXDTablet' => 'Android.* \b(F3000|A3300|JXD5000|JXD3000|JXD2000|JXD300B|JXD300|S5800|S7800|S602b|S5110b|S7300|S5300|S602|S603|S5100|S5110|S601|S7100a|P3000F|P3000s|P101|P200s|P1000m|P200m|P9100|P1000s|S6600b|S908|P1000|P300|S18|S6600|S9100)\b',
// i-Joy tablets - http://www.i-joy.es/en/cat/products/tablets/
'iJoyTablet' => 'Tablet (Spirit 7|Essentia|Galatea|Fusion|Onix 7|Landa|Titan|Scooby|Deox|Stella|Themis|Argon|Unique 7|Sygnus|Hexen|Finity 7|Cream|Cream X2|Jade|Neon 7|Neron 7|Kandy|Scape|Saphyr 7|Rebel|Biox|Rebel|Rebel 8GB|Myst|Draco 7|Myst|Tab7-004|Myst|Tadeo Jones|Tablet Boing|Arrow|Draco Dual Cam|Aurix|Mint|Amity|Revolution|Finity 9|Neon 9|T9w|Amity 4GB Dual Cam|Stone 4GB|Stone 8GB|Andromeda|Silken|X2|Andromeda II|Halley|Flame|Saphyr 9,7|Touch 8|Planet|Triton|Unique 10|Hexen 10|Memphis 4GB|Memphis 8GB|Onix 10)',
// http://www.intracon.eu/tablet
'FX2Tablet' => 'FX2 PAD7|FX2 PAD10',
// http://www.xoro.de/produkte/
// @note: Might be the same brand with 'Simply tablets'
'XoroTablet' => 'KidsPAD 701|PAD[ ]?712|PAD[ ]?714|PAD[ ]?716|PAD[ ]?717|PAD[ ]?718|PAD[ ]?720|PAD[ ]?721|PAD[ ]?722|PAD[ ]?790|PAD[ ]?792|PAD[ ]?900|PAD[ ]?9715D|PAD[ ]?9716DR|PAD[ ]?9718DR|PAD[ ]?9719QR|PAD[ ]?9720QR|TelePAD1030|Telepad1032|TelePAD730|TelePAD731|TelePAD732|TelePAD735Q|TelePAD830|TelePAD9730|TelePAD795|MegaPAD 1331|MegaPAD 1851|MegaPAD 2151',
// http://www1.viewsonic.com/products/computing/tablets/
'ViewsonicTablet' => 'ViewPad 10pi|ViewPad 10e|ViewPad 10s|ViewPad E72|ViewPad7|ViewPad E100|ViewPad 7e|ViewSonic VB733|VB100a',
// https://www.verizonwireless.com/tablets/verizon/
'VerizonTablet' => 'QTAQZ3|QTAIR7|QTAQTZ3|QTASUN1|QTASUN2|QTAXIA1',
// http://www.odys.de/web/internet-tablet_en.html
'OdysTablet' => 'LOOX|XENO10|ODYS[ -](Space|EVO|Xpress|NOON)|\bXELIO\b|Xelio10Pro|XELIO7PHONETAB|XELIO10EXTREME|XELIOPT2|NEO_QUAD10',
// http://www.captiva-power.de/products.html#tablets-en
'CaptivaTablet' => 'CAPTIVA PAD',
// IconBIT - http://www.iconbit.com/products/tablets/
'IconbitTablet' => 'NetTAB|NT-3702|NT-3702S|NT-3702S|NT-3603P|NT-3603P|NT-0704S|NT-0704S|NT-3805C|NT-3805C|NT-0806C|NT-0806C|NT-0909T|NT-0909T|NT-0907S|NT-0907S|NT-0902S|NT-0902S',
// http://www.teclast.com/topic.php?channelID=70&topicID=140&pid=63
'TeclastTablet' => 'T98 4G|\bP80\b|\bX90HD\b|X98 Air|X98 Air 3G|\bX89\b|P80 3G|\bX80h\b|P98 Air|\bX89HD\b|P98 3G|\bP90HD\b|P89 3G|X98 3G|\bP70h\b|P79HD 3G|G18d 3G|\bP79HD\b|\bP89s\b|\bA88\b|\bP10HD\b|\bP19HD\b|G18 3G|\bP78HD\b|\bA78\b|\bP75\b|G17s 3G|G17h 3G|\bP85t\b|\bP90\b|\bP11\b|\bP98t\b|\bP98HD\b|\bG18d\b|\bP85s\b|\bP11HD\b|\bP88s\b|\bA80HD\b|\bA80se\b|\bA10h\b|\bP89\b|\bP78s\b|\bG18\b|\bP85\b|\bA70h\b|\bA70\b|\bG17\b|\bP18\b|\bA80s\b|\bA11s\b|\bP88HD\b|\bA80h\b|\bP76s\b|\bP76h\b|\bP98\b|\bA10HD\b|\bP78\b|\bP88\b|\bA11\b|\bA10t\b|\bP76a\b|\bP76t\b|\bP76e\b|\bP85HD\b|\bP85a\b|\bP86\b|\bP75HD\b|\bP76v\b|\bA12\b|\bP75a\b|\bA15\b|\bP76Ti\b|\bP81HD\b|\bA10\b|\bT760VE\b|\bT720HD\b|\bP76\b|\bP73\b|\bP71\b|\bP72\b|\bT720SE\b|\bC520Ti\b|\bT760\b|\bT720VE\b|T720-3GE|T720-WiFi',
// Onda - http://www.onda-tablet.com/buy-android-onda.html?dir=desc&limit=all&order=price
'OndaTablet' => '\b(V975i|Vi30|VX530|V701|Vi60|V701s|Vi50|V801s|V719|Vx610w|VX610W|V819i|Vi10|VX580W|Vi10|V711s|V813|V811|V820w|V820|Vi20|V711|VI30W|V712|V891w|V972|V819w|V820w|Vi60|V820w|V711|V813s|V801|V819|V975s|V801|V819|V819|V818|V811|V712|V975m|V101w|V961w|V812|V818|V971|V971s|V919|V989|V116w|V102w|V973|Vi40)\b[\s]+|V10 \b4G\b',
'JaytechTablet' => 'TPC-PA762',
'BlaupunktTablet' => 'Endeavour 800NG|Endeavour 1010',
// http://www.digma.ru/support/download/
// @todo: Ebooks also (if requested)
'DigmaTablet' => '\b(iDx10|iDx9|iDx8|iDx7|iDxD7|iDxD8|iDsQ8|iDsQ7|iDsQ8|iDsD10|iDnD7|3TS804H|iDsQ11|iDj7|iDs10)\b',
// http://www.evolioshop.com/ro/tablete-pc.html
// http://www.evolio.ro/support/downloads_static.html?cat=2
// @todo: Research some more
'EvolioTablet' => 'ARIA_Mini_wifi|Aria[ _]Mini|Evolio X10|Evolio X7|Evolio X8|\bEvotab\b|\bNeura\b',
// @todo http://www.lavamobiles.com/tablets-data-cards
'LavaTablet' => 'QPAD E704|\bIvoryS\b|E-TAB IVORY|\bE-TAB\b',
// http://www.breezetablet.com/
'AocTablet' => 'MW0811|MW0812|MW0922|MTK8382|MW1031|MW0831|MW0821|MW0931|MW0712',
// http://www.mpmaneurope.com/en/products/internet-tablets-14/android-tablets-14/
'MpmanTablet' => 'MP11 OCTA|MP10 OCTA|MPQC1114|MPQC1004|MPQC994|MPQC974|MPQC973|MPQC804|MPQC784|MPQC780|\bMPG7\b|MPDCG75|MPDCG71|MPDC1006|MP101DC|MPDC9000|MPDC905|MPDC706HD|MPDC706|MPDC705|MPDC110|MPDC100|MPDC99|MPDC97|MPDC88|MPDC8|MPDC77|MP709|MID701|MID711|MID170|MPDC703|MPQC1010',
// https://www.celkonmobiles.com/?_a=categoryphones&sid=2
'CelkonTablet' => 'CT695|CT888|CT[\s]?910|CT7 Tab|CT9 Tab|CT3 Tab|CT2 Tab|CT1 Tab|C820|C720|\bCT-1\b',
// http://www.wolderelectronics.com/productos/manuales-y-guias-rapidas/categoria-2-miTab
'WolderTablet' => 'miTab \b(DIAMOND|SPACE|BROOKLYN|NEO|FLY|MANHATTAN|FUNK|EVOLUTION|SKY|GOCAR|IRON|GENIUS|POP|MINT|EPSILON|BROADWAY|JUMP|HOP|LEGEND|NEW AGE|LINE|ADVANCE|FEEL|FOLLOW|LIKE|LINK|LIVE|THINK|FREEDOM|CHICAGO|CLEVELAND|BALTIMORE-GH|IOWA|BOSTON|SEATTLE|PHOENIX|DALLAS|IN 101|MasterChef)\b',
'MediacomTablet' => 'M-MPI10C3G|M-SP10EG|M-SP10EGP|M-SP10HXAH|M-SP7HXAH|M-SP10HXBH|M-SP8HXAH|M-SP8MXA',
// http://www.mi.com/en
'MiTablet' => '\bMI PAD\b|\bHM NOTE 1W\b',
// http://www.nbru.cn/index.html
'NibiruTablet' => 'Nibiru M1|Nibiru Jupiter One',
// http://navroad.com/products/produkty/tablety/
// http://navroad.com/products/produkty/tablety/
'NexoTablet' => 'NEXO NOVA|NEXO 10|NEXO AVIO|NEXO FREE|NEXO GO|NEXO EVO|NEXO 3G|NEXO SMART|NEXO KIDDO|NEXO MOBI',
// http://leader-online.com/new_site/product-category/tablets/
// http://www.leader-online.net.au/List/Tablet
'LeaderTablet' => 'TBLT10Q|TBLT10I|TBL-10WDKB|TBL-10WDKBO2013|TBL-W230V2|TBL-W450|TBL-W500|SV572|TBLT7I|TBA-AC7-8G|TBLT79|TBL-8W16|TBL-10W32|TBL-10WKB|TBL-W100',
// http://www.datawind.com/ubislate/
'UbislateTablet' => 'UbiSlate[\s]?7C',
// http://www.pocketbook-int.com/ru/support
'PocketBookTablet' => 'Pocketbook',
// http://www.kocaso.com/product_tablet.html
'KocasoTablet' => '\b(TB-1207)\b',
// http://global.hisense.com/product/asia/tablet/Sero7/201412/t20141215_91832.htm
'HisenseTablet' => '\b(F5281|E2371)\b',
// http://www.tesco.com/direct/hudl/
'Hudl' => 'Hudl HT7S3|Hudl 2',
// http://www.telstra.com.au/home-phone/thub-2/
'TelstraTablet' => 'T-Hub2',
'GenericTablet' => 'Android.*\b97D\b|Tablet(?!.*PC)|BNTV250A|MID-WCDMA|LogicPD Zoom2|\bA7EB\b|CatNova8|A1_07|CT704|CT1002|\bM721\b|rk30sdk|\bEVOTAB\b|M758A|ET904|ALUMIUM10|Smartfren Tab|Endeavour 1010|Tablet-PC-4|Tagi Tab|\bM6pro\b|CT1020W|arc 10HD|\bTP750\b|\bQTAQZ3\b|WVT101|TM1088|KT107'
);
/**
* List of mobile Operating Systems.
*
* @var array
*/
protected static $operatingSystems = array(
'AndroidOS' => 'Android',
'BlackBerryOS' => 'blackberry|\bBB10\b|rim tablet os',
'PalmOS' => 'PalmOS|avantgo|blazer|elaine|hiptop|palm|plucker|xiino',
'SymbianOS' => 'Symbian|SymbOS|Series60|Series40|SYB-[0-9]+|\bS60\b',
// @reference: http://en.wikipedia.org/wiki/Windows_Mobile
'WindowsMobileOS' => 'Windows CE.*(PPC|Smartphone|Mobile|[0-9]{3}x[0-9]{3})|Windows Mobile|Windows Phone [0-9.]+|WCE;',
// @reference: http://en.wikipedia.org/wiki/Windows_Phone
// http://wifeng.cn/?r=blog&a=view&id=106
// http://nicksnettravels.builttoroam.com/post/2011/01/10/Bogus-Windows-Phone-7-User-Agent-String.aspx
// http://msdn.microsoft.com/library/ms537503.aspx
// https://msdn.microsoft.com/en-us/library/hh869301(v=vs.85).aspx
'WindowsPhoneOS' => 'Windows Phone 10.0|Windows Phone 8.1|Windows Phone 8.0|Windows Phone OS|XBLWP7|ZuneWP7|Windows NT 6.[23]; ARM;',
'iOS' => '\biPhone.*Mobile|\biPod|\biPad|AppleCoreMedia',
// https://en.wikipedia.org/wiki/IPadOS
'iPadOS' => 'CPU OS 13',
// @reference https://en.m.wikipedia.org/wiki/Sailfish_OS
// https://sailfishos.org/
'SailfishOS' => 'Sailfish',
// http://en.wikipedia.org/wiki/MeeGo
// @todo: research MeeGo in UAs
'MeeGoOS' => 'MeeGo',
// http://en.wikipedia.org/wiki/Maemo
// @todo: research Maemo in UAs
'MaemoOS' => 'Maemo',
'JavaOS' => 'J2ME/|\bMIDP\b|\bCLDC\b', // '|Java/' produces bug #135
'webOS' => 'webOS|hpwOS',
'badaOS' => '\bBada\b',
'BREWOS' => 'BREW',
);
/**
* List of mobile User Agents.
*
* IMPORTANT: This is a list of only mobile browsers.
* Mobile Detect 2.x supports only mobile browsers,
* it was never designed to detect all browsers.
* The change will come in 2017 in the 3.x release for PHP7.
*
* @var array
*/
protected static $browsers = array(
//'Vivaldi' => 'Vivaldi',
// @reference: https://developers.google.com/chrome/mobile/docs/user-agent
'Chrome' => '\bCrMo\b|CriOS.*Mobile|Android.*Chrome/[.0-9]* Mobile',
'Dolfin' => '\bDolfin\b',
'Opera' => 'Opera.*Mini|Opera.*Mobi|Android.*Opera|Mobile.*OPR/[0-9.]+$|Coast/[0-9.]+',
'Skyfire' => 'Skyfire',
// Added "Edge on iOS" https://github.com/serbanghita/Mobile-Detect/issues/764
'Edge' => 'EdgiOS.*Mobile|Mobile Safari/[.0-9]* Edge',
'IE' => 'IEMobile|MSIEMobile', // |Trident/[.0-9]+
'Firefox' => 'fennec|firefox.*maemo|(Mobile|Tablet).*Firefox|Firefox.*Mobile|FxiOS.*Mobile',
'Bolt' => 'bolt',
'TeaShark' => 'teashark',
'Blazer' => 'Blazer',
// @reference: http://developer.apple.com/library/safari/#documentation/AppleApplications/Reference/SafariWebContent/OptimizingforSafarioniPhone/OptimizingforSafarioniPhone.html#//apple_ref/doc/uid/TP40006517-SW3
// Excluded "Edge on iOS" https://github.com/serbanghita/Mobile-Detect/issues/764
'Safari' => 'Version((?!\bEdgiOS\b).)*Mobile.*Safari|Safari.*Mobile|MobileSafari',
// http://en.wikipedia.org/wiki/Midori_(web_browser)
//'Midori' => 'midori',
//'Tizen' => 'Tizen',
'WeChat' => '\bMicroMessenger\b',
'UCBrowser' => 'UC.*Browser|UCWEB',
'baiduboxapp' => 'baiduboxapp',
'baidubrowser' => 'baidubrowser',
// https://github.com/serbanghita/Mobile-Detect/issues/7
'DiigoBrowser' => 'DiigoBrowser',
// http://www.puffinbrowser.com/index.php
// https://github.com/serbanghita/Mobile-Detect/issues/752
// 'Puffin' => 'Puffin',
// http://mercury-browser.com/index.html
'Mercury' => '\bMercury\b',
// http://en.wikipedia.org/wiki/Obigo_Browser
'ObigoBrowser' => 'Obigo',
// http://en.wikipedia.org/wiki/NetFront
'NetFront' => 'NF-Browser',
// @reference: http://en.wikipedia.org/wiki/Minimo
// http://en.wikipedia.org/wiki/Vision_Mobile_Browser
'GenericBrowser' => 'NokiaBrowser|OviBrowser|OneBrowser|TwonkyBeamBrowser|SEMC.*Browser|FlyFlow|Minimo|NetFront|Novarra-Vision|MQQBrowser|MicroMessenger',
// @reference: https://en.wikipedia.org/wiki/Pale_Moon_(web_browser)
'PaleMoon' => 'Android.*PaleMoon|Mobile.*PaleMoon',
);
/**
* Utilities.
*
* @var array
*/
protected static $utilities = array(
// Experimental. When a mobile device wants to switch to 'Desktop Mode'.
// http://scottcate.com/technology/windows-phone-8-ie10-desktop-or-mobile/
// https://github.com/serbanghita/Mobile-Detect/issues/57#issuecomment-15024011
// https://developers.facebook.com/docs/sharing/webmasters/crawler/
'Bot' => 'Googlebot|facebookexternalhit|Google-AMPHTML|s~amp-validator|AdsBot-Google|Google Keyword Suggestion|Facebot|YandexBot|YandexMobileBot|bingbot|ia_archiver|AhrefsBot|Ezooms|GSLFbot|WBSearchBot|Twitterbot|TweetmemeBot|Twikle|PaperLiBot|Wotbox|UnwindFetchor|Exabot|MJ12bot|YandexImages|TurnitinBot|Pingdom|contentkingapp|AspiegelBot',
'MobileBot' => 'Googlebot-Mobile|AdsBot-Google-Mobile|YahooSeeker/M1A1-R2D2',
'DesktopMode' => 'WPDesktop',
'TV' => 'SonyDTV|HbbTV', // experimental
'WebKit' => '(webkit)[ /]([\w.]+)',
// @todo: Include JXD consoles.
'Console' => '\b(Nintendo|Nintendo WiiU|Nintendo 3DS|Nintendo Switch|PLAYSTATION|Xbox)\b',
'Watch' => 'SM-V700',
);
/**
* All possible HTTP headers that represent the
* User-Agent string.
*
* @var array
*/
protected static $uaHttpHeaders = array(
// The default User-Agent string.
'HTTP_USER_AGENT',
// Header can occur on devices using Opera Mini.
'HTTP_X_OPERAMINI_PHONE_UA',
// Vodafone specific header: http://www.seoprinciple.com/mobile-web-community-still-angry-at-vodafone/24/
'HTTP_X_DEVICE_USER_AGENT',
'HTTP_X_ORIGINAL_USER_AGENT',
'HTTP_X_SKYFIRE_PHONE',
'HTTP_X_BOLT_PHONE_UA',
'HTTP_DEVICE_STOCK_UA',
'HTTP_X_UCBROWSER_DEVICE_UA'
);
/**
* The individual segments that could exist in a User-Agent string. VER refers to the regular
* expression defined in the constant self::VER.
*
* @var array
*/
protected static $properties = array(
// Build
'Mobile' => 'Mobile/[VER]',
'Build' => 'Build/[VER]',
'Version' => 'Version/[VER]',
'VendorID' => 'VendorID/[VER]',
// Devices
'iPad' => 'iPad.*CPU[a-z ]+[VER]',
'iPhone' => 'iPhone.*CPU[a-z ]+[VER]',
'iPod' => 'iPod.*CPU[a-z ]+[VER]',
//'BlackBerry' => array('BlackBerry[VER]', 'BlackBerry [VER];'),
'Kindle' => 'Kindle/[VER]',
// Browser
'Chrome' => array('Chrome/[VER]', 'CriOS/[VER]', 'CrMo/[VER]'),
'Coast' => array('Coast/[VER]'),
'Dolfin' => 'Dolfin/[VER]',
// @reference: https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/User-Agent/Firefox
'Firefox' => array('Firefox/[VER]', 'FxiOS/[VER]'),
'Fennec' => 'Fennec/[VER]',
// http://msdn.microsoft.com/en-us/library/ms537503(v=vs.85).aspx
// https://msdn.microsoft.com/en-us/library/ie/hh869301(v=vs.85).aspx
'Edge' => 'Edge/[VER]',
'IE' => array('IEMobile/[VER];', 'IEMobile [VER]', 'MSIE [VER];', 'Trident/[0-9.]+;.*rv:[VER]'),
// http://en.wikipedia.org/wiki/NetFront
'NetFront' => 'NetFront/[VER]',
'NokiaBrowser' => 'NokiaBrowser/[VER]',
'Opera' => array( ' OPR/[VER]', 'Opera Mini/[VER]', 'Version/[VER]' ),
'Opera Mini' => 'Opera Mini/[VER]',
'Opera Mobi' => 'Version/[VER]',
'UCBrowser' => array( 'UCWEB[VER]', 'UC.*Browser/[VER]' ),
'MQQBrowser' => 'MQQBrowser/[VER]',
'MicroMessenger' => 'MicroMessenger/[VER]',
'baiduboxapp' => 'baiduboxapp/[VER]',
'baidubrowser' => 'baidubrowser/[VER]',
'SamsungBrowser' => 'SamsungBrowser/[VER]',
'Iron' => 'Iron/[VER]',
// @note: Safari 7534.48.3 is actually Version 5.1.
// @note: On BlackBerry the Version is overwriten by the OS.
'Safari' => array( 'Version/[VER]', 'Safari/[VER]' ),
'Skyfire' => 'Skyfire/[VER]',
'Tizen' => 'Tizen/[VER]',
'Webkit' => 'webkit[ /][VER]',
'PaleMoon' => 'PaleMoon/[VER]',
'SailfishBrowser' => 'SailfishBrowser/[VER]',
// Engine
'Gecko' => 'Gecko/[VER]',
'Trident' => 'Trident/[VER]',
'Presto' => 'Presto/[VER]',
'Goanna' => 'Goanna/[VER]',
// OS
'iOS' => ' \bi?OS\b [VER][ ;]{1}',
'Android' => 'Android [VER]',
'Sailfish' => 'Sailfish [VER]',
'BlackBerry' => array('BlackBerry[\w]+/[VER]', 'BlackBerry.*Version/[VER]', 'Version/[VER]'),
'BREW' => 'BREW [VER]',
'Java' => 'Java/[VER]',
// @reference: http://windowsteamblog.com/windows_phone/b/wpdev/archive/2011/08/29/introducing-the-ie9-on-windows-phone-mango-user-agent-string.aspx
// @reference: http://en.wikipedia.org/wiki/Windows_NT#Releases
'Windows Phone OS' => array( 'Windows Phone OS [VER]', 'Windows Phone [VER]'),
'Windows Phone' => 'Windows Phone [VER]',
'Windows CE' => 'Windows CE/[VER]',
// http://social.msdn.microsoft.com/Forums/en-US/windowsdeveloperpreviewgeneral/thread/6be392da-4d2f-41b4-8354-8dcee20c85cd
'Windows NT' => 'Windows NT [VER]',
'Symbian' => array('SymbianOS/[VER]', 'Symbian/[VER]'),
'webOS' => array('webOS/[VER]', 'hpwOS/[VER];'),
);
/**
* Construct an instance of this class.
*
* @param array $headers Specify the headers as injection. Should be PHP _SERVER flavored.
* If left empty, will use the global _SERVER['HTTP_*'] vars instead.
* @param string $userAgent Inject the User-Agent header. If null, will use HTTP_USER_AGENT
* from the $headers array instead.
*/
public function __construct(
array $headers = null,
$userAgent = null
) {
$this->setHttpHeaders($headers);
$this->setUserAgent($userAgent);
}
/**
* Get the current script version.
* This is useful for the demo.php file,
* so people can check on what version they are testing
* for mobile devices.
*
* @return string The version number in semantic version format.
*/
public static function getScriptVersion()
{
return self::VERSION;
}
/**
* Set the HTTP Headers. Must be PHP-flavored. This method will reset existing headers.
*
* @param array $httpHeaders The headers to set. If null, then using PHP's _SERVER to extract
* the headers. The default null is left for backwards compatibility.
*/
public function setHttpHeaders($httpHeaders = null)
{
// use global _SERVER if $httpHeaders aren't defined
if (!is_array($httpHeaders) || !count($httpHeaders)) {
$httpHeaders = $_SERVER;
}
// clear existing headers
$this->httpHeaders = array();
// Only save HTTP headers. In PHP land, that means only _SERVER vars that
// start with HTTP_.
foreach ($httpHeaders as $key => $value) {
if (substr($key, 0, 5) === 'HTTP_') {
$this->httpHeaders[$key] = $value;
}
}
// In case we're dealing with CloudFront, we need to know.
$this->setCfHeaders($httpHeaders);
}
/**
* Retrieves the HTTP headers.
*
* @return array
*/
public function getHttpHeaders()
{
return $this->httpHeaders;
}
/**
* Retrieves a particular header. If it doesn't exist, no exception/error is caused.
* Simply null is returned.
*
* @param string $header The name of the header to retrieve. Can be HTTP compliant such as
* "User-Agent" or "X-Device-User-Agent" or can be php-esque with the
* all-caps, HTTP_ prefixed, underscore seperated awesomeness.
*
* @return string|null The value of the header.
*/
public function getHttpHeader($header)
{
// are we using PHP-flavored headers?
if (strpos($header, '_') === false) {
$header = str_replace('-', '_', $header);
$header = strtoupper($header);
}
// test the alternate, too
$altHeader = 'HTTP_' . $header;
//Test both the regular and the HTTP_ prefix
if (isset($this->httpHeaders[$header])) {
return $this->httpHeaders[$header];
} elseif (isset($this->httpHeaders[$altHeader])) {
return $this->httpHeaders[$altHeader];
}
return null;
}
public function getMobileHeaders()
{
return self::$mobileHeaders;
}
/**
* Get all possible HTTP headers that
* can contain the User-Agent string.
*
* @return array List of HTTP headers.
*/
public function getUaHttpHeaders()
{
return self::$uaHttpHeaders;
}
/**
* Set CloudFront headers
* http://docs.aws.amazon.com/AmazonCloudFront/latest/DeveloperGuide/header-caching.html#header-caching-web-device
*
* @param array $cfHeaders List of HTTP headers
*
* @return boolean If there were CloudFront headers to be set
*/
public function setCfHeaders($cfHeaders = null) {
// use global _SERVER if $cfHeaders aren't defined
if (!is_array($cfHeaders) || !count($cfHeaders)) {
$cfHeaders = $_SERVER;
}
// clear existing headers
$this->cloudfrontHeaders = array();
// Only save CLOUDFRONT headers. In PHP land, that means only _SERVER vars that
// start with cloudfront-.
$response = false;
foreach ($cfHeaders as $key => $value) {
if (substr(strtolower($key), 0, 16) === 'http_cloudfront_') {
$this->cloudfrontHeaders[strtoupper($key)] = $value;
$response = true;
}
}
return $response;
}
/**
* Retrieves the cloudfront headers.
*
* @return array
*/
public function getCfHeaders()
{
return $this->cloudfrontHeaders;
}
/**
* @param string $userAgent
* @return string
*/
private function prepareUserAgent($userAgent) {
$userAgent = trim($userAgent);
$userAgent = substr($userAgent, 0, 500);
return $userAgent;
}
/**
* Set the User-Agent to be used.
*
* @param string $userAgent The user agent string to set.
*
* @return string|null
*/
public function setUserAgent($userAgent = null)
{
// Invalidate cache due to #375
$this->cache = array();
if (false === empty($userAgent)) {
return $this->userAgent = $this->prepareUserAgent($userAgent);
} else {
$this->userAgent = null;
foreach ($this->getUaHttpHeaders() as $altHeader) {
if (false === empty($this->httpHeaders[$altHeader])) { // @todo: should use getHttpHeader(), but it would be slow. (Serban)
$this->userAgent .= $this->httpHeaders[$altHeader] . " ";
}
}
if (!empty($this->userAgent)) {
return $this->userAgent = $this->prepareUserAgent($this->userAgent);
}
}
if (count($this->getCfHeaders()) > 0) {
return $this->userAgent = 'Amazon CloudFront';
}
return $this->userAgent = null;
}
/**
* Retrieve the User-Agent.
*
* @return string|null The user agent if it's set.
*/
public function getUserAgent()
{
return $this->userAgent;
}
/**
* Set the detection type. Must be one of self::DETECTION_TYPE_MOBILE or
* self::DETECTION_TYPE_EXTENDED. Otherwise, nothing is set.
*
* @deprecated since version 2.6.9
*
* @param string $type The type. Must be a self::DETECTION_TYPE_* constant. The default
* parameter is null which will default to self::DETECTION_TYPE_MOBILE.
*/
public function setDetectionType($type = null)
{
if ($type === null) {
$type = self::DETECTION_TYPE_MOBILE;
}
if ($type !== self::DETECTION_TYPE_MOBILE && $type !== self::DETECTION_TYPE_EXTENDED) {
return;
}
$this->detectionType = $type;
}
public function getMatchingRegex()
{
return $this->matchingRegex;
}
public function getMatchesArray()
{
return $this->matchesArray;
}
/**
* Retrieve the list of known phone devices.
*
* @return array List of phone devices.
*/
public static function getPhoneDevices()
{
return self::$phoneDevices;
}
/**
* Retrieve the list of known tablet devices.
*
* @return array List of tablet devices.
*/
public static function getTabletDevices()
{
return self::$tabletDevices;
}
/**
* Alias for getBrowsers() method.
*
* @return array List of user agents.
*/
public static function getUserAgents()
{
return self::getBrowsers();
}
/**
* Retrieve the list of known browsers. Specifically, the user agents.
*
* @return array List of browsers / user agents.
*/
public static function getBrowsers()
{
return self::$browsers;
}
/**
* Retrieve the list of known utilities.
*
* @return array List of utilities.
*/
public static function getUtilities()
{
return self::$utilities;
}
/**
* Method gets the mobile detection rules. This method is used for the magic methods $detect->is*().
*
* @deprecated since version 2.6.9
*
* @return array All the rules (but not extended).
*/
public static function getMobileDetectionRules()
{
static $rules;
if (!$rules) {
$rules = array_merge(
self::$phoneDevices,
self::$tabletDevices,
self::$operatingSystems,
self::$browsers
);
}
return $rules;
}
/**
* Method gets the mobile detection rules + utilities.
* The reason this is separate is because utilities rules
* don't necessary imply mobile. This method is used inside
* the new $detect->is('stuff') method.
*
* @deprecated since version 2.6.9
*
* @return array All the rules + extended.
*/
public function getMobileDetectionRulesExtended()
{
static $rules;
if (!$rules) {
// Merge all rules together.
$rules = array_merge(
self::$phoneDevices,
self::$tabletDevices,
self::$operatingSystems,
self::$browsers,
self::$utilities
);
}
return $rules;
}
/**
* Retrieve the current set of rules.
*
* @deprecated since version 2.6.9
*
* @return array
*/
public function getRules()
{
if ($this->detectionType == self::DETECTION_TYPE_EXTENDED) {
return self::getMobileDetectionRulesExtended();
} else {
return self::getMobileDetectionRules();
}
}
/**
* Retrieve the list of mobile operating systems.
*
* @return array The list of mobile operating systems.
*/
public static function getOperatingSystems()
{
return self::$operatingSystems;
}
/**
* Check the HTTP headers for signs of mobile.
* This is the fastest mobile check possible; it's used
* inside isMobile() method.
*
* @return bool
*/
public function checkHttpHeadersForMobile()
{
foreach ($this->getMobileHeaders() as $mobileHeader => $matchType) {
if (isset($this->httpHeaders[$mobileHeader])) {
if (isset($matchType['matches']) && is_array($matchType['matches'])) {
foreach ($matchType['matches'] as $_match) {
if (strpos($this->httpHeaders[$mobileHeader], $_match) !== false) {
return true;
}
}
return false;
} else {
return true;
}
}
}
return false;
}
/**
* Magic overloading method.
*
* @method boolean is[...]()
* @param string $name
* @param array $arguments
* @return mixed
* @throws BadMethodCallException when the method doesn't exist and doesn't start with 'is'
*/
public function __call($name, $arguments)
{
// make sure the name starts with 'is', otherwise
if (substr($name, 0, 2) !== 'is') {
throw new BadMethodCallException("No such method exists: $name");
}
$this->setDetectionType(self::DETECTION_TYPE_MOBILE);
$key = substr($name, 2);
return $this->matchUAAgainstKey($key);
}
/**
* Find a detection rule that matches the current User-agent.
*
* @param null $userAgent deprecated
* @return boolean
*/
protected function matchDetectionRulesAgainstUA($userAgent = null)
{
// Begin general search.
foreach ($this->getRules() as $_regex) {
if (empty($_regex)) {
continue;
}
if ($this->match($_regex, $userAgent)) {
return true;
}
}
return false;
}
/**
* Search for a certain key in the rules array.
* If the key is found then try to match the corresponding
* regex against the User-Agent.
*
* @param string $key
*
* @return boolean
*/
protected function matchUAAgainstKey($key)
{
// Make the keys lowercase so we can match: isIphone(), isiPhone(), isiphone(), etc.
$key = strtolower($key);
if (false === isset($this->cache[$key])) {
// change the keys to lower case
$_rules = array_change_key_case($this->getRules());
if (false === empty($_rules[$key])) {
$this->cache[$key] = $this->match($_rules[$key]);
}
if (false === isset($this->cache[$key])) {
$this->cache[$key] = false;
}
}
return $this->cache[$key];
}
/**
* Check if the device is mobile.
* Returns true if any type of mobile device detected, including special ones
* @param null $userAgent deprecated
* @param null $httpHeaders deprecated
* @return bool
*/
public function isMobile($userAgent = null, $httpHeaders = null)
{
if ($httpHeaders) {
$this->setHttpHeaders($httpHeaders);
}
if ($userAgent) {
$this->setUserAgent($userAgent);
}
// Check specifically for cloudfront headers if the useragent === 'Amazon CloudFront'
if ($this->getUserAgent() === 'Amazon CloudFront') {
$cfHeaders = $this->getCfHeaders();
if(array_key_exists('HTTP_CLOUDFRONT_IS_MOBILE_VIEWER', $cfHeaders) && $cfHeaders['HTTP_CLOUDFRONT_IS_MOBILE_VIEWER'] === 'true') {
return true;
}
}
$this->setDetectionType(self::DETECTION_TYPE_MOBILE);
if ($this->checkHttpHeadersForMobile()) {
return true;
} else {
return $this->matchDetectionRulesAgainstUA();
}
}
/**
* Check if the device is a tablet.
* Return true if any type of tablet device is detected.
*
* @param string $userAgent deprecated
* @param array $httpHeaders deprecated
* @return bool
*/
public function isTablet($userAgent = null, $httpHeaders = null)
{
// Check specifically for cloudfront headers if the useragent === 'Amazon CloudFront'
if ($this->getUserAgent() === 'Amazon CloudFront') {
$cfHeaders = $this->getCfHeaders();
if(array_key_exists('HTTP_CLOUDFRONT_IS_TABLET_VIEWER', $cfHeaders) && $cfHeaders['HTTP_CLOUDFRONT_IS_TABLET_VIEWER'] === 'true') {
return true;
}
}
$this->setDetectionType(self::DETECTION_TYPE_MOBILE);
foreach (self::$tabletDevices as $_regex) {
if ($this->match($_regex, $userAgent)) {
return true;
}
}
return false;
}
/**
* This method checks for a certain property in the
* userAgent.
* @todo: The httpHeaders part is not yet used.
*
* @param string $key
* @param string $userAgent deprecated
* @param string $httpHeaders deprecated
* @return bool|int|null
*/
public function is($key, $userAgent = null, $httpHeaders = null)
{
// Set the UA and HTTP headers only if needed (eg. batch mode).
if ($httpHeaders) {
$this->setHttpHeaders($httpHeaders);
}
if ($userAgent) {
$this->setUserAgent($userAgent);
}
$this->setDetectionType(self::DETECTION_TYPE_EXTENDED);
return $this->matchUAAgainstKey($key);
}
/**
* Some detection rules are relative (not standard),
* because of the diversity of devices, vendors and
* their conventions in representing the User-Agent or
* the HTTP headers.
*
* This method will be used to check custom regexes against
* the User-Agent string.
*
* @param $regex
* @param string $userAgent
* @return bool
*
* @todo: search in the HTTP headers too.
*/
public function match($regex, $userAgent = null)
{
if (!\is_string($userAgent) && !\is_string($this->userAgent)) {
return false;
}
$match = (bool) preg_match(sprintf('#%s#is', $regex), (false === empty($userAgent) ? $userAgent : $this->userAgent), $matches);
// If positive match is found, store the results for debug.
if ($match) {
$this->matchingRegex = $regex;
$this->matchesArray = $matches;
}
return $match;
}
/**
* Get the properties array.
*
* @return array
*/
public static function getProperties()
{
return self::$properties;
}
/**
* Prepare the version number.
*
* @todo Remove the error supression from str_replace() call.
*
* @param string $ver The string version, like "2.6.21.2152";
*
* @return float
*/
public function prepareVersionNo($ver)
{
$ver = str_replace(array('_', ' ', '/'), '.', $ver);
$arrVer = explode('.', $ver, 2);
if (isset($arrVer[1])) {
$arrVer[1] = @str_replace('.', '', $arrVer[1]); // @todo: treat strings versions.
}
return (float) implode('.', $arrVer);
}
/**
* Check the version of the given property in the User-Agent.
* Will return a float number. (eg. 2_0 will return 2.0, 4.3.1 will return 4.31)
*
* @param string $propertyName The name of the property. See self::getProperties() array
* keys for all possible properties.
* @param string $type Either self::VERSION_TYPE_STRING to get a string value or
* self::VERSION_TYPE_FLOAT indicating a float value. This parameter
* is optional and defaults to self::VERSION_TYPE_STRING. Passing an
* invalid parameter will default to the this type as well.
*
* @return string|float The version of the property we are trying to extract.
*/
public function version($propertyName, $type = self::VERSION_TYPE_STRING)
{
if (empty($propertyName)) {
return false;
}
if (!\is_string($this->userAgent)) {
return false;
}
// set the $type to the default if we don't recognize the type
if ($type !== self::VERSION_TYPE_STRING && $type !== self::VERSION_TYPE_FLOAT) {
$type = self::VERSION_TYPE_STRING;
}
$properties = self::getProperties();
// Check if the property exists in the properties array.
if (true === isset($properties[$propertyName])) {
// Prepare the pattern to be matched.
// Make sure we always deal with an array (string is converted).
$properties[$propertyName] = (array) $properties[$propertyName];
foreach ($properties[$propertyName] as $propertyMatchString) {
$propertyPattern = str_replace('[VER]', self::VER, $propertyMatchString);
// Identify and extract the version.
preg_match(sprintf('#%s#is', $propertyPattern), $this->userAgent, $match);
if (false === empty($match[1])) {
$version = ($type == self::VERSION_TYPE_FLOAT ? $this->prepareVersionNo($match[1]) : $match[1]);
return $version;
}
}
}
return false;
}
/**
* Retrieve the mobile grading, using self::MOBILE_GRADE_* constants.
* @deprecated This is no longer being maintained, it was an experiment at the time.
* @return string One of the self::MOBILE_GRADE_* constants.
*/
public function mobileGrade()
{
$isMobile = $this->isMobile();
if (
// Apple iOS 4-7.0 – Tested on the original iPad (4.3 / 5.0), iPad 2 (4.3 / 5.1 / 6.1), iPad 3 (5.1 / 6.0), iPad Mini (6.1), iPad Retina (7.0), iPhone 3GS (4.3), iPhone 4 (4.3 / 5.1), iPhone 4S (5.1 / 6.0), iPhone 5 (6.0), and iPhone 5S (7.0)
$this->is('iOS') && $this->version('iPad', self::VERSION_TYPE_FLOAT) >= 4.3 ||
$this->is('iOS') && $this->version('iPhone', self::VERSION_TYPE_FLOAT) >= 4.3 ||
$this->is('iOS') && $this->version('iPod', self::VERSION_TYPE_FLOAT) >= 4.3 ||
// Android 2.1-2.3 - Tested on the HTC Incredible (2.2), original Droid (2.2), HTC Aria (2.1), Google Nexus S (2.3). Functional on 1.5 & 1.6 but performance may be sluggish, tested on Google G1 (1.5)
// Android 3.1 (Honeycomb) - Tested on the Samsung Galaxy Tab 10.1 and Motorola XOOM
// Android 4.0 (ICS) - Tested on a Galaxy Nexus. Note: transition performance can be poor on upgraded devices
// Android 4.1 (Jelly Bean) - Tested on a Galaxy Nexus and Galaxy 7
( $this->version('Android', self::VERSION_TYPE_FLOAT)>2.1 && $this->is('Webkit') ) ||
// Windows Phone 7.5-8 - Tested on the HTC Surround (7.5), HTC Trophy (7.5), LG-E900 (7.5), Nokia 800 (7.8), HTC Mazaa (7.8), Nokia Lumia 520 (8), Nokia Lumia 920 (8), HTC 8x (8)
$this->version('Windows Phone OS', self::VERSION_TYPE_FLOAT) >= 7.5 ||
// Tested on the Torch 9800 (6) and Style 9670 (6), BlackBerry® Torch 9810 (7), BlackBerry Z10 (10)
$this->is('BlackBerry') && $this->version('BlackBerry', self::VERSION_TYPE_FLOAT) >= 6.0 ||
// Blackberry Playbook (1.0-2.0) - Tested on PlayBook
$this->match('Playbook.*Tablet') ||
// Palm WebOS (1.4-3.0) - Tested on the Palm Pixi (1.4), Pre (1.4), Pre 2 (2.0), HP TouchPad (3.0)
( $this->version('webOS', self::VERSION_TYPE_FLOAT) >= 1.4 && $this->match('Palm|Pre|Pixi') ) ||
// Palm WebOS 3.0 - Tested on HP TouchPad
$this->match('hp.*TouchPad') ||
// Firefox Mobile 18 - Tested on Android 2.3 and 4.1 devices
( $this->is('Firefox') && $this->version('Firefox', self::VERSION_TYPE_FLOAT) >= 18 ) ||
// Chrome for Android - Tested on Android 4.0, 4.1 device
( $this->is('Chrome') && $this->is('AndroidOS') && $this->version('Android', self::VERSION_TYPE_FLOAT) >= 4.0 ) ||
// Skyfire 4.1 - Tested on Android 2.3 device
( $this->is('Skyfire') && $this->version('Skyfire', self::VERSION_TYPE_FLOAT) >= 4.1 && $this->is('AndroidOS') && $this->version('Android', self::VERSION_TYPE_FLOAT) >= 2.3 ) ||
// Opera Mobile 11.5-12: Tested on Android 2.3
( $this->is('Opera') && $this->version('Opera Mobi', self::VERSION_TYPE_FLOAT) >= 11.5 && $this->is('AndroidOS') ) ||
// Meego 1.2 - Tested on Nokia 950 and N9
$this->is('MeeGoOS') ||
// Sailfish OS
$this->is('SailfishOS') ||
// Tizen (pre-release) - Tested on early hardware
$this->is('Tizen') ||
// Samsung Bada 2.0 - Tested on a Samsung Wave 3, Dolphin browser
// @todo: more tests here!
$this->is('Dolfin') && $this->version('Bada', self::VERSION_TYPE_FLOAT) >= 2.0 ||
// UC Browser - Tested on Android 2.3 device
( ($this->is('UC Browser') || $this->is('Dolfin')) && $this->version('Android', self::VERSION_TYPE_FLOAT) >= 2.3 ) ||
// Kindle 3 and Fire - Tested on the built-in WebKit browser for each
( $this->match('Kindle Fire') ||
$this->is('Kindle') && $this->version('Kindle', self::VERSION_TYPE_FLOAT) >= 3.0 ) ||
// Nook Color 1.4.1 - Tested on original Nook Color, not Nook Tablet
$this->is('AndroidOS') && $this->is('NookTablet') ||
// Chrome Desktop 16-24 - Tested on OS X 10.7 and Windows 7
$this->version('Chrome', self::VERSION_TYPE_FLOAT) >= 16 && !$isMobile ||
// Safari Desktop 5-6 - Tested on OS X 10.7 and Windows 7
$this->version('Safari', self::VERSION_TYPE_FLOAT) >= 5.0 && !$isMobile ||
// Firefox Desktop 10-18 - Tested on OS X 10.7 and Windows 7
$this->version('Firefox', self::VERSION_TYPE_FLOAT) >= 10.0 && !$isMobile ||
// Internet Explorer 7-9 - Tested on Windows XP, Vista and 7
$this->version('IE', self::VERSION_TYPE_FLOAT) >= 7.0 && !$isMobile ||
// Opera Desktop 10-12 - Tested on OS X 10.7 and Windows 7
$this->version('Opera', self::VERSION_TYPE_FLOAT) >= 10 && !$isMobile
){
return self::MOBILE_GRADE_A;
}
if (
$this->is('iOS') && $this->version('iPad', self::VERSION_TYPE_FLOAT)<4.3 ||
$this->is('iOS') && $this->version('iPhone', self::VERSION_TYPE_FLOAT)<4.3 ||
$this->is('iOS') && $this->version('iPod', self::VERSION_TYPE_FLOAT)<4.3 ||
// Blackberry 5.0: Tested on the Storm 2 9550, Bold 9770
$this->is('Blackberry') && $this->version('BlackBerry', self::VERSION_TYPE_FLOAT) >= 5 && $this->version('BlackBerry', self::VERSION_TYPE_FLOAT)<6 ||
//Opera Mini (5.0-6.5) - Tested on iOS 3.2/4.3 and Android 2.3
($this->version('Opera Mini', self::VERSION_TYPE_FLOAT) >= 5.0 && $this->version('Opera Mini', self::VERSION_TYPE_FLOAT) <= 7.0 &&
($this->version('Android', self::VERSION_TYPE_FLOAT) >= 2.3 || $this->is('iOS')) ) ||
// Nokia Symbian^3 - Tested on Nokia N8 (Symbian^3), C7 (Symbian^3), also works on N97 (Symbian^1)
$this->match('NokiaN8|NokiaC7|N97.*Series60|Symbian/3') ||
// @todo: report this (tested on Nokia N71)
$this->version('Opera Mobi', self::VERSION_TYPE_FLOAT) >= 11 && $this->is('SymbianOS')
){
return self::MOBILE_GRADE_B;
}
if (
// Blackberry 4.x - Tested on the Curve 8330
$this->version('BlackBerry', self::VERSION_TYPE_FLOAT) <= 5.0 ||
// Windows Mobile - Tested on the HTC Leo (WinMo 5.2)
$this->match('MSIEMobile|Windows CE.*Mobile') || $this->version('Windows Mobile', self::VERSION_TYPE_FLOAT) <= 5.2 ||
// Tested on original iPhone (3.1), iPhone 3 (3.2)
$this->is('iOS') && $this->version('iPad', self::VERSION_TYPE_FLOAT) <= 3.2 ||
$this->is('iOS') && $this->version('iPhone', self::VERSION_TYPE_FLOAT) <= 3.2 ||
$this->is('iOS') && $this->version('iPod', self::VERSION_TYPE_FLOAT) <= 3.2 ||
// Internet Explorer 7 and older - Tested on Windows XP
$this->version('IE', self::VERSION_TYPE_FLOAT) <= 7.0 && !$isMobile
){
return self::MOBILE_GRADE_C;
}
// All older smartphone platforms and featurephones - Any device that doesn't support media queries
// will receive the basic, C grade experience.
return self::MOBILE_GRADE_C;
}
}
![Mobile Detect](http://demo.mobiledetect.net/logo-github.png)
> Motto: "Every business should have a detection script to detect mobile readers."
![Build status](https://github.com/serbanghita/Mobile-Detect/workflows/Mobile-Detect/badge.svg)
[![Latest Stable Version](https://poser.pugx.org/mobiledetect/mobiledetectlib/v/stable.svg)](https://packagist.org/packages/mobiledetect/mobiledetectlib)
[![Total Downloads](https://poser.pugx.org/mobiledetect/mobiledetectlib/downloads.svg)](https://packagist.org/packages/mobiledetect/mobiledetectlib)
[![Daily Downloads](https://poser.pugx.org/mobiledetect/mobiledetectlib/d/daily.png)](https://packagist.org/packages/mobiledetect/mobiledetectlib)
[![License](https://poser.pugx.org/mobiledetect/mobiledetectlib/license.svg)](https://packagist.org/packages/mobiledetect/mobiledetectlib)
[![Chat on Slack](https://img.shields.io/badge/Slack%20%23general-join-orange.svg)](https://join.slack.com/t/mobiledetect/shared_invite/enQtMjg1NDY0OTg5NzgzLTcwMzEzMWJjZjRlOWFkY2ZiNzE1ZmRmNzEwM2VhOGY5OGVkYWMxNjdkZDU5YjQ5MmM5MGUxYjhlZDQwOGVjZjE)
#### About
Mobile Detect is a lightweight PHP class for detecting mobile devices (including tablets).
It uses the User-Agent string combined with specific HTTP headers to detect the mobile environment.
*Why*
Your website's _content strategy_ is important! You need a complete toolkit to deliver an experience that is _optimized_,
_fast_ and _relevant_ to your users. Mobile Detect class is a
[server-side detection](http://www.w3.org/TR/mwabp/#bp-devcap-detection) tool that can help you with your RWD strategy,
it is not a replacement for CSS3 media queries or other forms of client-side feature detection.
*How*
We're committed to make Mobile_Detect the best open-source mobile detection resource and this is why before
each release we're running [unit tests](./tests) and research and update the detection rules on **monthly** basis.
*Who*
See [the history](./docs/HISTORY.md) of the project.
#### Announcements
* **JetBrains** is sponsoring the project by providing licenses for [PHPStorm](https://www.jetbrains.com/phpstorm/) and
[DataGrip](https://www.jetbrains.com/datagrip/).
* **Mobile_Detect `2.x.x`** is only integrating new regexes, User-Agents and tests. We are focusing on **new tablets only**.
The rest of the PRs about TVs, bots or optimizations will be closed and analyzed after `3.0.0-beta` is released.
* **Mobile_Detect `3.x.x`** is experimental and WIP.
#### Install
**Download and include manually**
> Use this to quickly test the demo.
* [Download latest release](../../tags)
* [Mobile_Detect.php](./Mobile_Detect.php)
```php
require_once "libs/Mobile_Detect.php";
```
**Install as a [composer package](https://packagist.org/packages/mobiledetect/mobiledetectlib)**
> Use this method to get continuous updates.
```
composer require mobiledetect/mobiledetectlib
```
or include the dependency in the `composer.json` file:
```json
{
"require": {
"mobiledetect/mobiledetectlib": "^2.8"
}
}
```
#### Demo
* [:iphone: Live demo!](https://demo.mobiledetect.net)
* [Code examples](../../wiki/Code-examples)
#### Contribute
*Submit a PR*
> Submit a pull request but before make sure you read [how to contribute](docs/CONTRIBUTING.md) guide.
*Donate*
|Paypal|
|------|
|[Donate :+1:](https://www.paypal.com/cgi-bin/webscr?cmd=_donations&business=mobiledetectlib%40gmail%2ecom&lc=US&item_name=Mobile%20Detect&currency_code=USD&bn=PP%2dDonationsBF%3abtn_donate_SM%2egif%3aNonHosted)|
I'm currently paying for hosting and spend a lot of my family time to maintain the project and planning the future releases.
I would highly appreciate any money donations that will keep the research going.
Special thanks to the community :+1: for donations, JetBrains team for the continuous support and [Dragos Gavrila](https://twitter.com/grafician) who contributed with the logo.
#### Modules, plugins, ports
> [Submit new module, plugin, port](../../issues/new?title=New%203rd%20party%20module&body=Name,%20Link%20and%20Description%20of%20the%20module.)
:point_right: Keep `Mobile_Detect.php` class in a separate `module` and do NOT include it in your script core because of the high frequency of updates.
:point_right: When including the class into your `web application` or `module` always use `include_once '../path/to/Mobile_Detect.php` to prevent conflicts.
**JavaScript**
* mobile-detect.js - A [JavaScript port](https://github.com/hgoebl/mobile-detect.js) of Mobile-Detect class. Made by [Heinrich Goebl](https://github.com/hgoebl).
**Varnish Cache**
* [Varnish Mobile Detect](https://github.com/willemk/varnish-mobiletranslate) - Drop-in varnish solution to mobile user
detection based on the Mobile-Detect library. Made by [willemk](https://github.com/willemk).
* [mobiledetect2vcl](https://github.com/carlosabalde/mobiledetect2vcl) - Python script to transform the Mobile
Detect JSON database into an UA-based mobile detection VCL subroutine easily integrable in any Varnish Cache
configuration. Made by [Carlos Abalde](https://github.com/carlosabalde).
**LUA**
* [mobile-detect.lua](https://github.com/yourpalmark/mobile-detect.lua) is a port of Mobile-Detect to Lua for
NGINX HTTP servers. Follows closely to mobile-detect.js. Supports all methods that server-side
mobile-detect.js supports. Fully unit-tested and synced with Travis CI (Build Passing badge included).
Made by [Mark Walters](https://github.com/yourpalmark).
**PHP**
**WordPress**
* [Mobile Detect for WordPress](https://wordpress.org/plugins/tinywp-mobile-detect/) - WordPress has a built-in function
(`wp_is_mobile()`) to detect mobile devices. There is (at least) one catch, though. It considers iPad (iPad pro,
and any tablet) as a mobile. So, this 3rd party module changes the way `wp_is_mobile()` works with the help of
Mobile Detect PHP library!
Made by [Pothi Kalimuthu](https://github.com/pothi)
* [WordPress Mobile Detect](https://wordpress.org/plugins/wp-mobile-detect/) - Gives you the ability to wrap that
infographic in a `[notdevice][/notdevice]` shortcode so at the server level WordPress will
decide to show that content only if the user is NOT on a phone or tablet.
Made by [Jesse Friedman](https://profiles.wordpress.org/professor44/).
* [mobble](https://wordpress.org/plugins/mobble/) - provides mobile related conditional functions for your site.
e.g. `is_iphone()`, `is_mobile()` and `is_tablet()`. Made by Scott Evans.
* [WordPress Responsage](https://github.com/iamspacehead/responsage) - A small WordPress theme plugin that allows
you to make your images responsive. Made by [Adrian Ciaschetti](https://github.com/iamspacehead).
* [WP247 Body Classes](https://wordpress.org/plugins/wp247-body-classes/) - Add unique classes to the `body` tag for
easy styling based on various attributes (archive, user, post, mobile) and various WordPress "is" functions.
Mobile attributes include type of device, Operating System, Browser, etc. Examples: .is-mobile, .is-not-mobile,
.is-tablet, .is-ios, .is-not-ios, .is-androidos, .is-chromebrowser.
Made by [wescleveland56](https://github.com/wescleveland56).
* [Adaptive Content](https://wordpress.org/plugins/addfunc-adaptive-content/) for WordPress provides the most
intuitive set of shortcodes for including/excluding content on mobile devices, tablets desktops and other
more specific device parameters. This lightweight plugin lets content writers and theme authors choose when
WordPress should or shouldn’t show any give content item using shortcodes and quicktags or theme elements using functions.
Made by [AddFunc](https://profiles.wordpress.org/addfunc).
* [AddFunc Mobile Detect](https://wordpress.org/plugins/addfunc-mobile-detect/) for WordPress redirects
mobile traffic to your mobile website and, basically, gives you loads of control over your mobile redirects.
Made by [AddFunc](https://profiles.wordpress.org/addfunc).
**Drupal**
* [Drupal Mobile Switch](https://www.drupal.org/project/mobile_switch) - The Mobile Switch Drupal module provides a
automatic theme switch functionality for mobile devices, detected by Browscap or Mobile Detect.
Made by [Siegfried Neumann](https://www.drupal.org/user/45267).
* [Drupal Context Mobile Detect](https://www.drupal.org/project/context_mobile_detect) - This is a Drupal context module
which integrates Context and PHP Mobile Detect library.
Created by [Artem Shymko](https://www.drupal.org/user/432492).
* [Drupal Mobile Detect](https://www.drupal.org/project/mobile_detect) - Lightweight mobile detect module for Drupal
created by [Matthew Donadio](https://www.drupal.org/user/325244).
**Joomla**
* [yagendoo Joomla! Mobile Detection Plugin](http://www.yagendoo.com/en/blog/free-mobile-detection-plugin-for-joomla.html) - Lightweight PHP plugin for Joomla!
that detects a mobile browser using the Mobile Detect class.
Made by yagendoo media.
* [User Agent Detector plugin](https://github.com/renekreijveld/UserAgentDetector) - This system plugin detects the user
agent of your website visitor and sets a session variable accordingly. Based on the user agent, the plugin detects if the
site is running on a desktop pc, tablet or smartphone. It can also detect if the visitor is a spider bot (search engine).
Session variable that is set: `ualayout`. Possible values: desktop, tablet, mobile, bot.
Made by @ReneKreijveld.
**Magento**
* [Magento helper](http://www.magentocommerce.com/magento-connect/catalog/product/view/id/16835/) from Optimise Web enables
the use of all functions provided by Mobile Detect. Made by [Kathir Vel](http://www.kathirvel.com).
* [Magento 2 Mobile Detect Theme Change](https://github.com/EaDesgin/magento2-mobiledetect) is an extension for Magento 2
that will change the theme or redirect to a different URL. Also containing a helper to check for the device type.
**PrestaShop**
* [PrestaShop](https://www.prestashop.com) is a free, secure and open source shopping cart platform. Mobile_Detect
is included in the default package since 1.5.x.
**Laravel**
* [Agent](https://github.com/jenssegers/agent) is a user agent class for Laravel based on Mobile Detect with some
additional functionality.
Made by [Jens Segers](https://github.com/jenssegers).
* [Laravel Mobile Detect](https://github.com/riverskies/laravel-mobile-detect) is a package that enables you to use device detection right in your Laravel Blade templates. (Utilises the well-known, constantly updated PHP mobile detection library.)
Made by [Barnabas Kecskes](https://github.com/barnabaskecskes).
* [BrowserDetect](https://github.com/hisorange/browser-detect) is a browser and mobile detection package, collects
and wrap together the best user-agent identifiers for Laravel.
Created by [Varga Zsolt](https://github.com/hisorange).
**Zend Framework**
* [ZF2 Mobile-Detect](https://github.com/neilime/zf2-mobile-detect.git) is a Zend Framework 2 module that provides
Mobile-Detect features (Mobile_Detect class as a service, helper for views and plugin controllers).
Made by [neilime](https://github.com/neilime).
* [ZF2 MobileDetectModule](https://github.com/nikolaposa/MobileDetectModule) facilitates integration of a PHP MobileDetect
class with some ZF2-based application. Has similar idea like the existing ZF2 Mobile-Detect module,
but differs in initialization and provision routine of the actual Mobile_Detect class.
Appropriate view helper and controller plugin also have different conceptions.
Made by [Nikola Posa](https://github.com/nikolaposa).
**Symfony**
* [Symfony2 Mobile Detect Bundle](https://github.com/suncat2000/MobileDetectBundle) is a bundle for detecting mobile devices,
manage mobile view and redirect to the mobile and tablet version.
Made by [Nikolay Ivlev](https://github.com/suncat2000).
* [Silex Mobile Detect Service Provider](https://github.com/jbinfo/MobileDetectServiceProvider) is a service provider to
interact with Mobile detect class methods.
Made by [Lhassan Baazzi](https://github.com/jbinfo).
**Slim Framework**
* [Slim_Mobile_Detect](https://github.com/zguillez/slim_mobile_detect) implements Mobile_Detect lib for different
responses write on Slim Framework App.
**ExpressionEngine**
* [EE2 Detect Mobile](https://github.com/garethtdavies/detect-mobile) is a lightweight PHP plugin for EE2 that detects
a mobile browser using the Mobile Detect class. Made by [Gareth Davies](https://github.com/garethtdavies).
**Yii Framework**
* [Yii Extension](https://github.com/iamsalnikov/MobileDetect) - Mobile detect plugin for Yii framework.
Made by [Alexey Salnikov](https://github.com/iamsalnikov).
* [Yii Extension](https://github.com/candasm/yii1-mobile-detect-component) - Mobile detect component for Yii framework
1.x version which supports composer package manager. Made by [Candas Minareci](https://github.com/candasm).
* [Yii2 Device Detect](https://github.com/alexandernst/yii2-device-detect/) - Yii2 extension for Mobile-Detect library.
Made by [Alexander Nestorov](https://github.com/alexandernst).
**CakePHP**
* [CakePHP MobileDetect](https://github.com/chronon/CakePHP-MobileDetectComponent-Plugin) is a plugin component for
CakePHP 2.x. Made by [Gregory Gaskill](https://github.com/chronon).
**FuelPHP**
* [Special Agent](https://github.com/rob-bar/special_agent) is a FuelPHP package which uses php-mobile-detect to
determine whether a device is mobile or not. It overrides the Fuelphp Agent class its methods.
Made by [Robbie Bardjin](https://github.com/rob-bar).
**TYPO3**
* [px_mobiledetect](https://typo3.org/extensions/repository/view/px_mobiledetect) is an extension that helps to detect
visitor's mobile device class (if that’s tablet or mobile device like smartphone). Made by Alexander Tretyak.
**Other**
* [PageCache](https://github.com/mmamedov/page-cache) is a lightweight PHP library for full page cache,
with built-in Mobile-Detect support. Made by [Muhammed Mamedov](https://github.com/mmamedov).
* [Statamic CMS Mobile Detect](https://github.com/haikulab/statamic-mobile-detect) is a plugin.
Made by [Sergei Filippov](https://github.com/haikulab/statamic-mobile-detect) of Haiku Lab.
* [Kohana Mobile Detect](https://github.com/madeinnordeste/kohana-mobile-detect) is an example of implementation of
Mobile_Detect class with Kohana framework.
Written by [Luiz Alberto S. Ribeiro](https://github.com/madeinnordeste).
* [MemHT](https://www.memht.com) is a Free PHP CMS and Blog that permit the creation and the management online
of websites with few and easy steps. Has the class included in the core.
* [concrete5](https://www.concrete5.org) is a CMS that is free and open source. The library is included in the core.
* [engine7](https://github.com/QOXCorp/exengine) is PHP Open Source Framework. The Mobile_Detect class is included in
the engine.
* [Zikula](http://zikula.org) is a free and open-source Content Management Framework, which allows you to run
impressive websites and build powerful online applications. The core uses Mobile-Detect to switch to a special
Mobile theme, using jQueryMobile.
* [UserAgentInfo](https://github.com/quentin389/UserAgentInfo) is a PHP class for parsing user agent strings
(HTTP_USER_AGENT). Includes mobile checks, bot checks, browser types/versions and more.
Based on browscap, Mobile_Detect and ua-parser. Created for high traffic websites and fast batch processing.
Made by [quentin389](https://github.com/quentin389).
* [LJ Mobile Detect](https://github.com/lewisjenkins/craft-lj-mobiledetect) is a simple implementation of Mobile Detect
for Craft CMS. Made by [Lewis Jenkins](https://github.com/lewisjenkins).
* [Detect Craft](https://github.com/mmikkel/Detect-Craft) is a Craft CMS wrapper for the Mobile_Detect library. Made by [Mikkel Rummelhoff](https://github.com/mmikkel).
* [Grav Plugin Mobile Detect](https://github.com/dimitrilongo/grav-plugin-mobile-detect/) is a simple implementation
of Mobile Detect for Grav CMS. Made by [Dimitri Longo](https://github.com/dimitrilongo).
* [Mobile_Detect module for UliCMS](https://github.com/derUli/ulicms-Mobile_Detect).
Made by [derUli](https://github.com/derUli).
**Perl**
* [MobileDetect.pm](https://www.buzzerstar.com/development/) is a Perl module for Mobile Detect.
Made by [Sebastian Enger](https://devop.tools/).
**Python**
* [pymobiledetect](https://pypi.python.org/pypi/pymobiledetect) - Mobile detect python package.
Made by Bas van Oostveen.
**Ruby**
* [mobile_detect.rb](https://github.com/ktaragorn/mobile_detect) is a Ruby gem using the JSON data exposed by the
php project and implementing a basic subset of the API (as much as can be done by the exposed data).
Made by [Karthik T](https://github.com/ktaragorn).
**Go**
* [GoMobileDetect](https://github.com/Shaked/gomobiledetect) is a Go port of Mobile Detect class.
Made by [https://github.com/Shaked](Shaked).
**LUA**
* [ua-lua](https://github.com/robinef/ua-lua) is a small lib written in LUA providing device type detection.
ua-lua is detecting mobile or tablet devices based on user-agent inside nginx daemon.
Made by [Frédéric Robinet](https://github.com/robinef).
**.Net**
* [mobile-detect](https://github.com/validide/mobile-detect) is a .Net partial port written in C#.
Made by [Valentin Dide](https://github.com/validide).
**ColdFusion**
* [MobileDetect](https://github.com/GiancarloGomez/ColdFusion-MobileDetect) is a CFC port of the
Mobile_Detect PHP Library. Made by [Giancarlo Gomez](https://github.com/GiancarloGomez).
**Experiments** :bulb:
* [Mobile Detect Fast](https://bitbucket.org/lanaguani/mobile-detect-fast/) (See: [#474](https://github.com/serbanghita/Mobile-Detect/issues/474)) is a class to increase the performance of Mobile Detect lib. Made by [LanaGuani](https://github.com/lanaguanifw).
{
"name": "mobiledetect/mobiledetectlib",
"type": "library",
"description": "Mobile_Detect is a lightweight PHP class for detecting mobile devices. It uses the User-Agent string combined with specific HTTP headers to detect the mobile environment.",
"keywords": ["mobile", "mobile detect", "mobile detector", "php mobile detect", "detect mobile devices"],
"homepage": "https://github.com/serbanghita/Mobile-Detect",
"license": "MIT",
"authors": [
{
"name": "Serban Ghita",
"email": "serbanghita@gmail.com",
"homepage": "http://mobiledetect.net",
"role": "Developer"
}
],
"require": {
"php": ">=5.0.0"
},
"require-dev": {
"phpunit/phpunit": "~4.8.35||~5.7"
},
"autoload": {
"classmap": ["Mobile_Detect.php"],
"psr-0": {
"Detection": "namespaced/"
}
},
"archive": {
"exclude": ["docs", "examples", "export"]
}
}
app:
restart: 'on-failure'
image: php:7
working_dir: /app
command: vendor/bin/phpunit -v -c tests/phpunit.xml --coverage-text --strict-coverage --stop-on-risky
ports:
- "8000:8000"
volumes:
- .:/app
composer:
restart: 'no'
image: composer/composer:php7
command: install
volumes:
- .:/app
\ No newline at end of file
# Contributing to Mobile Detect
### License
By contributing to Mobile Detect library you agree with the [MIT License](../LICENSE) + contributing agreement below.
```
Developer’s Certificate of Origin 1.1
By making a contribution to this project, I certify that:
(a) The contribution was created in whole or in part by me and I
have the right to submit it under the open source license
indicated in the file; or
(b) The contribution is based upon previous work that, to the best
of my knowledge, is covered under an appropriate open source
license and I have the right under that license to submit that
work with modifications, whether created in whole or in part
by me, under the same open source license (unless I am
permitted to submit under a different license), as indicated
in the file; or
(c) The contribution was provided directly to me by some other
person who certified (a), (b) or (c) and I have not modified
it.
(d) I understand and agree that this project and the contribution
are public and that a record of the contribution (including all
personal information I submit with it, including my sign-off) is
maintained indefinitely and may be redistributed consistent with
this project or the open source license(s) involved.
```
### Reporting issues
1. Specify the User-agent by visiting [http://demo.mobiledetect.net](http://demo.mobiledetect.net).
1. Specify the expected behaviour.
### Developing
1. Fork Mobile Detect repository. See ["How to fork"](https://help.github.com/articles/fork-a-repo/#fork-an-example-repository) example.
2. `git clone https://github.com/[yourname]/Mobile-Detect.git`
3. `git add remote serbanghita https://github.com/serbanghita/Mobile-Detect.git`
4. `git remote -v` - You should see:
```
origin git@github.com:serbanghita/Mobile-Detect.git
serbanghita https://github.com/serbanghita/Mobile-Detect.git
```
5. `git checkout -b devel origin/devel`
6. `composer install`
1. On Windows use `php composer.phar update` first.
7. Start working on your changes.
1. If you add new methods or make structural changes to the `Mobile_Detect.php` class
you need to add unit tests!
1. If you add new regexes make sure you commit the User-Agents in [`tests/providers/vendors`](https://github.com/serbanghita/Mobile-Detect/tree/master/tests/providers/vendors)
8. Run tests
9. `vendor/bin/phpunit -v -c tests/phpunit.xml --coverage-text --strict-coverage --stop-on-risky`
1. On Windows use `%cd%/vendor/bin/phpunit ...`
10. `git status` or `git diff` - inspect your changes
1 `git stage .`
11. `git commit -m "[your commit message here]`
12. `git push origin devel`
13. Go to your repo on GitHub and ["Submit the PR"](https://help.github.com/articles/about-pull-requests/)
### New module, plugin, plugin or port
[Submit new module, plugin, port](../../issues/new?title=New%203rd%20party%20module&body=Name,%20Link%20and%20Description%20of%20the%20module.)
including the following information:
* Module name
* Description
* Link
* Author
Or you can submit a PR against `README.md`.
### Website updates
1. Our official website is hosted at [http://mobiledetect.net](http://mobiledetect.net).
1. The files are found on the `gh-pages` branch.
1. `git checkout gh-pages`
1. `npm install -g browser-sync`
1. `browser-sync start --s . --f . --port 3000 --reload-debounce 1500 --no-ui`
1. Go to `http://localhost:3000` and make changes.
1. Commit, push and submit the PR against `serbanghita:gh-pages`.
The first version of the script was developed in 2009 and it was hosted at https://code.google.com/p/php-mobile-detect/, it was a small project with around 30 stars. (Original blog post by Victor: http://victorstanciu.ro/detectarea-platformelor-mobile-in-php/)
In December 2011 it received a major update from the first version, an important number of issues were fixed, then 2.0 was launched. The new version marks a new mindset and also featuring tablet detection.
Throughout 2012 the script has been updated constantly and we have received tons of feedback and requests.
In July 2012 we moved the repository from Google Code to GitHub in order to quickly accommodate the frequent updates and to involve more people.
In August 2013 the library has 1800+ stargazers and support for: composer, PHPUnit tests, PSR standards and a new webpage http://mobiledetect.net
Mobile Detect library and user contributions are <a href="https://github.com/serbanghita/Mobile-Detect/blob/master/LICENSE.txt">MIT Licensed</a>.
-------------delete this message-------------
* By submitting a new issue I acknowledge that I already read the README, CODE EXAMPLES and KNOWN LIMITATIONS.
* I understand that the current version `2.x` is only meant to detect `mobile` devices.
* Please post your User-Agent string! On a real device/s, the library is expected to work correctly.
-------------delete this message-------------
**Issue description**
**User-Agent(s)**
**Suggestions**
\ No newline at end of file
**Known limitations**
* Mobile Detect script was designed to detect `mobile` devices. Implicitly other devices are considered to be `desktop`.
* User-Agent and HTTP headers sniffing is a non-reliable method of detecting a mobile device.
* If the mobile browser is set on `Desktop mode`, the Mobile Detect script has no indicator (eg. a group of strings) that would allow it to detect that the device is `mobile`.
* Ipad 2019 is being recognized as a desktop because of Safari's default `Request Desktop Website` setting. See details and possible workaround [#820](https://github.com/serbanghita/Mobile-Detect/issues/820)
* Some touchscreen devices (eg. Microsoft Surface) are tough to detect as mobile since they can be used in a laptop mode. See: [#32](https://github.com/serbanghita/Mobile-Detect/issues/32), [#461](https://github.com/serbanghita/Mobile-Detect/issues/461), [#667](https://github.com/serbanghita/Mobile-Detect/issues/667)
* Some mobile devices (eg. IPadOS, Google Pixel Slate). See: [#795](https://github.com/serbanghita/Mobile-Detect/issues/795), [#788](https://github.com/serbanghita/Mobile-Detect/issues/788)
* Detecting the device brand (eg. Apple, Samsung, HTC) is not 100% reliable.
* We don't monitor the quality of the 3rd party tools based on Mobile Detect script.
We cannot guarantee that they are using the class properly or if they provide the latest version.
* Version `2.x` is made to be PHP 5.3 compatible because of the backward compatibility changes of PHP.
* There are hundreds of devices launched every month, we cannot keep a 100% up to date detection rate.
* The script cannot detect the viewport, pixel density or resolution of the screen since it's running server-side.
<?php
/**
* Mobile Detect Library
* - export -
* =====================
*
* Use the resulting JSON export file in other languages
* other than PHP. Always check for 'version' key because
* new major versions can modify the structure of the JSON file.
*
* The result of running this script is the export.json file.
*
* @license Code and contributions have 'MIT License'
* More details: https://github.com/serbanghita/Mobile-Detect/blob/master/LICENSE.txt
*
*/
// Included nicejson function to beautify the result JSON file.
// This library is not mandatory.
if( file_exists(dirname(__FILE__).'/nicejson/nicejson.php') ) {
include_once dirname(__FILE__).'/nicejson/nicejson.php';
}
// Include Mobile Detect.
require_once dirname(__FILE__).'/../Mobile_Detect.php';
$detect = new Mobile_Detect;
$json = array(
// The current version of Mobile Detect class that
// is being exported.
'version' => $detect->getScriptVersion(),
// All headers that trigger 'isMobile' to be 'true',
// before reaching the User-Agent match detection.
'headerMatch' => $detect->getMobileHeaders(),
// All possible User-Agent headers.
'uaHttpHeaders' => $detect->getUaHttpHeaders(),
// All the regexes that trigger 'isMobile' or 'isTablet'
// to be true.
'uaMatch' => array(
// If match is found, triggers 'isMobile' to be true.
'phones' => $detect->getPhoneDevices(),
// Triggers 'isTablet' to be true.
'tablets' => $detect->getTabletDevices(),
// If match is found, triggers 'isMobile' to be true.
'browsers' => $detect->getBrowsers(),
// If match is found, triggers 'isMobile' to be true.
'os' => $detect->getOperatingSystems(),
// Various utilities. To be further discussed.
'utilities' => $detect->getUtilities()
)
);
$fileName = dirname(__FILE__).'/../Mobile_Detect.json';
// Write the JSON file to disk.11
// You can import this file in your app.
if (file_put_contents(
$fileName,
function_exists('json_format') ? json_format($json) : json_encode($json)
)) {
echo 'Done. Check '.realpath($fileName).' file.';
}
else {
echo 'Failed to write '.realpath($fileName).' to disk.';
}
<?php
/**
* Little piece of PHP to make Mobile_Detect auto-loadable in PSR-0 compatible PHP autoloaders like
* the Symfony Universal ClassLoader by Fabien Potencier. Since PSR-0 handles an underscore in
* classnames (on the filesystem) as a slash, "Mobile_Detect.php" autoloaders will try to convert
* the classname and path to "Mobile\Detect.php". This script will ensure autoloading with:
* - Namespace: Detection
* - Classname: MobileDetect
* - Namespased: \Detection\MobileDetect
* - Autoload path: ./namespaced
* - Converted path: ./namespaced/Detection/MobileDetect.php
*
* Don't forget to use MobileDetect (instead of Mobile_Detect) as class in code when autoloading.
*
* Thanks to @WietseWind.
* For details please check: https://github.com/serbanghita/Mobile-Detect/pull/120
*/
namespace Detection;
require_once dirname(__FILE__) . DIRECTORY_SEPARATOR . '..' . DIRECTORY_SEPARATOR . '..' . DIRECTORY_SEPARATOR . 'Mobile_Detect.php';
class MobileDetect extends \Mobile_Detect {}
<?xml version="1.0"?>
<ruleset name="PSR1">
<description>The PSR-2 coding standard extended.</description>
<rule ref="PSR1">
<exclude name="PSR1.Classes.ClassDeclaration.MissingNamespace"/>
</rule>
<rule ref="Squiz">
<exclude name="Squiz.Classes.ValidClassName.NotCamelCaps"/>
<exclude name="Squiz.Files.FileExtension.ClassFound"/>
<exclude name="Squiz.Commenting.ClassComment.TagNotAllowed"/>
</rule>
<rule ref="Squiz.Strings.DoubleQuoteUsage">
<type>error</type>
</rule>
<rule ref="Generic.Files.LineLength">
<properties>
<property name="lineLimit" value="140"/>
</properties>
</rule>
</ruleset>
\ No newline at end of file
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment