diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index f36d7788..91197f4f 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -29,16 +29,21 @@ jobs: env: WP_ORG_PASSWORD: ${{ secrets.WP_ORG_PASSWORD }} TAG: ${{ github.event.release.tag_name }} - - name: Upload assets + - name: Upload transbank-webpay-plus-rest.zip uses: actions/upload-release-asset@v1 env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} with: upload_url: ${{ github.event.release.upload_url }} - asset_path: | - transbank-webpay-plus-rest.zip - transbank-webpay-plus-rest-guzzle7.zip - asset_name: | - transbank-webpay-plus-rest.zip - transbank-webpay-plus-rest-guzzle7.zip + asset_path: transbank-webpay-plus-rest.zip + asset_name: transbank-webpay-plus-rest.zip + asset_content_type: application/zip + - name: Upload transbank-webpay-plus-rest-guzzle7.zip + uses: actions/upload-release-asset@v1 + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + with: + upload_url: ${{ github.event.release.upload_url }} + asset_path: transbank-webpay-plus-rest-guzzle7.zip + asset_name: transbank-webpay-plus-rest-guzzle7.zip asset_content_type: application/zip diff --git a/plugin/readme.txt b/plugin/readme.txt index 3d799df4..d697e461 100644 --- a/plugin/readme.txt +++ b/plugin/readme.txt @@ -14,6 +14,12 @@ Recibe pagos en línea con tarjetas de crédito, débito y prepago en tu WooComm Recibe pagos en línea con tarjetas de crédito, débito y prepago en tu WooCommerce a través de Webpay Plus y Webpay Oneclick == Changelog == += 1.9.1 = +* Se arregla un mensaje de warning provocado por la función maskData en PHP mayor o igual a 8.x. +* Se arregla un problema que impedía encontrar el archivo de log al migrar el sitio de un servidor a otro. +* Se arregla la zona horaria de los logs. Se usa la que este configurada en el ecommerce del comercio. +* Se arregla un problema que provocaba registros duplicados en el selector de archivos logs de la vista registros. + = 1.9.0 = * Se agrega la opción de poder seleccionar el archivo log en la sección de registros del menú de configuración. * Se agrega la funcionalidad para que se muestren las tarjetas registradas de Oneclick dependiendo del entorno. @@ -163,6 +169,12 @@ Arreglado: * Initial release. == Upgrade Notice == += 1.9.1 = +* Se arregla un mensaje de warning provocado por la función maskData en PHP mayor o igual a 8.x. +* Se arregla un problema que impedía encontrar el archivo de log al migrar el sitio de un servidor a otro. +* Se arregla la zona horaria de los logs. Se usa la que este configurada en el ecommerce del comercio. +* Se arregla un problema que provocaba registros duplicados en el selector de archivos logs de la vista registros. + = 1.9.0 = * Se agrega la opción de poder seleccionar el archivo log en la sección de registros del menú de configuración. * Se agrega la funcionalidad para que se muestren las tarjetas registradas de Oneclick dependiendo del entorno. diff --git a/plugin/shared/Helpers/PluginLogger.php b/plugin/shared/Helpers/PluginLogger.php index 08f05066..1796f66a 100644 --- a/plugin/shared/Helpers/PluginLogger.php +++ b/plugin/shared/Helpers/PluginLogger.php @@ -2,12 +2,17 @@ namespace Transbank\Plugin\Helpers; +use DateTimeZone; use Monolog\Logger; use Monolog\Handler\RotatingFileHandler; use Monolog\Formatter\LineFormatter; use Transbank\Plugin\Model\LogConfig; -final class PluginLogger implements ILogger { +final class PluginLogger implements ILogger +{ + + const CACHE_LOG_NAME = 'transbank_log_file_name'; + private $logger; private $config; @@ -18,32 +23,54 @@ final class PluginLogger implements ILogger { * output format : "[%datetime%] %channel%.%level_name%: %message% %context% %extra%\n" * @param Throwable $e */ - public function __construct(LogConfig $config) { + public function __construct(LogConfig $config) + { $this->config = $config; - $logDir = $this->config->getLogDir(); - $cacheLogName = 'transbank_log_name'; - $logFile = get_transient($cacheLogName); - if (!$logFile) { - $uniqueId = uniqid('', true); - $logFile = "{$logDir}/log_transbank_{$uniqueId}.log"; - $expireTime = strtotime('tomorrow') - time(); - set_transient($cacheLogName, $logFile, $expireTime); - } - $dateFormat = "Y-m-d H:i:s"; + + $logFilePath = $this->getLogFilePath(); + $this->initializeLogger($logFilePath); + } + + private function initializeLogger(string $logFilePath) + { + $ecommerceTz = new DateTimeZone(wc_timezone_string()); + $dateFormat = "Y-m-d H:i:s P"; $output = "%datetime% > %level_name% > %message% %context% %extra%\n"; $formatter = new LineFormatter($output, $dateFormat); - $stream = new RotatingFileHandler($logFile, - 100, Logger::DEBUG); + + $stream = new RotatingFileHandler( + $logFilePath, + 100, + Logger::DEBUG + ); $stream->setFormatter($formatter); + $this->logger = new Logger('transbank'); + $this->logger->setTimezone($ecommerceTz); $this->logger->pushHandler($stream); } - public function getLogger(){ + private function getLogFilePath(): string + { + $logFileName = $this->getLogFileNameFromCache(); + + if (!$logFileName) { + $logFileName = $this->getLogFileName(); + $expireTime = strtotime('tomorrow') - time(); + $this->saveLogFileNameInCache($logFileName, $expireTime); + } + + $logDir = $this->getLogDir(); + return $logDir . $logFileName; + } + + public function getLogger() + { return $this->logger; } - public function getConfig(){ + public function getConfig() + { return $this->config; } @@ -64,7 +91,7 @@ public function logError($msg) public function getInfo() { - $files = glob($this->config->getLogDir().'/*.log'); + $files = glob($this->config->getLogDir() . '/*.log'); if (!$files) { return [ 'dir' => $this->config->getLogDir(), @@ -77,7 +104,7 @@ public function getInfo() arsort($files); $logs = []; - foreach($files as $key=>$value) { + foreach ($files as $key => $value) { $logs[] = [ "filename" => basename($key), "modified" => $value @@ -97,7 +124,7 @@ public function getLogDetail($filename, $replaceNewline = false) if ($filename == '') { return []; } - $fle = $this->config->getLogDir().'/'.$filename; + $fle = $this->config->getLogDir() . '/' . $filename; $content = file_get_contents($fle); if ($replaceNewline && $content !== false) { $content = str_replace("\n", '#@#', $content); @@ -122,4 +149,26 @@ private function formatBytes($path) } return $bytes; } + + private function getLogDir(): string + { + $logDir = $this->config->getLogDir(); + return trailingslashit($logDir); + } + + private function getLogFileName(): string + { + $uniqueId = uniqid('', true); + return 'log_transbank_' . $uniqueId . '.log'; + } + + private function getLogFileNameFromCache() + { + return get_transient(self::CACHE_LOG_NAME); + } + + private function saveLogFileNameInCache(string $logFileName, int $expireTime) + { + set_transient(self::CACHE_LOG_NAME, $logFileName, $expireTime); + } } diff --git a/plugin/src/Helpers/MaskData.php b/plugin/src/Helpers/MaskData.php index 2b71451b..b4022eef 100644 --- a/plugin/src/Helpers/MaskData.php +++ b/plugin/src/Helpers/MaskData.php @@ -1,7 +1,9 @@ isIntegration = $environment == Options::ENVIRONMENT_INTEGRATION; $this->log = TbkFactory::createLogger(); } @@ -42,7 +45,8 @@ public function __construct($environment){ * @param string $input a string to be masked. * @return string a string with substrings masked. */ - private function maskWithFormat($input){ + private function maskWithFormat($input) + { return preg_replace_callback('/(?<=-).+?(?=-)/', function ($matches) { return str_repeat('x', strlen($matches[0])); }, $input); @@ -56,18 +60,23 @@ private function maskWithFormat($input){ * @param int $charsToKeep number of original chars to keep at start and end. * @return string a string masked. */ - private function mask($input, $pattern = null, $charsToKeep = 4 ){ + private function mask($input, $pattern = null, $charsToKeep = 4) + { + if(is_null($input)) { + return ''; + } + $len = strlen($input); - if ( $pattern != null ) { - $patternPos = strpos($input, $pattern); - if ( $patternPos === 0 ) { + if ($pattern != null) { + $patternPos = strpos($input, $pattern); + if ($patternPos === 0) { $startString = $pattern; - } - else { + } else { $endString = $pattern; } } + $startString = $startString ?? substr($input, 0, $charsToKeep); $endString = $endString ?? substr($input, -$charsToKeep, $charsToKeep); $charsToReplace = $len - (strlen($startString) + strlen($endString)); @@ -81,7 +90,8 @@ private function mask($input, $pattern = null, $charsToKeep = 4 ){ * @param string $email An email to be masked. * @return string email masked. */ - private function maskEmail($email){ + private function maskEmail($email) + { return preg_replace_callback('/^(.{1,4})[^@]*(@.*)$/', function ($match) { return $match[1] . str_repeat('x', strlen($match[0]) - strlen($match[1]) - strlen($match[2])) . $match[2]; }, $email); @@ -94,14 +104,16 @@ private function maskEmail($email){ * @param string $pattern A pattern to maintain, like `child` or `sessionId`. * @return string input masked. */ - private function maskWithPattern($input, $pattern){ + private function maskWithPattern($input, $pattern) + { $regexPattern = "/(wc:($pattern:)?\w{2})\w+:(\w{2})/"; - return preg_replace_callback($regexPattern, function($matches) use ($input){ - $prefix = $matches[1]; - $suffix = $matches[3]; - $maskLength = strlen($input) - strlen($prefix) - strlen($suffix) - 1; - return $prefix . str_repeat('x', $maskLength) . $suffix; - }, $input); + + return preg_replace_callback($regexPattern, function ($matches) use ($input) { + $prefix = $matches[1]; + $suffix = $matches[3]; + $maskLength = strlen($input) - strlen($prefix) - strlen($suffix) - 1; + return $prefix . str_repeat('x', $maskLength) . $suffix; + }, $input); } /** @@ -111,10 +123,12 @@ private function maskWithPattern($input, $pattern){ * @param string $buyOrder An string with buy order to mask. * @return string buy order masked. */ - public function maskBuyOrder($buyOrder){ + public function maskBuyOrder($buyOrder) + { if ($this->isIntegration) { return $buyOrder; } + $pattern = 'child'; return $this->maskWithPattern($buyOrder, $pattern); } @@ -126,10 +140,12 @@ public function maskBuyOrder($buyOrder){ * @param string $sessionId An string with session id to mask. * @return string session id masked. */ - public function maskSessionId($sessionId){ - if($this->isIntegration){ + public function maskSessionId($sessionId) + { + if ($this->isIntegration) { return $sessionId; } + $sessionIdPattern = 'sessionId'; return $this->maskWithPattern($sessionId, $sessionIdPattern); } @@ -140,7 +156,8 @@ public function maskSessionId($sessionId){ * @param array $array an array to evaluate * @return boolean `true` if is associative, `false` otherwise */ - private function isAssociative($array) { + private function isAssociative($array) + { return (bool)count(array_filter(array_keys($array), 'is_string')); } @@ -151,14 +168,15 @@ private function isAssociative($array) { * @param array $data An array containing data to mask. * @return array copy of input, with fields masked. */ - public function maskData($data){ - try{ - if ($this->isIntegration){ + public function maskData($data) + { + try { + if ($this->isIntegration) { return $data; } $newData = $this->copyWithSubArray($data); foreach ($newData as $key => $value) { - switch($this->getValueType($value)){ + switch ($this->getValueType($value)) { case $this::OBJECT: $newData[$key] = $this->maskObject($value); break; @@ -175,8 +193,7 @@ public function maskData($data){ } } return $newData; - } - catch (\Exception $e){ + } catch (\Exception $e) { $this->log->logError('Error on Mask Data: ' . $e->getMessage()); return $data; } @@ -189,17 +206,19 @@ public function maskData($data){ * @param array $array An array to be copied. * @return array copy of input array. */ - private function copyWithSubArray($array){ + private function copyWithSubArray($array) + { $newArray = null; foreach ($array as $key => $value) { if (is_array($value)) { - $clonedValue = array_map(function ($item) { - return is_object($item) ? clone $item : $item; - }, - $value); + $clonedValue = array_map( + function ($item) { + return is_object($item) ? clone $item : $item; + }, + $value + ); $newArray[$key] = $clonedValue; - } - else { + } else { $newArray[$key] = is_object($value) ? clone $value : $value; } } @@ -213,11 +232,14 @@ private function copyWithSubArray($array){ * @param mixed $value the value to be masked. * @return mixed masked value if key exists, `false` otherwise. */ - private function getMaskedValue($key, $value){ + private function getMaskedValue($key, $value) + { $keyExists = array_key_exists($key, $this->keysToMask); - if($keyExists){ + + if ($keyExists) { return call_user_func([$this, $this->keysToMask[$key]], $value); } + return $value; } @@ -227,16 +249,18 @@ private function getMaskedValue($key, $value){ * @param string $value to evaluate. * @return int a constant representing the type of element */ - private function getValueType($value){ + private function getValueType($value) + { $valueType = $this::NO_ITERABLE; - if(is_object($value)){ + + if (is_object($value)) { $valueType = $this::OBJECT; } - if (is_array($value)){ - if ($this->isAssociative($value)){ + + if (is_array($value)) { + if ($this->isAssociative($value)) { $valueType = $this::ASSOCIATIVE_ARRAY; - } - else { + } else { $valueType = $this::INDEXED_ARRAY; } } @@ -250,8 +274,9 @@ private function getValueType($value){ * @param object $object a reference to an object to mask * @return object the object with masked attributes */ - private function maskObject($object){ - foreach($object as $detailKey => $detailValue) { + private function maskObject($object) + { + foreach ($object as $detailKey => $detailValue) { $maskedValue = $this->getMaskedValue($detailKey, $detailValue); $object->$detailKey = $maskedValue; } @@ -264,8 +289,9 @@ private function maskObject($object){ * @param array $array the array to mask. * @return array the array with masked values. */ - private function maskAssociativeArray($array){ - foreach($array as $detailKey => $detailValue) { + private function maskAssociativeArray($array) + { + foreach ($array as $detailKey => $detailValue) { $maskedValue = $this->getMaskedValue($detailKey, $detailValue); $array[$detailKey] = $maskedValue; } @@ -278,17 +304,15 @@ private function maskAssociativeArray($array){ * @param array $array the array to mask. * @return array the array with masked values. */ - private function maskIndexedArray($array){ - foreach($array as $detail) { - if(is_object($detail)) { + private function maskIndexedArray($array) + { + foreach ($array as $detail) { + if (is_object($detail)) { $detail = $this->maskObject($detail); - } - else { + } else { $detail = $this->maskAssociativeArray($array); } - } return $array; } - } diff --git a/plugin/templates/admin/log.php b/plugin/templates/admin/log.php index 03d38e09..d2fbfb90 100644 --- a/plugin/templates/admin/log.php +++ b/plugin/templates/admin/log.php @@ -42,12 +42,14 @@ if (!$folderHasLogs) { $options = ""; } + foreach ($resume['logs'] as $index) { - $options .= ""; - if($index['filename'] == basename($lastLog['filename'])) { $options .= ""; + continue; } + + $options .= ""; } echo $options;