From 37aab36cd911fe8a7260c478c1e788363d3c7a8b Mon Sep 17 00:00:00 2001 From: Eduardo Bacarin Date: Fri, 13 Jun 2025 16:24:38 -0300 Subject: [PATCH 01/32] add gitignore and remove vendor folder --- .gitignore | 2 + vendor/autoload.php | 22 - vendor/composer/ClassLoader.php | 579 ------------------------ vendor/composer/LICENSE | 21 - vendor/composer/autoload_classmap.php | 10 - vendor/composer/autoload_files.php | 10 - vendor/composer/autoload_namespaces.php | 9 - vendor/composer/autoload_psr4.php | 10 - vendor/composer/autoload_real.php | 48 -- vendor/composer/autoload_static.php | 40 -- 10 files changed, 2 insertions(+), 749 deletions(-) create mode 100644 .gitignore delete mode 100644 vendor/autoload.php delete mode 100644 vendor/composer/ClassLoader.php delete mode 100644 vendor/composer/LICENSE delete mode 100644 vendor/composer/autoload_classmap.php delete mode 100644 vendor/composer/autoload_files.php delete mode 100644 vendor/composer/autoload_namespaces.php delete mode 100644 vendor/composer/autoload_psr4.php delete mode 100644 vendor/composer/autoload_real.php delete mode 100644 vendor/composer/autoload_static.php diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..f2fddf9 --- /dev/null +++ b/.gitignore @@ -0,0 +1,2 @@ +vendor/* +composer.lock \ No newline at end of file diff --git a/vendor/autoload.php b/vendor/autoload.php deleted file mode 100644 index 5e6a330..0000000 --- a/vendor/autoload.php +++ /dev/null @@ -1,22 +0,0 @@ - - * Jordi Boggiano - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Composer\Autoload; - -/** - * ClassLoader implements a PSR-0, PSR-4 and classmap class loader. - * - * $loader = new \Composer\Autoload\ClassLoader(); - * - * // register classes with namespaces - * $loader->add('Symfony\Component', __DIR__.'/component'); - * $loader->add('Symfony', __DIR__.'/framework'); - * - * // activate the autoloader - * $loader->register(); - * - * // to enable searching the include path (eg. for PEAR packages) - * $loader->setUseIncludePath(true); - * - * In this example, if you try to use a class in the Symfony\Component - * namespace or one of its children (Symfony\Component\Console for instance), - * the autoloader will first look for the class under the component/ - * directory, and it will then fallback to the framework/ directory if not - * found before giving up. - * - * This class is loosely based on the Symfony UniversalClassLoader. - * - * @author Fabien Potencier - * @author Jordi Boggiano - * @see https://www.php-fig.org/psr/psr-0/ - * @see https://www.php-fig.org/psr/psr-4/ - */ -class ClassLoader -{ - /** @var \Closure(string):void */ - private static $includeFile; - - /** @var string|null */ - private $vendorDir; - - // PSR-4 - /** - * @var array> - */ - private $prefixLengthsPsr4 = array(); - /** - * @var array> - */ - private $prefixDirsPsr4 = array(); - /** - * @var list - */ - private $fallbackDirsPsr4 = array(); - - // PSR-0 - /** - * List of PSR-0 prefixes - * - * Structured as array('F (first letter)' => array('Foo\Bar (full prefix)' => array('path', 'path2'))) - * - * @var array>> - */ - private $prefixesPsr0 = array(); - /** - * @var list - */ - private $fallbackDirsPsr0 = array(); - - /** @var bool */ - private $useIncludePath = false; - - /** - * @var array - */ - private $classMap = array(); - - /** @var bool */ - private $classMapAuthoritative = false; - - /** - * @var array - */ - private $missingClasses = array(); - - /** @var string|null */ - private $apcuPrefix; - - /** - * @var array - */ - private static $registeredLoaders = array(); - - /** - * @param string|null $vendorDir - */ - public function __construct($vendorDir = null) - { - $this->vendorDir = $vendorDir; - self::initializeIncludeClosure(); - } - - /** - * @return array> - */ - public function getPrefixes() - { - if (!empty($this->prefixesPsr0)) { - return call_user_func_array('array_merge', array_values($this->prefixesPsr0)); - } - - return array(); - } - - /** - * @return array> - */ - public function getPrefixesPsr4() - { - return $this->prefixDirsPsr4; - } - - /** - * @return list - */ - public function getFallbackDirs() - { - return $this->fallbackDirsPsr0; - } - - /** - * @return list - */ - public function getFallbackDirsPsr4() - { - return $this->fallbackDirsPsr4; - } - - /** - * @return array Array of classname => path - */ - public function getClassMap() - { - return $this->classMap; - } - - /** - * @param array $classMap Class to filename map - * - * @return void - */ - public function addClassMap(array $classMap) - { - if ($this->classMap) { - $this->classMap = array_merge($this->classMap, $classMap); - } else { - $this->classMap = $classMap; - } - } - - /** - * Registers a set of PSR-0 directories for a given prefix, either - * appending or prepending to the ones previously set for this prefix. - * - * @param string $prefix The prefix - * @param list|string $paths The PSR-0 root directories - * @param bool $prepend Whether to prepend the directories - * - * @return void - */ - public function add($prefix, $paths, $prepend = false) - { - $paths = (array) $paths; - if (!$prefix) { - if ($prepend) { - $this->fallbackDirsPsr0 = array_merge( - $paths, - $this->fallbackDirsPsr0 - ); - } else { - $this->fallbackDirsPsr0 = array_merge( - $this->fallbackDirsPsr0, - $paths - ); - } - - return; - } - - $first = $prefix[0]; - if (!isset($this->prefixesPsr0[$first][$prefix])) { - $this->prefixesPsr0[$first][$prefix] = $paths; - - return; - } - if ($prepend) { - $this->prefixesPsr0[$first][$prefix] = array_merge( - $paths, - $this->prefixesPsr0[$first][$prefix] - ); - } else { - $this->prefixesPsr0[$first][$prefix] = array_merge( - $this->prefixesPsr0[$first][$prefix], - $paths - ); - } - } - - /** - * Registers a set of PSR-4 directories for a given namespace, either - * appending or prepending to the ones previously set for this namespace. - * - * @param string $prefix The prefix/namespace, with trailing '\\' - * @param list|string $paths The PSR-4 base directories - * @param bool $prepend Whether to prepend the directories - * - * @throws \InvalidArgumentException - * - * @return void - */ - public function addPsr4($prefix, $paths, $prepend = false) - { - $paths = (array) $paths; - if (!$prefix) { - // Register directories for the root namespace. - if ($prepend) { - $this->fallbackDirsPsr4 = array_merge( - $paths, - $this->fallbackDirsPsr4 - ); - } else { - $this->fallbackDirsPsr4 = array_merge( - $this->fallbackDirsPsr4, - $paths - ); - } - } elseif (!isset($this->prefixDirsPsr4[$prefix])) { - // Register directories for a new namespace. - $length = strlen($prefix); - if ('\\' !== $prefix[$length - 1]) { - throw new \InvalidArgumentException("A non-empty PSR-4 prefix must end with a namespace separator."); - } - $this->prefixLengthsPsr4[$prefix[0]][$prefix] = $length; - $this->prefixDirsPsr4[$prefix] = $paths; - } elseif ($prepend) { - // Prepend directories for an already registered namespace. - $this->prefixDirsPsr4[$prefix] = array_merge( - $paths, - $this->prefixDirsPsr4[$prefix] - ); - } else { - // Append directories for an already registered namespace. - $this->prefixDirsPsr4[$prefix] = array_merge( - $this->prefixDirsPsr4[$prefix], - $paths - ); - } - } - - /** - * Registers a set of PSR-0 directories for a given prefix, - * replacing any others previously set for this prefix. - * - * @param string $prefix The prefix - * @param list|string $paths The PSR-0 base directories - * - * @return void - */ - public function set($prefix, $paths) - { - if (!$prefix) { - $this->fallbackDirsPsr0 = (array) $paths; - } else { - $this->prefixesPsr0[$prefix[0]][$prefix] = (array) $paths; - } - } - - /** - * Registers a set of PSR-4 directories for a given namespace, - * replacing any others previously set for this namespace. - * - * @param string $prefix The prefix/namespace, with trailing '\\' - * @param list|string $paths The PSR-4 base directories - * - * @throws \InvalidArgumentException - * - * @return void - */ - public function setPsr4($prefix, $paths) - { - if (!$prefix) { - $this->fallbackDirsPsr4 = (array) $paths; - } else { - $length = strlen($prefix); - if ('\\' !== $prefix[$length - 1]) { - throw new \InvalidArgumentException("A non-empty PSR-4 prefix must end with a namespace separator."); - } - $this->prefixLengthsPsr4[$prefix[0]][$prefix] = $length; - $this->prefixDirsPsr4[$prefix] = (array) $paths; - } - } - - /** - * Turns on searching the include path for class files. - * - * @param bool $useIncludePath - * - * @return void - */ - public function setUseIncludePath($useIncludePath) - { - $this->useIncludePath = $useIncludePath; - } - - /** - * Can be used to check if the autoloader uses the include path to check - * for classes. - * - * @return bool - */ - public function getUseIncludePath() - { - return $this->useIncludePath; - } - - /** - * Turns off searching the prefix and fallback directories for classes - * that have not been registered with the class map. - * - * @param bool $classMapAuthoritative - * - * @return void - */ - public function setClassMapAuthoritative($classMapAuthoritative) - { - $this->classMapAuthoritative = $classMapAuthoritative; - } - - /** - * Should class lookup fail if not found in the current class map? - * - * @return bool - */ - public function isClassMapAuthoritative() - { - return $this->classMapAuthoritative; - } - - /** - * APCu prefix to use to cache found/not-found classes, if the extension is enabled. - * - * @param string|null $apcuPrefix - * - * @return void - */ - public function setApcuPrefix($apcuPrefix) - { - $this->apcuPrefix = function_exists('apcu_fetch') && filter_var(ini_get('apc.enabled'), FILTER_VALIDATE_BOOLEAN) ? $apcuPrefix : null; - } - - /** - * The APCu prefix in use, or null if APCu caching is not enabled. - * - * @return string|null - */ - public function getApcuPrefix() - { - return $this->apcuPrefix; - } - - /** - * Registers this instance as an autoloader. - * - * @param bool $prepend Whether to prepend the autoloader or not - * - * @return void - */ - public function register($prepend = false) - { - spl_autoload_register(array($this, 'loadClass'), true, $prepend); - - if (null === $this->vendorDir) { - return; - } - - if ($prepend) { - self::$registeredLoaders = array($this->vendorDir => $this) + self::$registeredLoaders; - } else { - unset(self::$registeredLoaders[$this->vendorDir]); - self::$registeredLoaders[$this->vendorDir] = $this; - } - } - - /** - * Unregisters this instance as an autoloader. - * - * @return void - */ - public function unregister() - { - spl_autoload_unregister(array($this, 'loadClass')); - - if (null !== $this->vendorDir) { - unset(self::$registeredLoaders[$this->vendorDir]); - } - } - - /** - * Loads the given class or interface. - * - * @param string $class The name of the class - * @return true|null True if loaded, null otherwise - */ - public function loadClass($class) - { - if ($file = $this->findFile($class)) { - $includeFile = self::$includeFile; - $includeFile($file); - - return true; - } - - return null; - } - - /** - * Finds the path to the file where the class is defined. - * - * @param string $class The name of the class - * - * @return string|false The path if found, false otherwise - */ - public function findFile($class) - { - // class map lookup - if (isset($this->classMap[$class])) { - return $this->classMap[$class]; - } - if ($this->classMapAuthoritative || isset($this->missingClasses[$class])) { - return false; - } - if (null !== $this->apcuPrefix) { - $file = apcu_fetch($this->apcuPrefix.$class, $hit); - if ($hit) { - return $file; - } - } - - $file = $this->findFileWithExtension($class, '.php'); - - // Search for Hack files if we are running on HHVM - if (false === $file && defined('HHVM_VERSION')) { - $file = $this->findFileWithExtension($class, '.hh'); - } - - if (null !== $this->apcuPrefix) { - apcu_add($this->apcuPrefix.$class, $file); - } - - if (false === $file) { - // Remember that this class does not exist. - $this->missingClasses[$class] = true; - } - - return $file; - } - - /** - * Returns the currently registered loaders keyed by their corresponding vendor directories. - * - * @return array - */ - public static function getRegisteredLoaders() - { - return self::$registeredLoaders; - } - - /** - * @param string $class - * @param string $ext - * @return string|false - */ - private function findFileWithExtension($class, $ext) - { - // PSR-4 lookup - $logicalPathPsr4 = strtr($class, '\\', DIRECTORY_SEPARATOR) . $ext; - - $first = $class[0]; - if (isset($this->prefixLengthsPsr4[$first])) { - $subPath = $class; - while (false !== $lastPos = strrpos($subPath, '\\')) { - $subPath = substr($subPath, 0, $lastPos); - $search = $subPath . '\\'; - if (isset($this->prefixDirsPsr4[$search])) { - $pathEnd = DIRECTORY_SEPARATOR . substr($logicalPathPsr4, $lastPos + 1); - foreach ($this->prefixDirsPsr4[$search] as $dir) { - if (file_exists($file = $dir . $pathEnd)) { - return $file; - } - } - } - } - } - - // PSR-4 fallback dirs - foreach ($this->fallbackDirsPsr4 as $dir) { - if (file_exists($file = $dir . DIRECTORY_SEPARATOR . $logicalPathPsr4)) { - return $file; - } - } - - // PSR-0 lookup - if (false !== $pos = strrpos($class, '\\')) { - // namespaced class name - $logicalPathPsr0 = substr($logicalPathPsr4, 0, $pos + 1) - . strtr(substr($logicalPathPsr4, $pos + 1), '_', DIRECTORY_SEPARATOR); - } else { - // PEAR-like class name - $logicalPathPsr0 = strtr($class, '_', DIRECTORY_SEPARATOR) . $ext; - } - - if (isset($this->prefixesPsr0[$first])) { - foreach ($this->prefixesPsr0[$first] as $prefix => $dirs) { - if (0 === strpos($class, $prefix)) { - foreach ($dirs as $dir) { - if (file_exists($file = $dir . DIRECTORY_SEPARATOR . $logicalPathPsr0)) { - return $file; - } - } - } - } - } - - // PSR-0 fallback dirs - foreach ($this->fallbackDirsPsr0 as $dir) { - if (file_exists($file = $dir . DIRECTORY_SEPARATOR . $logicalPathPsr0)) { - return $file; - } - } - - // PSR-0 include paths. - if ($this->useIncludePath && $file = stream_resolve_include_path($logicalPathPsr0)) { - return $file; - } - - return false; - } - - /** - * @return void - */ - private static function initializeIncludeClosure() - { - if (self::$includeFile !== null) { - return; - } - - /** - * Scope isolated include. - * - * Prevents access to $this/self from included files. - * - * @param string $file - * @return void - */ - self::$includeFile = \Closure::bind(static function($file) { - include $file; - }, null, null); - } -} diff --git a/vendor/composer/LICENSE b/vendor/composer/LICENSE deleted file mode 100644 index f27399a..0000000 --- a/vendor/composer/LICENSE +++ /dev/null @@ -1,21 +0,0 @@ - -Copyright (c) Nils Adermann, Jordi Boggiano - -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. - diff --git a/vendor/composer/autoload_classmap.php b/vendor/composer/autoload_classmap.php deleted file mode 100644 index 0fb0a2c..0000000 --- a/vendor/composer/autoload_classmap.php +++ /dev/null @@ -1,10 +0,0 @@ - $vendorDir . '/composer/InstalledVersions.php', -); diff --git a/vendor/composer/autoload_files.php b/vendor/composer/autoload_files.php deleted file mode 100644 index de51552..0000000 --- a/vendor/composer/autoload_files.php +++ /dev/null @@ -1,10 +0,0 @@ - $baseDir . '/src/helpers.php', -); diff --git a/vendor/composer/autoload_namespaces.php b/vendor/composer/autoload_namespaces.php deleted file mode 100644 index 15a2ff3..0000000 --- a/vendor/composer/autoload_namespaces.php +++ /dev/null @@ -1,9 +0,0 @@ - array($baseDir . '/src'), -); diff --git a/vendor/composer/autoload_real.php b/vendor/composer/autoload_real.php deleted file mode 100644 index f4faf00..0000000 --- a/vendor/composer/autoload_real.php +++ /dev/null @@ -1,48 +0,0 @@ -register(true); - - $filesToLoad = \Composer\Autoload\ComposerStaticInit60f22886a6c2e74ff0ac05bdf2882e7a::$files; - $requireFile = \Closure::bind(static function ($fileIdentifier, $file) { - if (empty($GLOBALS['__composer_autoload_files'][$fileIdentifier])) { - $GLOBALS['__composer_autoload_files'][$fileIdentifier] = true; - - require $file; - } - }, null, null); - foreach ($filesToLoad as $fileIdentifier => $file) { - $requireFile($fileIdentifier, $file); - } - - return $loader; - } -} diff --git a/vendor/composer/autoload_static.php b/vendor/composer/autoload_static.php deleted file mode 100644 index 9160470..0000000 --- a/vendor/composer/autoload_static.php +++ /dev/null @@ -1,40 +0,0 @@ - __DIR__ . '/../..' . '/src/helpers.php', - ); - - public static $prefixLengthsPsr4 = array ( - 'K' => - array ( - 'Kontrl\\PhpKore\\' => 15, - ), - ); - - public static $prefixDirsPsr4 = array ( - 'Kontrl\\PhpKore\\' => - array ( - 0 => __DIR__ . '/../..' . '/src', - ), - ); - - public static $classMap = array ( - 'Composer\\InstalledVersions' => __DIR__ . '/..' . '/composer/InstalledVersions.php', - ); - - public static function getInitializer(ClassLoader $loader) - { - return \Closure::bind(function () use ($loader) { - $loader->prefixLengthsPsr4 = ComposerStaticInit60f22886a6c2e74ff0ac05bdf2882e7a::$prefixLengthsPsr4; - $loader->prefixDirsPsr4 = ComposerStaticInit60f22886a6c2e74ff0ac05bdf2882e7a::$prefixDirsPsr4; - $loader->classMap = ComposerStaticInit60f22886a6c2e74ff0ac05bdf2882e7a::$classMap; - - }, null, ClassLoader::class); - } -} From be5a68f217a59b2860381abdb7f8e50dcc6a1e52 Mon Sep 17 00:00:00 2001 From: Eduardo Bacarin Date: Fri, 13 Jun 2025 16:25:04 -0300 Subject: [PATCH 02/32] install phpseclib and create function to sign every body request --- composer.json | 4 +++- src/Kore.php | 10 ++++++---- 2 files changed, 9 insertions(+), 5 deletions(-) diff --git a/composer.json b/composer.json index e0023a0..e4787ba 100644 --- a/composer.json +++ b/composer.json @@ -16,5 +16,7 @@ "email": "me@bacarin.dev" } ], - "require": {} + "require": { + "phpseclib/phpseclib": "~3.0" + } } diff --git a/src/Kore.php b/src/Kore.php index 6c8b403..1c2be7b 100644 --- a/src/Kore.php +++ b/src/Kore.php @@ -2,17 +2,19 @@ namespace Kontrl\PhpKore; +use phpseclib3\Crypt\PublicKeyLoader; + class Kore { private $url = 'https://httpbin.org'; - private $token; public function __construct(){ - $this->token = $this->auth(); + } - public function auth(){ - return ''; + public function signBody(array $body, string|array $key, string|bool $password = false){ + $publicKey = PublicKeyLoader::loadPrivateKey($key, $password); + return base64_encode($publicKey->sign(json_encode($body))); } public function testRequest(){ From 3472b19591b836ce8dd3bb6f41d24c3c0efcec08 Mon Sep 17 00:00:00 2001 From: Eduardo Bacarin Date: Tue, 24 Jun 2025 14:41:29 -0300 Subject: [PATCH 03/32] Identation and fixes to load keys --- src/Kore.php | 37 ++++++++++++++++++++++++------------- src/helpers.php | 4 ++-- 2 files changed, 26 insertions(+), 15 deletions(-) diff --git a/src/Kore.php b/src/Kore.php index 1c2be7b..7744c2a 100644 --- a/src/Kore.php +++ b/src/Kore.php @@ -2,29 +2,40 @@ namespace Kontrl\PhpKore; +use phpseclib3\Common\Functions\Strings; +use phpseclib3\Crypt\EC; +use phpseclib3\Crypt\EC\PublicKey; use phpseclib3\Crypt\PublicKeyLoader; +use phpseclib3\Crypt\RSA; class Kore { private $url = 'https://httpbin.org'; - public function __construct(){ - + public function __construct() {} + + public function signBody($body, string|array $key, string|bool $password = false) + { + $privateKey = PublicKeyLoader::loadPrivateKey(base64_decode($key), $password); + $sig = $privateKey->sign($body); + $sig = base64_encode($sig); + return $sig; } - public function signBody(array $body, string|array $key, string|bool $password = false){ - $publicKey = PublicKeyLoader::loadPrivateKey($key, $password); - return base64_encode($publicKey->sign(json_encode($body))); + public function verifySignature($signature, $message, $key) + { + $publicKey = PublicKeyLoader::loadPublicKey($key); + return $publicKey->verify($message, $signature); } - - public function testRequest(){ + + public function testRequest() + { return [ - 'get' => curlRequest($this->url.'/get', 'GET')['status'], - 'post' => curlRequest($this->url.'/post', 'POST', [], [], ['test' => 'test'])['status'], - 'patch' => curlRequest($this->url.'/patch', 'PATCH', [], [], ['test' => 'test'])['status'], - 'put' => curlRequest($this->url.'/put', 'PUT', [], [], ['test' => 'test'])['status'], - 'delete' => curlRequest($this->url.'/delete', 'DELETE')['status'] + 'get' => curlRequest($this->url . '/get', 'GET')['status'], + 'post' => curlRequest($this->url . '/post', 'POST', [], [], ['test' => 'test'])['status'], + 'patch' => curlRequest($this->url . '/patch', 'PATCH', [], [], ['test' => 'test'])['status'], + 'put' => curlRequest($this->url . '/put', 'PUT', [], [], ['test' => 'test'])['status'], + 'delete' => curlRequest($this->url . '/delete', 'DELETE')['status'] ]; } - } diff --git a/src/helpers.php b/src/helpers.php index 75b0cf6..517c0d2 100644 --- a/src/helpers.php +++ b/src/helpers.php @@ -13,7 +13,7 @@ if (!function_exists('curlRequest')) { if (!empty($queryParams)) { $url .= (strpos($url, '?') === false ? '?' : '&') . http_build_query($queryParams); } - + $options = [ CURLOPT_URL => $url, CURLOPT_RETURNTRANSFER => true, @@ -29,7 +29,7 @@ if (!function_exists('curlRequest')) { } $options[CURLOPT_POSTFIELDS] = $body; } - + if (!empty($headers)) { $options[CURLOPT_HTTPHEADER] = $headers; } From 17ebac8300e1787ccf69c2fcd0571d1305d186ea Mon Sep 17 00:00:00 2001 From: Eduardo Bacarin Date: Tue, 24 Jun 2025 16:30:38 -0300 Subject: [PATCH 04/32] improvements --- src/Kore.php | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/src/Kore.php b/src/Kore.php index 7744c2a..6a8766d 100644 --- a/src/Kore.php +++ b/src/Kore.php @@ -14,18 +14,17 @@ class Kore public function __construct() {} - public function signBody($body, string|array $key, string|bool $password = false) + public function signBody(string|array $body, string|array $key, string|bool $password = false) { $privateKey = PublicKeyLoader::loadPrivateKey(base64_decode($key), $password); - $sig = $privateKey->sign($body); - $sig = base64_encode($sig); - return $sig; + $sig = $privateKey->sign(json_encode($body)); + return base64_encode($sig); } - public function verifySignature($signature, $message, $key) + public function verifySignature(string $signature, string|array $message, $key) { $publicKey = PublicKeyLoader::loadPublicKey($key); - return $publicKey->verify($message, $signature); + return $publicKey->verify(json_encode($message), $signature); } public function testRequest() From bfe904943c67f239e015238997e5c6920bc11e00 Mon Sep 17 00:00:00 2001 From: Eduardo Bacarin Date: Tue, 24 Jun 2025 16:56:49 -0300 Subject: [PATCH 05/32] first steps with Pix class --- src/Kore.php | 10 +++------- src/Pix.php | 24 ++++++++++++++++++++++++ 2 files changed, 27 insertions(+), 7 deletions(-) create mode 100644 src/Pix.php diff --git a/src/Kore.php b/src/Kore.php index 6a8766d..7610ad5 100644 --- a/src/Kore.php +++ b/src/Kore.php @@ -2,21 +2,17 @@ namespace Kontrl\PhpKore; -use phpseclib3\Common\Functions\Strings; -use phpseclib3\Crypt\EC; -use phpseclib3\Crypt\EC\PublicKey; use phpseclib3\Crypt\PublicKeyLoader; -use phpseclib3\Crypt\RSA; class Kore { private $url = 'https://httpbin.org'; - public function __construct() {} + public function __construct(public $privateKey) {} - public function signBody(string|array $body, string|array $key, string|bool $password = false) + public function signBody(string|array $body, string|bool $password = false) { - $privateKey = PublicKeyLoader::loadPrivateKey(base64_decode($key), $password); + $privateKey = PublicKeyLoader::loadPrivateKey(base64_decode($this->privateKey), $password); $sig = $privateKey->sign(json_encode($body)); return base64_encode($sig); } diff --git a/src/Pix.php b/src/Pix.php new file mode 100644 index 0000000..e9c49f0 --- /dev/null +++ b/src/Pix.php @@ -0,0 +1,24 @@ + $amount, + 'pix_key' => $pix_key + ]; + return curlRequest( + 'https://httpbin.org/post', + 'POST', + [], + [ + 'x-kore-drone-uid: drone:f8f19d43660d7bbdd2c63d428de6d7b1ff33554311adbe35c784b0584aa007fd', + 'x-kore-drone-sign: ' . $this->signBody($payload) + ], + $payload + ); + } +} From 0bcfded7c78ecaf3c42b69f9e65bb4d822f4e55a Mon Sep 17 00:00:00 2001 From: Eduardo Bacarin Date: Thu, 3 Jul 2025 17:13:01 -0300 Subject: [PATCH 06/32] add drone as parameter to Kore main lib --- src/Kore.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Kore.php b/src/Kore.php index 7610ad5..2c15dcb 100644 --- a/src/Kore.php +++ b/src/Kore.php @@ -8,7 +8,7 @@ class Kore { private $url = 'https://httpbin.org'; - public function __construct(public $privateKey) {} + public function __construct(public $privateKey, public $drone) {} public function signBody(string|array $body, string|bool $password = false) { From 44e9ac4f3464650978f2f90ad74f756c5c0816ef Mon Sep 17 00:00:00 2001 From: Eduardo Bacarin Date: Thu, 3 Jul 2025 17:13:51 -0300 Subject: [PATCH 07/32] =?UTF-8?q?add=20main=20parameters=20to=20pixCobran?= =?UTF-8?q?=C3=A7aImediata=20function=20on=20Pix?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/Pix.php | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/src/Pix.php b/src/Pix.php index e9c49f0..0e688a4 100644 --- a/src/Pix.php +++ b/src/Pix.php @@ -2,20 +2,19 @@ namespace Kontrl\PhpKore; +include_once(__DIR__.'/rules.php'); + class Pix extends Kore { - public function newPixCharge($amount, $pix_key) + public function pixCobrancaImediata($payload) { - $payload = [ - 'amount' => $amount, - 'pix_key' => $pix_key - ]; + return curlRequest( 'https://httpbin.org/post', 'POST', [], [ - 'x-kore-drone-uid: drone:f8f19d43660d7bbdd2c63d428de6d7b1ff33554311adbe35c784b0584aa007fd', + 'x-kore-drone-uid: drone:' . $this->drone, 'x-kore-drone-sign: ' . $this->signBody($payload) ], $payload From 8af086e83439927ad5734ce52163e5bd7cc73700 Mon Sep 17 00:00:00 2001 From: Eduardo Bacarin Date: Thu, 3 Jul 2025 17:15:09 -0300 Subject: [PATCH 08/32] ignoring some files --- .gitignore | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/.gitignore b/.gitignore index f2fddf9..4672d29 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,5 @@ vendor/* -composer.lock \ No newline at end of file +composer.lock +*.key +*.pub +index.php \ No newline at end of file From a91b6e86509a2bea29d73977abd47d404f305c8c Mon Sep 17 00:00:00 2001 From: Eduardo Bacarin Date: Thu, 3 Jul 2025 17:15:31 -0300 Subject: [PATCH 09/32] rules file to manage required payloads --- src/rules.php | 9 +++++++++ 1 file changed, 9 insertions(+) create mode 100644 src/rules.php diff --git a/src/rules.php b/src/rules.php new file mode 100644 index 0000000..04560f5 --- /dev/null +++ b/src/rules.php @@ -0,0 +1,9 @@ + 'required|integer', + 'expiracao' => 'integer', + 'devedor' => 'sometimes|string' + ]; +} From b2d14abbce69cbe8d8ea2d6e8b0ca9bbc880f22d Mon Sep 17 00:00:00 2001 From: Eduardo Bacarin Date: Thu, 3 Jul 2025 18:40:11 -0300 Subject: [PATCH 10/32] validation rules --- composer.json | 3 ++- src/rules.php | 22 +++++++++++++++++++--- 2 files changed, 21 insertions(+), 4 deletions(-) diff --git a/composer.json b/composer.json index e4787ba..0a60726 100644 --- a/composer.json +++ b/composer.json @@ -17,6 +17,7 @@ } ], "require": { - "phpseclib/phpseclib": "~3.0" + "phpseclib/phpseclib": "~3.0", + "somnambulist/validation": "^1.12" } } diff --git a/src/rules.php b/src/rules.php index 04560f5..727ad18 100644 --- a/src/rules.php +++ b/src/rules.php @@ -1,9 +1,25 @@ 'required|integer', 'expiracao' => 'integer', - 'devedor' => 'sometimes|string' + 'devedor' => 'array', + 'devedor.documento' => 'string|min:11|max:18', + 'devedor.nome' => 'required_with:devedor.documento|string|max:100', + 'valor' => 'required|integer|min:1', + 'chave' => 'required|string', + 'txid' => 'required|string|max:100', + 'solicitacaoPagador' => 'string|max:140' ]; + + $validation = (new Factory)->validate($data, $rules); + + if ($validation->fails()) { + throw new Exception(json_encode($validation->errors()->firstOfAll()), 500); + } else { + return true; + } } From 337f1945ff1827003916b65acb2cdcd4e176ecad Mon Sep 17 00:00:00 2001 From: Eduardo Bacarin Date: Thu, 3 Jul 2025 18:41:58 -0300 Subject: [PATCH 11/32] Validation library and rules to generate pix --- src/rules.php | 25 ++++++++++++++++++++++++- 1 file changed, 24 insertions(+), 1 deletion(-) diff --git a/src/rules.php b/src/rules.php index 727ad18..33d877a 100644 --- a/src/rules.php +++ b/src/rules.php @@ -2,7 +2,7 @@ use Somnambulist\Components\Validation\Factory; -function pixCobrancaImediataRules(array $data) +function pixCobrancaImediataComValorRules(array $data) { $rules = [ 'expiracao' => 'integer', @@ -23,3 +23,26 @@ function pixCobrancaImediataRules(array $data) return true; } } + + +function pixCobrancaImediataSemValorRules(array $data) +{ + $rules = [ + 'expiracao' => 'integer', + 'devedor' => 'array', + 'devedor.documento' => 'string|min:11|max:18', + 'devedor.nome' => 'required_with:devedor.documento|string|max:100', + 'valor' => 'sometimes|integer', + 'chave' => 'required|string', + 'txid' => 'required|string|max:100', + 'solicitacaoPagador' => 'string|max:140' + ]; + + $validation = (new Factory)->validate($data, $rules); + + if ($validation->fails()) { + throw new Exception(json_encode($validation->errors()->firstOfAll()), 500); + } else { + return true; + } +} From c4702e0c933e049ffa6bfef672b7ca8c660cb008 Mon Sep 17 00:00:00 2001 From: Eduardo Bacarin Date: Thu, 3 Jul 2025 18:44:16 -0300 Subject: [PATCH 12/32] generating pix with and without value --- src/Pix.php | 65 ++++++++++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 62 insertions(+), 3 deletions(-) diff --git a/src/Pix.php b/src/Pix.php index 0e688a4..9a75a36 100644 --- a/src/Pix.php +++ b/src/Pix.php @@ -2,12 +2,34 @@ namespace Kontrl\PhpKore; -include_once(__DIR__.'/rules.php'); +include_once(__DIR__ . '/rules.php'); class Pix extends Kore { - public function pixCobrancaImediata($payload) + public function pixCobrancaImediataComValor($payload) { + pixCobrancaImediataComValorRules($payload); + $korePayload = [ + 'calendario' => [ + 'expiracao' => $payload['expiracao'] ?? 86400, + ], + 'valor' => [ + 'original' => $payload['valor'], + 'modalidadeAlteracao' => 0, + ], + 'chave' => $payload['chave'], + 'txid' => $payload['txid'], + 'solicitacaoPagador' => $payload['solicitacaoPagador'] ?? null + ]; + + if (isset($payload['devedor'])){ + if (strlen($payload['devedor']['documento']) > 11){ + $korePayload['devedor']['cnpj'] = $payload['devedor']['documento']; + }else{ + $korePayload['devedor']['cpf'] = $payload['devedor']['documento']; + } + $korePayload['devedor']['nome'] = $payload['devedor']; + } return curlRequest( 'https://httpbin.org/post', @@ -15,7 +37,44 @@ class Pix extends Kore [], [ 'x-kore-drone-uid: drone:' . $this->drone, - 'x-kore-drone-sign: ' . $this->signBody($payload) + 'x-kore-drone-sign: ' . $this->signBody($korePayload) + ], + $payload + ); + } + + public function pixCobrancaImediataSemValor($payload) + { + pixCobrancaImediataSemValorRules($payload); + $korePayload = [ + 'calendario' => [ + 'expiracao' => $payload['expiracao'] ?? 86400, + ], + 'valor' => [ + 'original' => $payload['valor'] ?? 0, + 'modalidadeAlteracao' => 1, + ], + 'chave' => $payload['chave'], + 'txid' => $payload['txid'], + 'solicitacaoPagador' => $payload['solicitacaoPagador'] ?? null + ]; + + if (isset($payload['devedor'])){ + if (strlen($payload['devedor']['documento']) > 11){ + $korePayload['devedor']['cnpj'] = $payload['devedor']['documento']; + }else{ + $korePayload['devedor']['cpf'] = $payload['devedor']['documento']; + } + $korePayload['devedor']['nome'] = $payload['devedor']; + } + + return curlRequest( + 'https://httpbin.org/post', + 'POST', + [], + [ + 'x-kore-drone-uid: drone:' . $this->drone, + 'x-kore-drone-sign: ' . $this->signBody($korePayload) ], $payload ); From e2c3372ab188814427dc5c4aa3ab5d1cc140a1af Mon Sep 17 00:00:00 2001 From: Eduardo Bacarin Date: Thu, 3 Jul 2025 18:49:54 -0300 Subject: [PATCH 13/32] changing pix function names to describe it better --- src/Pix.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Pix.php b/src/Pix.php index 9a75a36..d0f02a6 100644 --- a/src/Pix.php +++ b/src/Pix.php @@ -6,7 +6,7 @@ include_once(__DIR__ . '/rules.php'); class Pix extends Kore { - public function pixCobrancaImediataComValor($payload) + public function pixCobrancaDinamicoImediataComValor($payload) { pixCobrancaImediataComValorRules($payload); $korePayload = [ @@ -43,7 +43,7 @@ class Pix extends Kore ); } - public function pixCobrancaImediataSemValor($payload) + public function pixCobrancaDinamicoImediataSemValor($payload) { pixCobrancaImediataSemValorRules($payload); $korePayload = [ From 2e3346998782ef748bb1c81cbd988f3b1dcd5d2c Mon Sep 17 00:00:00 2001 From: Eduardo Bacarin Date: Fri, 4 Jul 2025 11:43:22 -0300 Subject: [PATCH 14/32] Custom validator created with some functions --- src/validator.php | 160 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 160 insertions(+) create mode 100644 src/validator.php diff --git a/src/validator.php b/src/validator.php new file mode 100644 index 0000000..a3a1403 --- /dev/null +++ b/src/validator.php @@ -0,0 +1,160 @@ + $ruleString) { + $value = getDataValue($data, $field); + $ruleList = explode('|', $ruleString); + + $hasSometimes = in_array('sometimes', $ruleList, true); + if ($hasSometimes && !fieldExistsInData($data, $field)) { + continue; + } + + foreach ($ruleList as $ruleItem) { + if ($ruleItem === 'sometimes') { + continue; // already handled + } + + $param = null; + if (strpos($ruleItem, ':') !== false) { + $exploded = explode(':', $ruleItem, 2); + $rule = $exploded[0]; + $param = isset($exploded[1]) ? $exploded[1] : null; + } else { + $rule = $ruleItem; + } + + $validator = 'validate_' . $rule; + + if (function_exists($validator)) { + $result = $validator($field, $value, $param, $data); + + if ($result !== true) { + $errors[$field][] = $result; + } + } else { + $errors[$field][] = "Rule '$rule' is not supported."; + } + } + } + + return ['valid' => !empty($errors) ? false : true, 'errors' => $errors]; +} + +function validate_array($field, $value, $param = null, $data = []) +{ + if (!is_array($value)) { + return "The field '$field' must be an array."; + } + return true; +} + +function validate_integer($field, $value, $param = null, $data = []) +{ + if (!is_int($value)) { + return "The field '$field' must be an integer."; + } + return true; +} + +function validate_max($field, $value, $param, $data = []) +{ + if (is_string($value) && strlen($value) > $param) { + return "The field '$field' must have at most $param characters."; + } + if (is_integer($value) && $value > $param) { + return "The value of '$field' must be at most $param."; + } + return true; +} + +function validate_min($field, $value, $param, $data = []) +{ + if (is_string($value) && strlen($value) < $param) { + return "The field '$field' must have at least $param characters."; + } + if (is_numeric($value) && $value < $param) { + return "The value of '$field' must be at least $param."; + } + return true; +} + +function validate_prohibited_with($field, $value, $param, $data = []) +{ + $otherFields = explode(',', $param); + + foreach ($otherFields as $other) { + $other = trim($other); + if (!empty($data[$other])) { + if (!empty($value)) { + return "The field '$field' is not allowed when '$other' is present."; + } + } + } + + return true; +} + +function validate_required($field, $value, $param = null, $data = []) +{ + if ($value === null || $value === '') { + return "The field '$field' is required."; + } + return true; +} + +function validate_required_with($field, $value, $param, $data = []) +{ + $relatedFields = explode(',', $param); + + foreach ($relatedFields as $related) { + $related = trim($related); + + if (isset($data[$related]) && $data[$related] !== '') { + if ($value === null || $value === '') { + return "The field '$field' is required when '$related' is present."; + } + } + } + + return true; +} + +function validate_string($field, $value, $param = null, $data = []) +{ + if (!is_string($value)) { + return "The field '$field' must be a string."; + } + return true; +} From de8c7b4ac42e86f78e3b44c97c662b00003fbddd Mon Sep 17 00:00:00 2001 From: Eduardo Bacarin Date: Fri, 4 Jul 2025 11:43:43 -0300 Subject: [PATCH 15/32] rework on rules --- src/rules.php | 29 +++++++++++++---------------- 1 file changed, 13 insertions(+), 16 deletions(-) diff --git a/src/rules.php b/src/rules.php index 33d877a..d54bfa2 100644 --- a/src/rules.php +++ b/src/rules.php @@ -1,24 +1,22 @@ 'integer', - 'devedor' => 'array', - 'devedor.documento' => 'string|min:11|max:18', - 'devedor.nome' => 'required_with:devedor.documento|string|max:100', + 'devedor' => 'sometimes|array', + 'devedor.documento' => 'sometimes|string|min:11|max:18', + 'devedor.nome' => 'sometimes|required_with:devedor.documento|string|max:100', 'valor' => 'required|integer|min:1', 'chave' => 'required|string', 'txid' => 'required|string|max:100', 'solicitacaoPagador' => 'string|max:140' ]; - - $validation = (new Factory)->validate($data, $rules); - - if ($validation->fails()) { - throw new Exception(json_encode($validation->errors()->firstOfAll()), 500); + $validate = validate($data, $rules); + if (!$validate['valid']) { + throw new Exception(json_encode(array_slice($validate['errors'], 0, 1)), 500); } else { return true; } @@ -29,19 +27,18 @@ function pixCobrancaImediataSemValorRules(array $data) { $rules = [ 'expiracao' => 'integer', - 'devedor' => 'array', - 'devedor.documento' => 'string|min:11|max:18', - 'devedor.nome' => 'required_with:devedor.documento|string|max:100', + 'devedor' => 'sometimes|array', + 'devedor.documento' => 'sometimes|string|min:11|max:18', + 'devedor.nome' => 'sometimes|required_with:devedor.documento|string|max:100', 'valor' => 'sometimes|integer', 'chave' => 'required|string', 'txid' => 'required|string|max:100', 'solicitacaoPagador' => 'string|max:140' ]; - $validation = (new Factory)->validate($data, $rules); - - if ($validation->fails()) { - throw new Exception(json_encode($validation->errors()->firstOfAll()), 500); + $validate = validate($data, $rules); + if (!$validate['valid']) { + throw new Exception(json_encode(array_slice($validate['errors'], 0, 1)), 500); } else { return true; } From 480cc208d7bdca2ce6db2747dffd5bbd9374b16e Mon Sep 17 00:00:00 2001 From: Eduardo Bacarin Date: Fri, 4 Jul 2025 11:44:27 -0300 Subject: [PATCH 16/32] Rework to be compatible with PHP 7.* --- src/Kore.php | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/src/Kore.php b/src/Kore.php index 2c15dcb..8549a08 100644 --- a/src/Kore.php +++ b/src/Kore.php @@ -7,17 +7,21 @@ use phpseclib3\Crypt\PublicKeyLoader; class Kore { private $url = 'https://httpbin.org'; + public $privateKey; + public $drone; + public function __construct($privateKey, $drone) { + $this->privateKey = $privateKey; + $this->drone = $drone; + } - public function __construct(public $privateKey, public $drone) {} - - public function signBody(string|array $body, string|bool $password = false) + public function signBody($body, $password = false) { $privateKey = PublicKeyLoader::loadPrivateKey(base64_decode($this->privateKey), $password); $sig = $privateKey->sign(json_encode($body)); return base64_encode($sig); } - public function verifySignature(string $signature, string|array $message, $key) + public function verifySignature($signature, $message, $key) { $publicKey = PublicKeyLoader::loadPublicKey($key); return $publicKey->verify(json_encode($message), $signature); From 507e68a15363d3ad704acc92a994446b81fce35e Mon Sep 17 00:00:00 2001 From: Eduardo Bacarin Date: Fri, 4 Jul 2025 11:45:50 -0300 Subject: [PATCH 17/32] Rework to be compatible with PHP 7.* --- src/helpers.php | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/helpers.php b/src/helpers.php index 517c0d2..fb783cb 100644 --- a/src/helpers.php +++ b/src/helpers.php @@ -2,11 +2,11 @@ if (!function_exists('curlRequest')) { function curlRequest( - string $url, - string $method = 'GET', - array $queryParams = [], - array $headers = [], - array|string|null $body = null + $url, + $method = 'GET', + $queryParams = [], + $headers = [], + $body = null ): array { $curl = curl_init(); From 876ea2b8680a25c97ef1725c93ef8c5112227f14 Mon Sep 17 00:00:00 2001 From: Eduardo Bacarin Date: Fri, 4 Jul 2025 11:47:50 -0300 Subject: [PATCH 18/32] Removing old package to made validation --- composer.json | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/composer.json b/composer.json index 0a60726..e4787ba 100644 --- a/composer.json +++ b/composer.json @@ -17,7 +17,6 @@ } ], "require": { - "phpseclib/phpseclib": "~3.0", - "somnambulist/validation": "^1.12" + "phpseclib/phpseclib": "~3.0" } } From df99b098e30840845b0f1c82e2230693b9c6e5ab Mon Sep 17 00:00:00 2001 From: Eduardo Bacarin Date: Fri, 4 Jul 2025 11:48:06 -0300 Subject: [PATCH 19/32] Started documentation --- README.md | 92 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 92 insertions(+) create mode 100644 README.md diff --git a/README.md b/README.md new file mode 100644 index 0000000..58b3efa --- /dev/null +++ b/README.md @@ -0,0 +1,92 @@ +## KORE PHP LIB ## + +### Classe: `PIX` + +**Descrição:** +Classe padrão para consumo das funções de PIX do Kore, utilizado para gerar cobranças, transferir valores e etc. + +**Como Usar** +```php +$class = new \Kontrl\PhpKore\Pix($priv, $drone); +``` + +**Parâmetros:** + +| Nome | Tipo | Obrigatório | Descrição | +|----------|--------|-------------|---------------------------------------------| +| `$priv` | string | Sim | Chave privada para assinatura da requisição | +| `$drone` | string | Sim | ID do drone gerado e fornecido pela Kontrl | + + + +### Função: `pixCobrancaDinamicoImediataSemValor` + +**Descrição:** +Gera uma cobrança PIX dinâmica e imediata sem valor predefinido, ou com valor sugerido. O usuário pagador poderá alterar o valor na hora do pagamento. + +**Como usar:** +```php +$class = new \Kontrl\PhpKore\Pix($priv, $drone); +$class->pixCobrancaDinamicoImediataSemValor($dados); +``` + +**Parâmetros:** + +| Nome | Tipo | Obrigatório | Padrão | Descrição | +|----------|-------|-------------|--------|-----------------------------------------------------------------| +| `$dados` | array | Sim | — | Um array com os dados a serem enviados para geração da cobrança | + +**Dados:** + +| Chave | Tipo | Obrigatório | Descrição | Exemplo | +|----------------------|--------|-------------------------------------------|--------------------------------|-------------------------| +| `expiracao` | int | Sim | Tempo de expiração em segundos | `3600` | +| `devedor.documento` | string | Não | Documento do pagador | `"09432312054"` | +| `devedor.nome` | string | Não, somente se o documento for informado | Nome do pagador | `"Fulano da Silva"` | +| `valor` | int | Não | Valor sugerido | `10000` (R$100,00) | +| `chave` | string | Sim | Chave Pix de destino | `"12345678911"` | +| `txid` | string | Sim | Identificador da transação | `"098765432111"` | +| `solicitacaoPagador` | string | Não | Mensagem opcional ao pagador | `"Mensagem ao usuário"` | + +**Retorno:** +Tipo: `array` + +**Notas adicionais:** +- Lança `Exception` se algum dado obrigatório do array estiver vazio ou inválido. + + + +### Função: `pixCobrancaDinamicoImediataComValor` + +**Descrição:** +Gera uma cobrança PIX dinâmica e imediata com valor predefinido, o usuário pagador não poderá alterar o valor ao efetuar a cobrança. + +**Como usar:** +```php +$class = new \Kontrl\PhpKore\Pix($priv, $drone); +$class->pixCobrancaDinamicoImediataComValor($dados); +``` + +**Parâmetros:** + +| Nome | Tipo | Obrigatório | Padrão | Descrição | +|----------|-------|-------------|--------|-----------------------------------------------------------------| +| `$dados` | array | Sim | — | Um array com os dados a serem enviados para geração da cobrança | + +**Dados:** + +| Chave | Tipo | Obrigatório | Descrição | Exemplo | +|----------------------|--------|-------------------------------------------|--------------------------------|-------------------------| +| `expiracao` | int | Sim | Tempo de expiração em segundos | `3600` | +| `devedor.documento` | string | Não | Documento do pagador | `"09432312054"` | +| `devedor.nome` | string | Não, somente se o documento for informado | Nome do pagador | `"Fulano da Silva"` | +| `valor` | int | Sim | Valor sugerido | `10000` (R$100,00) | +| `chave` | string | Sim | Chave Pix de destino | `"12345678911"` | +| `txid` | string | Sim | Identificador da transação | `"098765432111"` | +| `solicitacaoPagador` | string | Não | Mensagem opcional ao pagador | `"Mensagem ao usuário"` | + +**Retorno:** +Tipo: `array` + +**Notas adicionais:** +- Lança `Exception` se algum dado obrigatório do array estiver vazio ou inválido. From 96769b84c5c1ef3ac9c83311896c9cf45ee50071 Mon Sep 17 00:00:00 2001 From: Eduardo Bacarin Date: Fri, 4 Jul 2025 16:44:14 -0300 Subject: [PATCH 20/32] =?UTF-8?q?Pix=20Cobran=C3=A7a=20Din=C3=A2mico=20Ime?= =?UTF-8?q?diata=20Saque=20Sem=20Valor?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/Pix.php | 45 +++++++++++++++++++++++++++++++++++++++++++++ src/rules.php | 24 ++++++++++++++++++++++++ src/validator.php | 16 ++++++++++++++++ 3 files changed, 85 insertions(+) diff --git a/src/Pix.php b/src/Pix.php index d0f02a6..cc66bc5 100644 --- a/src/Pix.php +++ b/src/Pix.php @@ -79,4 +79,49 @@ class Pix extends Kore $payload ); } + + + public function pixCobrancaDinamicoImediatoSaqueSemValor($payload) + { + pixCobrancaImediataSaqueSemValorRules($payload); + $korePayload = [ + 'calendario' => [ + 'expiracao' => $payload['expiracao'] ?? 86400, + ], + 'valor' => [ + 'original' => 0, + 'retirada' => [ + 'saque' => [ + 'valor' => $payload['valor'] ?? 0, + 'modalidadeAlteracao' => 0, + 'prestadorDoServicoDeSaque' => $payload['ispb'], + 'modalidadeAgente' => $payload['modalidadeAgente'] + ] + ] + ], + 'chave' => $payload['chave'], + 'txid' => $payload['txid'], + 'solicitacaoPagador' => $payload['solicitacaoPagador'] ?? null + ]; + + if (isset($payload['devedor'])){ + if (strlen($payload['devedor']['documento']) > 11){ + $korePayload['devedor']['cnpj'] = $payload['devedor']['documento']; + }else{ + $korePayload['devedor']['cpf'] = $payload['devedor']['documento']; + } + $korePayload['devedor']['nome'] = $payload['devedor']; + } + + return curlRequest( + 'https://httpbin.org/post', + 'POST', + [], + [ + 'x-kore-drone-uid: drone:' . $this->drone, + 'x-kore-drone-sign: ' . $this->signBody($korePayload) + ], + $payload + ); + } } diff --git a/src/rules.php b/src/rules.php index d54bfa2..20ec273 100644 --- a/src/rules.php +++ b/src/rules.php @@ -43,3 +43,27 @@ function pixCobrancaImediataSemValorRules(array $data) return true; } } + + +function pixCobrancaImediataSaqueSemValorRules(array $data) +{ + $rules = [ + 'expiracao' => 'integer', + 'devedor' => 'sometimes|array', + 'devedor.documento' => 'sometimes|string|min:11|max:18', + 'devedor.nome' => 'sometimes|required_with:devedor.documento|string|max:100', + 'valor' => 'sometimes|integer', + 'chave' => 'required|string', + 'txid' => 'required|string|max:100', + 'solicitacaoPagador' => 'string|max:140', + 'ispb' => 'required|string', + 'modalidadeAgente' => 'required|string|in:agtec,agtot,agpss' + ]; + + $validate = validate($data, $rules); + if (!$validate['valid']) { + throw new Exception(json_encode(array_slice($validate['errors'], 0, 1)), 500); + } else { + return true; + } +} diff --git a/src/validator.php b/src/validator.php index a3a1403..42033d8 100644 --- a/src/validator.php +++ b/src/validator.php @@ -80,6 +80,22 @@ function validate_array($field, $value, $param = null, $data = []) return true; } +function validate_in($field, $value, $param, $data = []) +{ + if ($param === null) { + return "The rule 'in' requires a list of accepted values."; + } + + $accepted = explode(',', $param); + + if (!in_array((string) $value, $accepted, true)) { + return "The field '$field' must be one of: " . implode(', ', $accepted) . "."; + } + + return true; +} + + function validate_integer($field, $value, $param = null, $data = []) { if (!is_int($value)) { From 4cf3ecc86760bffef12251f41395ff777534c972 Mon Sep 17 00:00:00 2001 From: Eduardo Bacarin Date: Fri, 4 Jul 2025 16:49:35 -0300 Subject: [PATCH 21/32] =?UTF-8?q?Pix=20Cobran=C3=A7a=20Din=C3=A2mico=20Ime?= =?UTF-8?q?diata=20Saque=20Com=20Valor?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/Pix.php | 70 +++++++++++++++++++++++++++++++++++++++++---------- src/rules.php | 37 +++++++++++++++++++++------ 2 files changed, 86 insertions(+), 21 deletions(-) diff --git a/src/Pix.php b/src/Pix.php index cc66bc5..0561dfe 100644 --- a/src/Pix.php +++ b/src/Pix.php @@ -22,15 +22,15 @@ class Pix extends Kore 'solicitacaoPagador' => $payload['solicitacaoPagador'] ?? null ]; - if (isset($payload['devedor'])){ - if (strlen($payload['devedor']['documento']) > 11){ + if (isset($payload['devedor'])) { + if (strlen($payload['devedor']['documento']) > 11) { $korePayload['devedor']['cnpj'] = $payload['devedor']['documento']; - }else{ + } else { $korePayload['devedor']['cpf'] = $payload['devedor']['documento']; } $korePayload['devedor']['nome'] = $payload['devedor']; } - + return curlRequest( 'https://httpbin.org/post', 'POST', @@ -59,15 +59,15 @@ class Pix extends Kore 'solicitacaoPagador' => $payload['solicitacaoPagador'] ?? null ]; - if (isset($payload['devedor'])){ - if (strlen($payload['devedor']['documento']) > 11){ + if (isset($payload['devedor'])) { + if (strlen($payload['devedor']['documento']) > 11) { $korePayload['devedor']['cnpj'] = $payload['devedor']['documento']; - }else{ + } else { $korePayload['devedor']['cpf'] = $payload['devedor']['documento']; } $korePayload['devedor']['nome'] = $payload['devedor']; } - + return curlRequest( 'https://httpbin.org/post', 'POST', @@ -80,7 +80,7 @@ class Pix extends Kore ); } - + public function pixCobrancaDinamicoImediatoSaqueSemValor($payload) { pixCobrancaImediataSaqueSemValorRules($payload); @@ -93,6 +93,50 @@ class Pix extends Kore 'retirada' => [ 'saque' => [ 'valor' => $payload['valor'] ?? 0, + 'modalidadeAlteracao' => 1, + 'prestadorDoServicoDeSaque' => $payload['ispb'], + 'modalidadeAgente' => $payload['modalidadeAgente'] + ] + ] + ], + 'chave' => $payload['chave'], + 'txid' => $payload['txid'], + 'solicitacaoPagador' => $payload['solicitacaoPagador'] ?? null + ]; + + if (isset($payload['devedor'])) { + if (strlen($payload['devedor']['documento']) > 11) { + $korePayload['devedor']['cnpj'] = $payload['devedor']['documento']; + } else { + $korePayload['devedor']['cpf'] = $payload['devedor']['documento']; + } + $korePayload['devedor']['nome'] = $payload['devedor']; + } + + return curlRequest( + 'https://httpbin.org/post', + 'POST', + [], + [ + 'x-kore-drone-uid: drone:' . $this->drone, + 'x-kore-drone-sign: ' . $this->signBody($korePayload) + ], + $payload + ); + } + + public function pixCobrancaDinamicoImediatoSaqueComValor($payload) + { + pixCobrancaImediataSaqueComValorRules($payload); + $korePayload = [ + 'calendario' => [ + 'expiracao' => $payload['expiracao'] ?? 86400, + ], + 'valor' => [ + 'original' => 0, + 'retirada' => [ + 'saque' => [ + 'valor' => $payload['valor'], 'modalidadeAlteracao' => 0, 'prestadorDoServicoDeSaque' => $payload['ispb'], 'modalidadeAgente' => $payload['modalidadeAgente'] @@ -104,15 +148,15 @@ class Pix extends Kore 'solicitacaoPagador' => $payload['solicitacaoPagador'] ?? null ]; - if (isset($payload['devedor'])){ - if (strlen($payload['devedor']['documento']) > 11){ + if (isset($payload['devedor'])) { + if (strlen($payload['devedor']['documento']) > 11) { $korePayload['devedor']['cnpj'] = $payload['devedor']['documento']; - }else{ + } else { $korePayload['devedor']['cpf'] = $payload['devedor']['documento']; } $korePayload['devedor']['nome'] = $payload['devedor']; } - + return curlRequest( 'https://httpbin.org/post', 'POST', diff --git a/src/rules.php b/src/rules.php index 20ec273..38e37c3 100644 --- a/src/rules.php +++ b/src/rules.php @@ -1,11 +1,11 @@ 'integer', + 'expiracao' => 'sometimes|integer', 'devedor' => 'sometimes|array', 'devedor.documento' => 'sometimes|string|min:11|max:18', 'devedor.nome' => 'sometimes|required_with:devedor.documento|string|max:100', @@ -22,11 +22,10 @@ function pixCobrancaImediataComValorRules(array $data) } } - function pixCobrancaImediataSemValorRules(array $data) { $rules = [ - 'expiracao' => 'integer', + 'expiracao' => 'sometimes|integer', 'devedor' => 'sometimes|array', 'devedor.documento' => 'sometimes|string|min:11|max:18', 'devedor.nome' => 'sometimes|required_with:devedor.documento|string|max:100', @@ -35,7 +34,7 @@ function pixCobrancaImediataSemValorRules(array $data) 'txid' => 'required|string|max:100', 'solicitacaoPagador' => 'string|max:140' ]; - + $validate = validate($data, $rules); if (!$validate['valid']) { throw new Exception(json_encode(array_slice($validate['errors'], 0, 1)), 500); @@ -44,11 +43,10 @@ function pixCobrancaImediataSemValorRules(array $data) } } - function pixCobrancaImediataSaqueSemValorRules(array $data) { $rules = [ - 'expiracao' => 'integer', + 'expiracao' => 'sometimes|integer', 'devedor' => 'sometimes|array', 'devedor.documento' => 'sometimes|string|min:11|max:18', 'devedor.nome' => 'sometimes|required_with:devedor.documento|string|max:100', @@ -59,7 +57,30 @@ function pixCobrancaImediataSaqueSemValorRules(array $data) 'ispb' => 'required|string', 'modalidadeAgente' => 'required|string|in:agtec,agtot,agpss' ]; - + + $validate = validate($data, $rules); + if (!$validate['valid']) { + throw new Exception(json_encode(array_slice($validate['errors'], 0, 1)), 500); + } else { + return true; + } +} + +function pixCobrancaImediataSaqueComValorRules(array $data) +{ + $rules = [ + 'expiracao' => 'sometimes|integer', + 'devedor' => 'sometimes|array', + 'devedor.documento' => 'sometimes|string|min:11|max:18', + 'devedor.nome' => 'sometimes|required_with:devedor.documento|string|max:100', + 'valor' => 'required|integer', + 'chave' => 'required|string', + 'txid' => 'required|string|max:100', + 'solicitacaoPagador' => 'string|max:140', + 'ispb' => 'required|string', + 'modalidadeAgente' => 'required|string|in:agtec,agtot,agpss' + ]; + $validate = validate($data, $rules); if (!$validate['valid']) { throw new Exception(json_encode(array_slice($validate['errors'], 0, 1)), 500); From a9abbfe932453702704eb0a5e593f23294d3e203 Mon Sep 17 00:00:00 2001 From: Eduardo Bacarin Date: Fri, 4 Jul 2025 16:57:17 -0300 Subject: [PATCH 22/32] setted server url as a class property and consumes it in every function --- src/Kore.php | 2 +- src/Pix.php | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/Kore.php b/src/Kore.php index 8549a08..22347e9 100644 --- a/src/Kore.php +++ b/src/Kore.php @@ -6,7 +6,7 @@ use phpseclib3\Crypt\PublicKeyLoader; class Kore { - private $url = 'https://httpbin.org'; + public $url = 'https://httpbin.org'; public $privateKey; public $drone; public function __construct($privateKey, $drone) { diff --git a/src/Pix.php b/src/Pix.php index 0561dfe..23c97bc 100644 --- a/src/Pix.php +++ b/src/Pix.php @@ -32,7 +32,7 @@ class Pix extends Kore } return curlRequest( - 'https://httpbin.org/post', + $this->url . '/post', 'POST', [], [ @@ -69,7 +69,7 @@ class Pix extends Kore } return curlRequest( - 'https://httpbin.org/post', + $this->url . '/post', 'POST', [], [ @@ -114,7 +114,7 @@ class Pix extends Kore } return curlRequest( - 'https://httpbin.org/post', + $this->url . '/post', 'POST', [], [ @@ -158,7 +158,7 @@ class Pix extends Kore } return curlRequest( - 'https://httpbin.org/post', + $this->url . '/post', 'POST', [], [ From d26f5850f979405fefb54e7dd2bd5fae95efc347 Mon Sep 17 00:00:00 2001 From: Eduardo Bacarin Date: Fri, 4 Jul 2025 17:27:44 -0300 Subject: [PATCH 23/32] =?UTF-8?q?Pix=20Cobran=C3=A7a=20Din=C3=A2mico=20Ime?= =?UTF-8?q?diata=20Troco=20Sem=20Valor?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/Pix.php | 45 +++++++++++++++++++++++++++++++++++++++++++++ src/rules.php | 23 +++++++++++++++++++++++ 2 files changed, 68 insertions(+) diff --git a/src/Pix.php b/src/Pix.php index 23c97bc..e508a6d 100644 --- a/src/Pix.php +++ b/src/Pix.php @@ -168,4 +168,49 @@ class Pix extends Kore $payload ); } + + public function pixCobrancaDinamicoImediatoTrocoSemValor($payload) + { + pixCobrancaImediataTrocoSemValorRules($payload); + $korePayload = [ + 'calendario' => [ + 'expiracao' => $payload['expiracao'] ?? 86400, + ], + 'valor' => [ + 'original' => 0, + 'retirada' => [ + 'troco' => [ + 'valor' => $payload['valor'] ?? 0, + 'modalidadeAlteracao' => 1, + 'prestadorDoServicoDeSaque' => $payload['ispb'], + 'modalidadeAgente' => $payload['modalidadeAgente'] + ] + ] + ], + 'chave' => $payload['chave'], + 'txid' => $payload['txid'], + 'solicitacaoPagador' => $payload['solicitacaoPagador'] ?? null + ]; + + if (isset($payload['devedor'])) { + if (strlen($payload['devedor']['documento']) > 11) { + $korePayload['devedor']['cnpj'] = $payload['devedor']['documento']; + } else { + $korePayload['devedor']['cpf'] = $payload['devedor']['documento']; + } + $korePayload['devedor']['nome'] = $payload['devedor']; + } + + return curlRequest( + $this->url . '/post', + 'POST', + [], + [ + 'x-kore-drone-uid: drone:' . $this->drone, + 'x-kore-drone-sign: ' . $this->signBody($korePayload) + ], + $payload + ); + } + } diff --git a/src/rules.php b/src/rules.php index 38e37c3..f8d4051 100644 --- a/src/rules.php +++ b/src/rules.php @@ -88,3 +88,26 @@ function pixCobrancaImediataSaqueComValorRules(array $data) return true; } } + +function pixCobrancaImediataTrocoSemValorRules(array $data) +{ + $rules = [ + 'expiracao' => 'sometimes|integer', + 'devedor' => 'sometimes|array', + 'devedor.documento' => 'sometimes|string|min:11|max:18', + 'devedor.nome' => 'sometimes|required_with:devedor.documento|string|max:100', + 'valor' => 'sometimes|integer', + 'chave' => 'required|string', + 'txid' => 'required|string|max:100', + 'solicitacaoPagador' => 'string|max:140', + 'ispb' => 'required|string', + 'modalidadeAgente' => 'required|string|in:agtec,agtot' + ]; + + $validate = validate($data, $rules); + if (!$validate['valid']) { + throw new Exception(json_encode(array_slice($validate['errors'], 0, 1)), 500); + } else { + return true; + } +} From 5da8edc42661706fca0abf6075cf55fab178900a Mon Sep 17 00:00:00 2001 From: Eduardo Bacarin Date: Fri, 4 Jul 2025 17:28:56 -0300 Subject: [PATCH 24/32] =?UTF-8?q?Pix=20Cobran=C3=A7a=20Din=C3=A2mico=20Ime?= =?UTF-8?q?diata=20Troco=20Com=20Valor?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/Pix.php | 42 ++++++++++++++++++++++++++++++++++++++++++ src/rules.php | 23 +++++++++++++++++++++++ 2 files changed, 65 insertions(+) diff --git a/src/Pix.php b/src/Pix.php index e508a6d..9f3e61f 100644 --- a/src/Pix.php +++ b/src/Pix.php @@ -212,5 +212,47 @@ class Pix extends Kore $payload ); } + public function pixCobrancaDinamicoImediatoTrocoComValor($payload) + { + pixCobrancaImediataTrocoComValorRules($payload); + $korePayload = [ + 'calendario' => [ + 'expiracao' => $payload['expiracao'] ?? 86400, + ], + 'valor' => [ + 'original' => 0, + 'retirada' => [ + 'troco' => [ + 'valor' => $payload['valor'], + 'modalidadeAlteracao' => 0, + 'prestadorDoServicoDeSaque' => $payload['ispb'], + 'modalidadeAgente' => $payload['modalidadeAgente'] + ] + ] + ], + 'chave' => $payload['chave'], + 'txid' => $payload['txid'], + 'solicitacaoPagador' => $payload['solicitacaoPagador'] ?? null + ]; + if (isset($payload['devedor'])) { + if (strlen($payload['devedor']['documento']) > 11) { + $korePayload['devedor']['cnpj'] = $payload['devedor']['documento']; + } else { + $korePayload['devedor']['cpf'] = $payload['devedor']['documento']; + } + $korePayload['devedor']['nome'] = $payload['devedor']; + } + + return curlRequest( + $this->url . '/post', + 'POST', + [], + [ + 'x-kore-drone-uid: drone:' . $this->drone, + 'x-kore-drone-sign: ' . $this->signBody($korePayload) + ], + $payload + ); + } } diff --git a/src/rules.php b/src/rules.php index f8d4051..83a4231 100644 --- a/src/rules.php +++ b/src/rules.php @@ -111,3 +111,26 @@ function pixCobrancaImediataTrocoSemValorRules(array $data) return true; } } + +function pixCobrancaImediataTrocoComValorRules(array $data) +{ + $rules = [ + 'expiracao' => 'sometimes|integer', + 'devedor' => 'sometimes|array', + 'devedor.documento' => 'sometimes|string|min:11|max:18', + 'devedor.nome' => 'sometimes|required_with:devedor.documento|string|max:100', + 'valor' => 'sometimes|integer', + 'chave' => 'required|string', + 'txid' => 'required|string|max:100', + 'solicitacaoPagador' => 'string|max:140', + 'ispb' => 'required|string', + 'modalidadeAgente' => 'required|string|in:agtec,agtot' + ]; + + $validate = validate($data, $rules); + if (!$validate['valid']) { + throw new Exception(json_encode(array_slice($validate['errors'], 0, 1)), 500); + } else { + return true; + } +} From 847da21c0253b3863611ec8cd490163f49c21048 Mon Sep 17 00:00:00 2001 From: Eduardo Bacarin Date: Mon, 7 Jul 2025 14:24:13 -0300 Subject: [PATCH 25/32] PixTroco e PixSaque documentation --- README.md | 193 +++++++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 191 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 58b3efa..fe29412 100644 --- a/README.md +++ b/README.md @@ -59,7 +59,7 @@ Tipo: `array` ### Função: `pixCobrancaDinamicoImediataComValor` **Descrição:** -Gera uma cobrança PIX dinâmica e imediata com valor predefinido, o usuário pagador não poderá alterar o valor ao efetuar a cobrança. +Gera uma cobrança PIX dinâmica e imediata com valor predefinido, o usuário pagador não poderá alterar o valor ao efetuar o pagamento. **Como usar:** ```php @@ -89,4 +89,193 @@ $class->pixCobrancaDinamicoImediataComValor($dados); Tipo: `array` **Notas adicionais:** -- Lança `Exception` se algum dado obrigatório do array estiver vazio ou inválido. +- Lança `Exception` se algum dado obrigatório do array estiver vazio ou inválido. + + +### Função: `pixCobrancaDinamicoImediataComValor` + +**Descrição:** +Gera uma cobrança PIX dinâmica e imediata com valor predefinido, o usuário pagador não poderá alterar o valor ao efetuar o pagamento. + +**Como usar:** +```php +$class = new \Kontrl\PhpKore\Pix($priv, $drone); +$class->pixCobrancaDinamicoImediataComValor($dados); +``` + +**Parâmetros:** + +| Nome | Tipo | Obrigatório | Padrão | Descrição | +|----------|-------|-------------|--------|-----------------------------------------------------------------| +| `$dados` | array | Sim | — | Um array com os dados a serem enviados para geração da cobrança | + +**Dados:** + +| Chave | Tipo | Obrigatório | Descrição | Exemplo | +|----------------------|--------|-------------------------------------------|--------------------------------|-------------------------| +| `expiracao` | int | Sim | Tempo de expiração em segundos | `3600` | +| `devedor.documento` | string | Não | Documento do pagador | `"09432312054"` | +| `devedor.nome` | string | Não, somente se o documento for informado | Nome do pagador | `"Fulano da Silva"` | +| `valor` | int | Sim | Valor sugerido | `10000` (R$100,00) | +| `chave` | string | Sim | Chave Pix de destino | `"12345678911"` | +| `txid` | string | Sim | Identificador da transação | `"098765432111"` | +| `solicitacaoPagador` | string | Não | Mensagem opcional ao pagador | `"Mensagem ao usuário"` | + +**Retorno:** +Tipo: `array` + +**Notas adicionais:** +- Lança `Exception` se algum dado obrigatório do array estiver vazio ou inválido. + + +### Função: `pixCobrancaDinamicoImediataSaqueComValor` + +**Descrição:** +Gera uma cobrança PIX dinâmica e imediata para SAQUE com valor predefinido, o usuário pagador não poderá alterar o valor ao efetuar o pagamento. + +**Como usar:** +```php +$class = new \Kontrl\PhpKore\Pix($priv, $drone); +$class->pixCobrancaDinamicoImediatoSaqueComValor($dados); +``` + +**Parâmetros:** + +| Nome | Tipo | Obrigatório | Padrão | Descrição | +|----------|-------|-------------|--------|-----------------------------------------------------------------| +| `$dados` | array | Sim | — | Um array com os dados a serem enviados para geração da cobrança | + +**Dados:** + +| Chave | Tipo | Obrigatório | Descrição | Exemplo | +|----------------------|--------|-------------------------------------------|--------------------------------------------------------------------------------------------------------------|-------------------------| +| `expiracao` | int | Sim | Tempo de expiração em segundos | `3600` | +| `devedor.documento` | string | Não | Documento do pagador | `"09432312054"` | +| `devedor.nome` | string | Não, somente se o documento for informado | Nome do pagador | `"Fulano da Silva"` | +| `valor` | int | Sim | Valor do saque | `10000` (R$100,00) | +| `chave` | string | Sim | Chave Pix de destino | `"12345678911"` | +| `txid` | string | Sim | Identificador da transação | `"098765432111"` | +| `solicitacaoPagador` | string | Não | Mensagem opcional ao pagador | `"Mensagem ao usuário"` | +| `ispb` | string | Sim | ISPB da instituição do prestador de serviço do saque | `"33233"` | +| `modalidadeAgente` | string | Sim | Indica a modalidade do agente a qual se dará a facilitação do serviço. DEVE SER: "agtot", "agtec" ou "agpss" | `"agtot"` | + +**Retorno:** +Tipo: `array` + +**Notas adicionais:** +- Lança `Exception` se algum dado obrigatório do array estiver vazio ou inválido. + + +### Função: `pixCobrancaDinamicoImediataSaqueSemValor` + +**Descrição:** +Gera uma cobrança PIX dinâmica e imediata para SAQUE sem valor predefinido, o usuário pagador poderá alterar o valor ao efetuar o pagamento. + +**Como usar:** +```php +$class = new \Kontrl\PhpKore\Pix($priv, $drone); +$class->pixCobrancaDinamicoImediatoSaqueSemValor($dados); +``` + +**Parâmetros:** + +| Nome | Tipo | Obrigatório | Padrão | Descrição | +|----------|-------|-------------|--------|-----------------------------------------------------------------| +| `$dados` | array | Sim | — | Um array com os dados a serem enviados para geração da cobrança | + +**Dados:** + +| Chave | Tipo | Obrigatório | Descrição | Exemplo | +|----------------------|--------|-------------------------------------------|--------------------------------------------------------------------------------------------------------------|-------------------------| +| `expiracao` | int | Sim | Tempo de expiração em segundos | `3600` | +| `devedor.documento` | string | Não | Documento do pagador | `"09432312054"` | +| `devedor.nome` | string | Não, somente se o documento for informado | Nome do pagador | `"Fulano da Silva"` | +| `valor` | int | Não | Valor sugerido | `10000` (R$100,00) | +| `chave` | string | Sim | Chave Pix de destino | `"12345678911"` | +| `txid` | string | Sim | Identificador da transação | `"098765432111"` | +| `solicitacaoPagador` | string | Não | Mensagem opcional ao pagador | `"Mensagem ao usuário"` | +| `ispb` | string | Sim | ISPB da instituição do prestador de serviço do saque | `"33233"` | +| `modalidadeAgente` | string | Sim | Indica a modalidade do agente a qual se dará a facilitação do serviço. DEVE SER: "agtot", "agtec" ou "agpss" | `"agtot"` | + +**Retorno:** +Tipo: `array` + +**Notas adicionais:** +- Lança `Exception` se algum dado obrigatório do array estiver vazio ou inválido. + + + +### Função: `pixCobrancaDinamicoImediataTrocoComValor` + +**Descrição:** +Gera uma cobrança PIX dinâmica e imediata para TROCO com valor predefinido, o usuário pagador não poderá alterar o valor ao efetuar o pagamento. + +**Como usar:** +```php +$class = new \Kontrl\PhpKore\Pix($priv, $drone); +$class->pixCobrancaDinamicoImediatoTrocoComValor($dados); +``` + +**Parâmetros:** + +| Nome | Tipo | Obrigatório | Padrão | Descrição | +|----------|-------|-------------|--------|-----------------------------------------------------------------| +| `$dados` | array | Sim | — | Um array com os dados a serem enviados para geração da cobrança | + +**Dados:** + +| Chave | Tipo | Obrigatório | Descrição | Exemplo | +|----------------------|--------|-------------------------------------------|-----------------------------------------------------------------------------------------------------|-------------------------| +| `expiracao` | int | Sim | Tempo de expiração em segundos | `3600` | +| `devedor.documento` | string | Não | Documento do pagador | `"09432312054"` | +| `devedor.nome` | string | Não, somente se o documento for informado | Nome do pagador | `"Fulano da Silva"` | +| `valor` | int | Sim | Valor do troco | `10000` (R$100,00) | +| `chave` | string | Sim | Chave Pix de destino | `"12345678911"` | +| `txid` | string | Sim | Identificador da transação | `"098765432111"` | +| `solicitacaoPagador` | string | Não | Mensagem opcional ao pagador | `"Mensagem ao usuário"` | +| `ispb` | string | Sim | ISPB da instituição do prestador de serviço do troco | `"33233"` | +| `modalidadeAgente` | string | Sim | Indica a modalidade do agente a qual se dará a facilitação do serviço. DEVE SER: "agtot" ou "agtec" | `"agtot"` | + +**Retorno:** +Tipo: `array` + +**Notas adicionais:** +- Lança `Exception` se algum dado obrigatório do array estiver vazio ou inválido. + + +### Função: `pixCobrancaDinamicoImediataTrocoSemValor` + +**Descrição:** +Gera uma cobrança PIX dinâmica e imediata para TROCO sem valor predefinido, o usuário pagador poderá alterar o valor ao efetuar o pagamento. + +**Como usar:** +```php +$class = new \Kontrl\PhpKore\Pix($priv, $drone); +$class->pixCobrancaDinamicoImediatoTrocoSemValor($dados); +``` + +**Parâmetros:** + +| Nome | Tipo | Obrigatório | Padrão | Descrição | +|----------|-------|-------------|--------|-----------------------------------------------------------------| +| `$dados` | array | Sim | — | Um array com os dados a serem enviados para geração da cobrança | + +**Dados:** + +| Chave | Tipo | Obrigatório | Descrição | Exemplo | +|----------------------|--------|-------------------------------------------|-----------------------------------------------------------------------------------------------------|-------------------------| +| `expiracao` | int | Sim | Tempo de expiração em segundos | `3600` | +| `devedor.documento` | string | Não | Documento do pagador | `"09432312054"` | +| `devedor.nome` | string | Não, somente se o documento for informado | Nome do pagador | `"Fulano da Silva"` | +| `valor` | int | Não | Valor sugerido | `10000` (R$100,00) | +| `chave` | string | Sim | Chave Pix de destino | `"12345678911"` | +| `txid` | string | Sim | Identificador da transação | `"098765432111"` | +| `solicitacaoPagador` | string | Não | Mensagem opcional ao pagador | `"Mensagem ao usuário"` | +| `ispb` | string | Sim | ISPB da instituição do prestador de serviço do troco | `"33233"` | +| `modalidadeAgente` | string | Sim | Indica a modalidade do agente a qual se dará a facilitação do serviço. DEVE SER: "agtot" ou "agtec" | `"agtot"` | + +**Retorno:** +Tipo: `array` + +**Notas adicionais:** +- Lança `Exception` se algum dado obrigatório do array estiver vazio ou inválido. From 1eea65bef76413b37274e71545517cfdea075c09 Mon Sep 17 00:00:00 2001 From: Eduardo Bacarin Date: Mon, 7 Jul 2025 15:05:13 -0300 Subject: [PATCH 26/32] Index on docs --- README.md | 48 +++++++++++------------------------------------- 1 file changed, 11 insertions(+), 37 deletions(-) diff --git a/README.md b/README.md index fe29412..488e412 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,16 @@ ## KORE PHP LIB ## + +## Índice + +- [Classe: `PIX`](#classe-pix) +- [Função: `pixCobrancaDinamicoImediataSemValor`](#função-pixcobrancadinamicoimediatasemvalor) +- [Função: `pixCobrancaDinamicoImediataComValor`](#função-pixcobrancadinamicoimediatacomvalor) +- [Função: `pixCobrancaDinamicoImediataSaqueComValor`](#função-pixcobrancadinamicoimediatasaquecomvalor) +- [Função: `pixCobrancaDinamicoImediataSaqueSemValor`](#função-pixcobrancadinamicoimediatasaquesemvalor) +- [Função: `pixCobrancaDinamicoImediataTrocoComValor`](#função-pixcobrancadinamicoimediatatrococomvalor) +- [Função: `pixCobrancaDinamicoImediataTrocoSemValor`](#função-pixcobrancadinamicoimediatatrocosemvalor) + ### Classe: `PIX` **Descrição:** @@ -55,43 +66,6 @@ Tipo: `array` - Lança `Exception` se algum dado obrigatório do array estiver vazio ou inválido. - -### Função: `pixCobrancaDinamicoImediataComValor` - -**Descrição:** -Gera uma cobrança PIX dinâmica e imediata com valor predefinido, o usuário pagador não poderá alterar o valor ao efetuar o pagamento. - -**Como usar:** -```php -$class = new \Kontrl\PhpKore\Pix($priv, $drone); -$class->pixCobrancaDinamicoImediataComValor($dados); -``` - -**Parâmetros:** - -| Nome | Tipo | Obrigatório | Padrão | Descrição | -|----------|-------|-------------|--------|-----------------------------------------------------------------| -| `$dados` | array | Sim | — | Um array com os dados a serem enviados para geração da cobrança | - -**Dados:** - -| Chave | Tipo | Obrigatório | Descrição | Exemplo | -|----------------------|--------|-------------------------------------------|--------------------------------|-------------------------| -| `expiracao` | int | Sim | Tempo de expiração em segundos | `3600` | -| `devedor.documento` | string | Não | Documento do pagador | `"09432312054"` | -| `devedor.nome` | string | Não, somente se o documento for informado | Nome do pagador | `"Fulano da Silva"` | -| `valor` | int | Sim | Valor sugerido | `10000` (R$100,00) | -| `chave` | string | Sim | Chave Pix de destino | `"12345678911"` | -| `txid` | string | Sim | Identificador da transação | `"098765432111"` | -| `solicitacaoPagador` | string | Não | Mensagem opcional ao pagador | `"Mensagem ao usuário"` | - -**Retorno:** -Tipo: `array` - -**Notas adicionais:** -- Lança `Exception` se algum dado obrigatório do array estiver vazio ou inválido. - - ### Função: `pixCobrancaDinamicoImediataComValor` **Descrição:** From 3758d3f1d00aff3c66cd8377b1bb5a67c414399d Mon Sep 17 00:00:00 2001 From: Eduardo Bacarin Date: Mon, 7 Jul 2025 18:17:25 -0300 Subject: [PATCH 27/32] function pixCobrancaEstatico --- src/Pix.php | 23 +++++++++++++++++++++++ src/rules.php | 18 ++++++++++++++++++ 2 files changed, 41 insertions(+) diff --git a/src/Pix.php b/src/Pix.php index 9f3e61f..8e9a0d2 100644 --- a/src/Pix.php +++ b/src/Pix.php @@ -255,4 +255,27 @@ class Pix extends Kore $payload ); } + + + public function pixCobrancaEstatico($payload) + { + pixCobrancaEstaticoRules($payload); + $korePayload = [ + 'valor' => $payload['valor'] ?? 0, + 'chave' => $payload['chave'], + 'txid' => $payload['txid'] ?? null, + 'solicitacaoPagador' => $payload['solicitacaoPagador'] ?? null + ]; + + return curlRequest( + $this->url . '/post', + 'POST', + [], + [ + 'x-kore-drone-uid: drone:' . $this->drone, + 'x-kore-drone-sign: ' . $this->signBody($korePayload) + ], + $payload + ); + } } diff --git a/src/rules.php b/src/rules.php index 83a4231..ca217b4 100644 --- a/src/rules.php +++ b/src/rules.php @@ -134,3 +134,21 @@ function pixCobrancaImediataTrocoComValorRules(array $data) return true; } } + + +function pixCobrancaEstaticoRules(array $data) +{ + $rules = [ + 'valor' => 'sometimes|integer', + 'chave' => 'required|string', + 'txid' => 'sometimes|string|max:100', + 'solicitacaoPagador' => 'sometimes|string|max:140', + ]; + + $validate = validate($data, $rules); + if (!$validate['valid']) { + throw new Exception(json_encode(array_slice($validate['errors'], 0, 1)), 500); + } else { + return true; + } +} From 155ac8fd4221daad9f12d84b2b2102947a909b69 Mon Sep 17 00:00:00 2001 From: Eduardo Bacarin Date: Fri, 11 Jul 2025 14:41:29 -0300 Subject: [PATCH 28/32] pixEstatico documentation --- README.md | 34 ++++++++++++++++++++++++++++++++++ 1 file changed, 34 insertions(+) diff --git a/README.md b/README.md index 488e412..d1314f6 100644 --- a/README.md +++ b/README.md @@ -10,6 +10,7 @@ - [Função: `pixCobrancaDinamicoImediataSaqueSemValor`](#função-pixcobrancadinamicoimediatasaquesemvalor) - [Função: `pixCobrancaDinamicoImediataTrocoComValor`](#função-pixcobrancadinamicoimediatatrococomvalor) - [Função: `pixCobrancaDinamicoImediataTrocoSemValor`](#função-pixcobrancadinamicoimediatatrocosemvalor) +- [Função: `pixCobrancaEstatico`](#função-pixcobrancaestatico) ### Classe: `PIX` @@ -253,3 +254,36 @@ Tipo: `array` **Notas adicionais:** - Lança `Exception` se algum dado obrigatório do array estiver vazio ou inválido. + + +### Função: `pixCobrancaEstatico` + +**Descrição:** +Gera uma cobrança PIX estática com ou sem valor predefinido. + +**Como usar:** +```php +$class = new \Kontrl\PhpKore\Pix($priv, $drone); +$class->pixCobrancaEstatico($dados); +``` + +**Parâmetros:** + +| Nome | Tipo | Obrigatório | Padrão | Descrição | +|----------|-------|-------------|--------|-----------------------------------------------------------------| +| `$dados` | array | Sim | — | Um array com os dados a serem enviados para geração da cobrança | + +**Dados:** + +| Chave | Tipo | Obrigatório | Descrição | Exemplo | +|----------------------|--------|-------------------------------------------|--------------------------------|-------------------------| +| `valor` | int | Não | Valor sugerido | `10000` (R$100,00) | +| `chave` | string | Sim | Chave Pix de destino | `"12345678911"` | +| `txid` | string | Sim | Identificador da transação | `"098765432111"` | +| `solicitacaoPagador` | string | Não | Mensagem opcional ao pagador | `"Mensagem ao usuário"` | + +**Retorno:** +Tipo: `array` + +**Notas adicionais:** +- Lança `Exception` se algum dado obrigatório do array estiver vazio ou inválido. From 43f296585b17c59dea4b87328812ef8e5c8d5672 Mon Sep 17 00:00:00 2001 From: Eduardo Bacarin Date: Fri, 11 Jul 2025 15:20:26 -0300 Subject: [PATCH 29/32] update gitignore: ignoring test.php file --- .gitignore | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.gitignore b/.gitignore index 4672d29..5ce73e2 100644 --- a/.gitignore +++ b/.gitignore @@ -2,4 +2,5 @@ vendor/* composer.lock *.key *.pub -index.php \ No newline at end of file +index.php +tests.php From 22a5288af5f94430e481532695521a9eb7d846ea Mon Sep 17 00:00:00 2001 From: Eduardo Bacarin Date: Fri, 11 Jul 2025 15:23:51 -0300 Subject: [PATCH 30/32] Removing testRequest function from Kore class --- src/Kore.php | 11 ----------- 1 file changed, 11 deletions(-) diff --git a/src/Kore.php b/src/Kore.php index 22347e9..6bf034b 100644 --- a/src/Kore.php +++ b/src/Kore.php @@ -26,15 +26,4 @@ class Kore $publicKey = PublicKeyLoader::loadPublicKey($key); return $publicKey->verify(json_encode($message), $signature); } - - public function testRequest() - { - return [ - 'get' => curlRequest($this->url . '/get', 'GET')['status'], - 'post' => curlRequest($this->url . '/post', 'POST', [], [], ['test' => 'test'])['status'], - 'patch' => curlRequest($this->url . '/patch', 'PATCH', [], [], ['test' => 'test'])['status'], - 'put' => curlRequest($this->url . '/put', 'PUT', [], [], ['test' => 'test'])['status'], - 'delete' => curlRequest($this->url . '/delete', 'DELETE')['status'] - ]; - } } From e34c057087ed6dd6a0791f657a98d7fe85528ced Mon Sep 17 00:00:00 2001 From: Eduardo Bacarin Date: Fri, 11 Jul 2025 15:28:25 -0300 Subject: [PATCH 31/32] Environment variable for Kore Class --- README.md | 11 ++++++----- src/Kore.php | 7 +++++-- 2 files changed, 11 insertions(+), 7 deletions(-) diff --git a/README.md b/README.md index d1314f6..7583e6f 100644 --- a/README.md +++ b/README.md @@ -19,15 +19,16 @@ Classe padrão para consumo das funções de PIX do Kore, utilizado para gerar c **Como Usar** ```php -$class = new \Kontrl\PhpKore\Pix($priv, $drone); +$class = new \Kontrl\PhpKore\Pix($priv, $drone, $environment); ``` **Parâmetros:** -| Nome | Tipo | Obrigatório | Descrição | -|----------|--------|-------------|---------------------------------------------| -| `$priv` | string | Sim | Chave privada para assinatura da requisição | -| `$drone` | string | Sim | ID do drone gerado e fornecido pela Kontrl | +| Nome | Tipo | Obrigatório | Descrição | +|----------------|--------|-------------|--------------------------------------------------------------------------| +| `$priv` | string | Sim | Chave privada para assinatura da requisição | +| `$drone` | string | Sim | ID do drone gerado e fornecido pela Kontrl | +| `$environment` | string | Não | Ambiente a ser utilizado - Aceito: **PROD** ou **DEV** - Padrão: **DEV** | diff --git a/src/Kore.php b/src/Kore.php index 6bf034b..0842515 100644 --- a/src/Kore.php +++ b/src/Kore.php @@ -6,12 +6,15 @@ use phpseclib3\Crypt\PublicKeyLoader; class Kore { - public $url = 'https://httpbin.org'; + public $url = 'https://stage.kore.kontrl.tech'; public $privateKey; public $drone; - public function __construct($privateKey, $drone) { + public function __construct($privateKey, $drone, $environment = 'DEV') { $this->privateKey = $privateKey; $this->drone = $drone; + if ($environment == 'PROD'){ + $this->url = 'https://kore.kontrl.tech'; + } } public function signBody($body, $password = false) From 4a3d0684e8adcfd6bb5865c4adfadd5fcd6ce904 Mon Sep 17 00:00:00 2001 From: Eduardo Bacarin Date: Fri, 11 Jul 2025 15:29:29 -0300 Subject: [PATCH 32/32] documentation: updating to show 'environment' variable --- README.md | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/README.md b/README.md index 7583e6f..04aa0a8 100644 --- a/README.md +++ b/README.md @@ -39,7 +39,7 @@ Gera uma cobrança PIX dinâmica e imediata sem valor predefinido, ou com valor **Como usar:** ```php -$class = new \Kontrl\PhpKore\Pix($priv, $drone); +$class = new \Kontrl\PhpKore\Pix($priv, $drone, 'DEV'); $class->pixCobrancaDinamicoImediataSemValor($dados); ``` @@ -75,7 +75,7 @@ Gera uma cobrança PIX dinâmica e imediata com valor predefinido, o usuário pa **Como usar:** ```php -$class = new \Kontrl\PhpKore\Pix($priv, $drone); +$class = new \Kontrl\PhpKore\Pix($priv, $drone, 'DEV'); $class->pixCobrancaDinamicoImediataComValor($dados); ``` @@ -111,7 +111,7 @@ Gera uma cobrança PIX dinâmica e imediata para SAQUE com valor predefinido, o **Como usar:** ```php -$class = new \Kontrl\PhpKore\Pix($priv, $drone); +$class = new \Kontrl\PhpKore\Pix($priv, $drone, 'DEV'); $class->pixCobrancaDinamicoImediatoSaqueComValor($dados); ``` @@ -149,7 +149,7 @@ Gera uma cobrança PIX dinâmica e imediata para SAQUE sem valor predefinido, o **Como usar:** ```php -$class = new \Kontrl\PhpKore\Pix($priv, $drone); +$class = new \Kontrl\PhpKore\Pix($priv, $drone, 'DEV'); $class->pixCobrancaDinamicoImediatoSaqueSemValor($dados); ``` @@ -188,7 +188,7 @@ Gera uma cobrança PIX dinâmica e imediata para TROCO com valor predefinido, o **Como usar:** ```php -$class = new \Kontrl\PhpKore\Pix($priv, $drone); +$class = new \Kontrl\PhpKore\Pix($priv, $drone, 'DEV'); $class->pixCobrancaDinamicoImediatoTrocoComValor($dados); ``` @@ -226,7 +226,7 @@ Gera uma cobrança PIX dinâmica e imediata para TROCO sem valor predefinido, o **Como usar:** ```php -$class = new \Kontrl\PhpKore\Pix($priv, $drone); +$class = new \Kontrl\PhpKore\Pix($priv, $drone, 'DEV'); $class->pixCobrancaDinamicoImediatoTrocoSemValor($dados); ``` @@ -264,7 +264,7 @@ Gera uma cobrança PIX estática com ou sem valor predefinido. **Como usar:** ```php -$class = new \Kontrl\PhpKore\Pix($priv, $drone); +$class = new \Kontrl\PhpKore\Pix($priv, $drone, 'DEV'); $class->pixCobrancaEstatico($dados); ```