allow vendord
All checks were successful
Build, Push and Deploy / build-and-push (push) Successful in 3m3s
Gitea Actions Demo / Explore-Gitea-Actions (push) Successful in 16s
Build, Push and Deploy / deploy-staging (push) Successful in 32s
Build, Push and Deploy / deploy-production (push) Has been skipped
Build, Push and Deploy / cleanup (push) Successful in 1s

This commit is contained in:
2026-03-30 14:54:57 +07:00
parent 66aed7c4e8
commit b5e3a778ce
21316 changed files with 2777892 additions and 13 deletions

2
.gitignore vendored
View File

@@ -1,7 +1,7 @@
/node_modules /node_modules
/public/build /public/build
/public/hot /public/hot
/vendor #/vendor
.env .env
.env.backup .env.backup
.phpunit.result.cache .phpunit.result.cache

View File

@@ -16,14 +16,14 @@ RUN apk add --no-cache \
npm \ npm \
&& docker-php-ext-configure gd --with-freetype --with-jpeg \ && docker-php-ext-configure gd --with-freetype --with-jpeg \
&& docker-php-ext-install -j$(nproc) \ && docker-php-ext-install -j$(nproc) \
pdo_pgsql \ pdo_pgsql \
pgsql \ pgsql \
opcache \ opcache \
zip \ zip \
bcmath \ bcmath \
gd \ gd \
exif \ exif \
pcntl pcntl
# Configure git to allow safe directory # Configure git to allow safe directory
RUN git config --global --add safe.directory /var/www/html RUN git config --global --add safe.directory /var/www/html
@@ -50,17 +50,17 @@ RUN mkdir -p storage/framework/cache \
RUN composer install --no-interaction --no-progress --no-scripts RUN composer install --no-interaction --no-progress --no-scripts
# Isolate the clean vendor directory # Isolate the clean vendor directory
RUN mv vendor /vendor_clean #RUN mv vendor /vendor_clean
# Copy the rest of the application files (will ignore vendor because of .dockerignore) # Copy the rest of the application files (will ignore vendor because of .dockerignore)
COPY --chown=www-data:www-data . . COPY --chown=www-data:www-data . .
# Restore the clean vendor directory and set proper permissions # Restore the clean vendor directory and set proper permissions
RUN rm -rf vendor && mv /vendor_clean vendor && chown -R www-data:www-data vendor #RUN rm -rf vendor && mv /vendor_clean vendor && chown -R www-data:www-data vendor
# Final build verification # Final build verification
RUN if [ ! -f vendor/laravel/prompts/src/helpers.php ]; then \ RUN if [ ! -f vendor/laravel/prompts/src/helpers.php ]; then \
echo "ERROR: laravel/prompts/src/helpers.php missing!" && exit 1; \ echo "ERROR: laravel/prompts/src/helpers.php missing!" && exit 1; \
fi fi
# Final check and debug listing # Final check and debug listing

2
package-lock.json generated
View File

@@ -1,5 +1,5 @@
{ {
"name": "kulakpos_web", "name": "public_html",
"lockfileVersion": 3, "lockfileVersion": 3,
"requires": true, "requires": true,
"packages": { "packages": {

View File

@@ -0,0 +1,21 @@
The MIT License (MIT)
Copyright (c) AgeekDev
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 NON-INFRINGEMENT. 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.

View File

@@ -0,0 +1,74 @@
{
"name": "ageekdev/laravel-barcode",
"description": "laravel barcode generator",
"keywords": [
"ageekdev",
"laravel",
"barcode"
],
"homepage": "https://github.com/ageekdev/laravel-barcode",
"license": "MIT",
"authors": [
{
"name": "Tint Naing Win",
"email": "amigo.k8@gmail.com",
"role": "Developer"
}
],
"require": {
"php": "^8.1",
"ext-bcmath": "*",
"illuminate/contracts": "^9.0|^10.0|^11.0|^12.0",
"spatie/color": "^1.5"
},
"require-dev": {
"laravel/pint": "^1.5",
"larastan/larastan": "^2.0|^3.0",
"orchestra/testbench": "^7.31|^8.11|^9.0|^10.0",
"pestphp/pest": "^1.21|^2.0|^3.0",
"pestphp/pest-plugin-laravel": "^1.4|^2.0|^3.0",
"phpstan/extension-installer": "^1.1",
"phpstan/phpstan-deprecation-rules": "^1.0|^2.0",
"phpstan/phpstan-phpunit": "^1.0|^2.0",
"roave/security-advisories": "dev-latest"
},
"autoload": {
"psr-4": {
"AgeekDev\\Barcode\\": "src"
}
},
"autoload-dev": {
"psr-4": {
"AgeekDev\\Barcode\\Tests\\": "tests"
}
},
"suggest": {
"ext-gd": "For JPG and PNG generators, GD or Imagick is required",
"ext-imagick": "For JPG and PNG generators, GD or Imagick is required"
},
"scripts": {
"analyse": "vendor/bin/phpstan analyse",
"test": "vendor/bin/pest",
"test-coverage": "vendor/bin/pest --coverage",
"format": "vendor/bin/pint"
},
"config": {
"sort-packages": true,
"allow-plugins": {
"pestphp/pest-plugin": true,
"phpstan/extension-installer": true
}
},
"extra": {
"laravel": {
"providers": [
"AgeekDev\\Barcode\\BarcodeServiceProvider"
],
"aliases": {
"Barcode": "AgeekDev\\Barcode\\Facades\\Barcode"
}
}
},
"minimum-stability": "dev",
"prefer-stable": true
}

View File

@@ -0,0 +1,47 @@
<?php
return [
/*
|--------------------------------------------------------------------------
| Default Barcode Image Type
|--------------------------------------------------------------------------
|
| This option controls the default barcode generator that will be used
| to generate barcode. Alternative barcode generators may be setup and used as
| needed; however, this generator will be used by default.
|
| Supported: "dynamic_html", "html", "jpg", "png", "svg"
|
*/
'image_type' => env('BARCODE_DRIVER', 'png'),
/*
|----------------------------------------------------------------------------------------------
| Accepted Barcode Types
|----------------------------------------------------------------------------------------------
| Supported: TYPE_CODE_32, TYPE_CODE_39, TYPE_CODE_39_CHECKSUM, TYPE_CODE_39E,
| TYPE_CODE_39E_CHECKSUM, TYPE_CODE_93, TYPE_STANDARD_2_5, TYPE_STANDARD_2_5_CHECKSUM,
| TYPE_INTERLEAVED_2_5, TYPE_INTERLEAVED_2_5_CHECKSUM, TYPE_CODE_128, TYPE_CODE_128_A,
| TYPE_CODE_128_B, TYPE_CODE_128_C, TYPE_EAN_2, TYPE_EAN_5, TYPE_EAN_8, TYPE_EAN_13,
| TYPE_UPC_A, TYPE_UPC_E, TYPE_MSI, TYPE_MSI_CHECKSUM, TYPE_POSTNET, TYPE_PLANET, TYPE_RMS4CC,
| TYPE_KIX, TYPE_IMB, TYPE_CODABAR, TYPE_CODE_11, TYPE_PHARMA_CODE, TYPE_PHARMA_CODE_TWO_TRACKS
|
*/
'type' => \AgeekDev\Barcode\Enums\BarcodeType::CODE_128,
/*
* Foreground color of the barcode
*/
'foreground_color' => '#000000',
/*
* width factor of barcode
*/
'width_factor' => 2,
/*
* Height of image barcode
*/
'height' => 30,
];

View File

@@ -0,0 +1,68 @@
<?php
namespace AgeekDev\Barcode;
use AgeekDev\Barcode\Contracts\ImageType;
use AgeekDev\Barcode\Enums\BarcodeType;
use AgeekDev\Barcode\Enums\Type;
use AgeekDev\Barcode\Types\TypeInterface;
abstract class AbstractGenerator implements ImageType
{
/**
* The foreground color of the barcode.
*/
protected string|array $foregroundColor = '#000000';
protected int $height;
protected int $widthFactor;
protected BarcodeType|Type $type;
public function __construct()
{
$this->foregroundColor = config('barcode.foreground_color');
$this->widthFactor = config('barcode.width_factor');
$this->height = config('barcode.height');
$this->type = config('barcode.type');
}
protected function getBarcodeData(string $code, BarcodeType|Type $type): Barcode
{
return $this->createDataBuilderForType($type)->getBarcodeData($code);
}
protected function createDataBuilderForType(BarcodeType|Type $type): TypeInterface
{
return $type->class();
}
public function type(BarcodeType|Type $type): static
{
$this->type = $type;
return $this;
}
public function foregroundColor(string $foregroundColor): static
{
$this->foregroundColor = $foregroundColor;
return $this;
}
public function height(int $height): static
{
$this->height = $height;
return $this;
}
public function widthFactor(int $widthFactor): static
{
$this->widthFactor = $widthFactor;
return $this;
}
}

View File

@@ -0,0 +1,61 @@
<?php
namespace AgeekDev\Barcode;
class Barcode
{
protected string $barcode;
protected int $width = 0;
protected int $height = 0;
protected array $bars = [];
public function __construct(string $barcode)
{
$this->barcode = $barcode;
}
/**
* Add bar.
*/
public function addBar(BarcodeBar $bar): void
{
$this->bars[] = $bar;
$this->width += $bar->getWidth();
$this->height = max($this->height, $bar->getHeight());
}
/**
* Get the barcode.
*/
public function getBarcode(): string
{
return $this->barcode;
}
/**
* Get the width.
*/
public function getWidth(): int
{
return $this->width;
}
/**
* Get the height.
*/
public function getHeight(): int
{
return $this->height;
}
/**
* Get the bars.
*/
public function getBars(): array
{
return $this->bars;
}
}

View File

@@ -0,0 +1,58 @@
<?php
namespace AgeekDev\Barcode;
class BarcodeBar
{
protected int $width;
protected int $height;
protected int $positionVertical;
protected int $type;
public const TYPE_BAR = 1;
public const TYPE_SPACING = 0;
public function __construct(int $width, int $height, bool $drawBar = true, int $positionVertical = 0)
{
$this->width = $width;
$this->height = $height;
$this->positionVertical = $positionVertical;
$this->type = $drawBar ? self::TYPE_BAR : self::TYPE_SPACING;
}
/**
* Get the width.
*/
public function getWidth(): int
{
return $this->width;
}
/**
* Get the height.
*/
public function getHeight(): int
{
return $this->height;
}
/**
* Get position vertical.
*/
public function getPositionVertical(): int
{
return $this->positionVertical;
}
/**
* Bar or not.
*/
public function isBar(): bool
{
return $this->type === self::TYPE_BAR;
}
}

View File

@@ -0,0 +1,277 @@
<?php
namespace AgeekDev\Barcode;
use AgeekDev\Barcode\Contracts\Factory;
use AgeekDev\Barcode\Contracts\ImageType;
use AgeekDev\Barcode\Drivers\DynamicHTML;
use AgeekDev\Barcode\Drivers\HTML;
use AgeekDev\Barcode\Drivers\JPG;
use AgeekDev\Barcode\Drivers\PNG;
use AgeekDev\Barcode\Drivers\SVG;
use AgeekDev\Barcode\Enums\BarcodeType;
use AgeekDev\Barcode\Enums\Type;
use AgeekDev\Barcode\Exceptions\BarcodeException;
use Closure;
use Illuminate\Contracts\Container\BindingResolutionException;
use Illuminate\Contracts\Container\Container;
use Illuminate\Support\Str;
use InvalidArgumentException;
class BarcodeManager implements Factory
{
/**
* The container instance.
*/
protected Container $container;
/**
* The configuration repository instance.
*
* @var \Illuminate\Contracts\Config\Repository
*/
protected mixed $config;
/**
* The registered custom driver creators.
*/
protected array $customCreators = [];
/**
* The array of created "drivers".
*/
protected array $imageTypes = [];
/**
* Create a new manager instance.
*
* @throws BindingResolutionException
*/
public function __construct(Container $container)
{
$this->container = $container;
$this->config = $container->make('config');
}
/**
* Get a image type instance.
*/
public function imageType(?string $name = null): ImageType
{
$name = $name ?: $this->getDefaultDriver();
// If the given driver has not been created before, we will create the instances
// here and cache it, so we can return it next time very quickly. If there is
// already a driver created by this name, we'll just return that instance.
if (! isset($this->imageTypes[$name])) {
$this->imageTypes[$name] = $this->createDriver($name);
}
return $this->imageTypes[$name];
}
/**
* Create a new driver instance.
*
* @throws InvalidArgumentException
*/
protected function createDriver(string $driver): ImageType
{
// First, we will determine if a custom driver creator exists for the given driver and
// if it does not we will check for a creator method for the driver. Custom creator
// callbacks allow developers to build their own "drivers" easily using Closures.
if (isset($this->customCreators[$driver])) {
return $this->callCustomCreator($driver);
}
$method = 'create'.Str::studly($driver).'Driver';
if (method_exists($this, $method)) {
return $this->$method();
}
throw new InvalidArgumentException("ImageType [$driver] not supported.");
}
/**
* Call a custom driver creator.
*/
protected function callCustomCreator(string $driver): ImageType
{
return $this->customCreators[$driver]($this->container);
}
/**
* Create an HTML instance.
*/
public function createHtmlDriver(): ImageType
{
return new HTML;
}
/**
* Create an DynamicHTML instance.
*/
public function createDynamicHtmlDriver(): ImageType
{
return new DynamicHTML;
}
/**
* Create an JPG instance.
*/
public function createJpgDriver(): ImageType
{
return new JPG;
}
/**
* Create an PNG instance.
*/
public function createPngDriver(): ImageType
{
return new PNG;
}
/**
* Create an SVG instance.
*/
public function createSvgDriver(): ImageType
{
return new SVG;
}
/**
* Generate Barcode.
*/
public function generate(string $text): string
{
return $this->imageType()->generate($text);
}
/**
* Set the barcode type.
*/
public function type(BarcodeType|Type $type): ImageType
{
return $this->imageType()->type($type);
}
/**
* Set the barcode foreground color.
*/
public function foregroundColor(string $foregroundColor): ImageType
{
return $this->imageType()->foregroundColor($foregroundColor);
}
/**
* Set the barcode height.
*/
public function height(int $height): ImageType
{
return $this->imageType()->height($height);
}
/**
* Set the barcode width factor.
*/
public function widthFactor(int $widthFactor): ImageType
{
return $this->imageType()->widthFactor($widthFactor);
}
/**
* Force the use of Imagick image extension
*
* @throws BarcodeException
*/
public function useImagick(): ImageType
{
if (method_exists($this->imageType(), 'useImagick')) {
if (! extension_loaded('imagick')) {
throw new BarcodeException('The imagick is not installed!');
}
return $this->imageType()->useImagick();
}
throw new BarcodeException('This image type does not support useImagick function.');
}
/**
* Force the use of the GD image library
*
* @throws BarcodeException
*/
public function useGd(): ImageType
{
if (method_exists($this->imageType(), 'useGd')) {
if (! function_exists('imagecreate')) {
throw new BarcodeException('The GD is not installed!');
}
return $this->imageType()->useGd();
}
throw new BarcodeException('This image type does not support useGd function.');
}
/**
* Get the default driver name.
*/
public function getDefaultDriver(): string
{
return $this->config->get('barcode.image_type', 'png');
}
/**
* Register a custom driver creator Closure.
*/
public function extend(string $imageType, Closure $callback): self
{
$this->customCreators[$imageType] = $callback;
return $this;
}
/**
* Get the container instance used by the manager.
*/
public function getContainer(): Container
{
return $this->container;
}
/**
* Set the container instance used by the manager.
*/
public function setContainer(Container $container): self
{
$this->container = $container;
return $this;
}
/**
* Unset the given disk instances.
*/
public function forgetImageType(array|string $imageType): self
{
foreach ((array) $imageType as $imageTypeName) {
unset($this->imageTypes[$imageTypeName]);
}
return $this;
}
/**
* Dynamically call the default driver instance.
*
* @return mixed
*/
public function __call(string $method, array $parameters)
{
return $this->imageType()->$method(...$parameters);
}
}

View File

@@ -0,0 +1,27 @@
<?php
namespace AgeekDev\Barcode;
use Illuminate\Support\ServiceProvider;
class BarcodeServiceProvider extends ServiceProvider
{
/**
* Register the service provider.
*/
public function register(): void
{
$this->mergeConfigFrom(__DIR__.'/../config/barcode.php', 'barcode');
$this->app->bind('laravel-barcode', function ($app) {
return new BarcodeManager($app);
});
}
public function boot(): void
{
$this->publishes([
__DIR__.'/../config/barcode.php' => config_path('barcode.php'),
], 'laravel-barcode-config');
}
}

View File

@@ -0,0 +1,11 @@
<?php
namespace AgeekDev\Barcode\Contracts;
interface Factory
{
/**
* Get image type implementation.
*/
public function imageType(?string $name = null): ImageType;
}

View File

@@ -0,0 +1,19 @@
<?php
namespace AgeekDev\Barcode\Contracts;
use AgeekDev\Barcode\Enums\BarcodeType;
use AgeekDev\Barcode\Enums\Type;
interface ImageType
{
public function generate(string $text): string;
public function type(BarcodeType|Type $type): static;
public function foregroundColor(string $foregroundColor): static;
public function height(int $height): static;
public function widthFactor(int $widthFactor): static;
}

View File

@@ -0,0 +1,44 @@
<?php
namespace AgeekDev\Barcode\Drivers;
use AgeekDev\Barcode\AbstractGenerator;
use AgeekDev\Barcode\BarcodeBar;
class DynamicHTML extends AbstractGenerator
{
private const WIDTH_PRECISION = 6;
/**
* Return an HTML representation of barcode.
* This 'dynamic' version uses percentage based widths and heights, resulting in a vector-y qualitative result.
*
* @param string $text code to print
*/
public function generate(string $text): string
{
$barcodeData = $this->getBarcodeData($text, $this->type);
$html = '<div style="font-size:0;position:relative;width:100%;height:100%">'.PHP_EOL;
$positionHorizontal = 0;
/** @var BarcodeBar $bar */
foreach ($barcodeData->getBars() as $bar) {
$barWidth = $bar->getWidth() / $barcodeData->getWidth() * 100;
$barHeight = round(($bar->getHeight() / $barcodeData->getHeight() * 100), 3);
if ($barWidth > 0 && $bar->isBar()) {
$positionVertical = round(($bar->getPositionVertical() / $barcodeData->getHeight() * 100), 3);
// draw a vertical bar
$html .= '<div style="background-color:'.$this->foregroundColor.';width:'.round($barWidth, self::WIDTH_PRECISION).'%;height:'.$barHeight.'%;position:absolute;left:'.round($positionHorizontal, self::WIDTH_PRECISION).'%;top:'.$positionVertical.(($positionVertical > 0) ? '%' : '').'">&nbsp;</div>'.PHP_EOL;
}
$positionHorizontal += $barWidth;
}
$html .= '</div>'.PHP_EOL;
return $html;
}
}

View File

@@ -0,0 +1,39 @@
<?php
namespace AgeekDev\Barcode\Drivers;
use AgeekDev\Barcode\AbstractGenerator;
use AgeekDev\Barcode\BarcodeBar;
class HTML extends AbstractGenerator
{
/**
* Return an HTML representation of barcode.
* This original version uses pixel based widths and heights. Use Dynamic HTML version for better quality representation.
*/
public function generate(string $text): string
{
$barcodeData = $this->getBarcodeData($text, $this->type);
$html = '<div style="font-size:0;position:relative;width:'.($barcodeData->getWidth() * $this->widthFactor).'px;height:'.($this->height).'px;">'.PHP_EOL;
$positionHorizontal = 0;
/** @var BarcodeBar $bar */
foreach ($barcodeData->getBars() as $bar) {
$barWidth = round(($bar->getWidth() * $this->widthFactor), 3);
$barHeight = round(($bar->getHeight() * $this->height / $barcodeData->getHeight()), 3);
if ($barWidth > 0 && $bar->isBar()) {
$positionVertical = round(($bar->getPositionVertical() * $this->height / $barcodeData->getHeight()), 3);
$html .= '<div style="background-color:'.$this->foregroundColor.';width:'.$barWidth.'px;height:'.$barHeight.'px;position:absolute;left:'.$positionHorizontal.'px;top:'.$positionVertical.(($positionVertical > 0) ? 'px' : '').'">&nbsp;</div>'.PHP_EOL;
}
$positionHorizontal += $barWidth;
}
$html .= '</div>'.PHP_EOL;
return $html;
}
}

View File

@@ -0,0 +1,22 @@
<?php
namespace AgeekDev\Barcode\Drivers;
use Imagick;
class JPG extends PNG
{
protected function createImagickImageObject(int $width, int $height): Imagick
{
$image = new Imagick;
$image->newImage($width, $height, 'white', 'JPG');
return $image;
}
protected function generateGdImage($image): void
{
imagejpeg($image);
imagedestroy($image);
}
}

View File

@@ -0,0 +1,141 @@
<?php
namespace AgeekDev\Barcode\Drivers;
use AgeekDev\Barcode\AbstractGenerator;
use AgeekDev\Barcode\BarcodeBar;
use AgeekDev\Barcode\Exceptions\BarcodeException;
use Imagick;
use imagickdraw;
use imagickpixel;
use Spatie\Color\Hex;
class PNG extends AbstractGenerator
{
protected bool $useImagick = true;
/**
* @throws BarcodeException
*/
public function __construct()
{
parent::__construct();
// Auto switch between GD and Imagick based on what is installed
if (extension_loaded('imagick')) {
$this->useImagick = true;
} elseif (function_exists('imagecreate')) {
$this->useImagick = false;
} else {
throw new BarcodeException('Neither gd-lib or imagick are installed!');
}
}
/**
* Force the use of Imagick image extension.
*/
public function useImagick(): self
{
$this->useImagick = true;
return $this;
}
/**
* Force the use of the GD image library.
*/
public function useGd(): self
{
$this->useImagick = false;
return $this;
}
/**
* @param string $text code to print
*
* @throws \ImagickDrawException
* @throws \ImagickException
* @throws \ImagickPixelException
*/
public function generate(string $text): string
{
$barcodeData = $this->getBarcodeData($text, $this->type);
$width = round($barcodeData->getWidth() * $this->widthFactor);
$foregroundColor = $this->getForegroundColor();
if ($this->useImagick) {
$imagickBarsShape = new imagickdraw;
$imagickBarsShape->setFillColor(new imagickpixel('rgb('.implode(',', $foregroundColor).')'));
} else {
$image = $this->createGdImageObject($width, $this->height);
$gdForegroundColor = imagecolorallocate($image, $foregroundColor[0], $foregroundColor[1], $foregroundColor[2]);
}
// print bars
$positionHorizontal = 0;
/** @var BarcodeBar $bar */
foreach ($barcodeData->getBars() as $bar) {
$barWidth = round(($bar->getWidth() * $this->widthFactor), 3);
if ($barWidth > 0 && $bar->isBar()) {
$y = round(($bar->getPositionVertical() * $this->height / $barcodeData->getHeight()), 3);
$barHeight = round(($bar->getHeight() * $this->height / $barcodeData->getHeight()), 3);
// draw a vertical bar
if ($this->useImagick) {
$imagickBarsShape->rectangle($positionHorizontal, $y, ($positionHorizontal + $barWidth - 1), ($y + $barHeight));
} else {
imagefilledrectangle($image, $positionHorizontal, $y, ($positionHorizontal + $barWidth - 1), ($y + $barHeight), $gdForegroundColor);
}
}
$positionHorizontal += $barWidth;
}
if ($this->useImagick) {
$image = $this->createImagickImageObject($width, $this->height);
$image->drawImage($imagickBarsShape);
return $image->getImageBlob();
}
ob_start();
$this->generateGdImage($image);
return ob_get_clean();
}
public function getForegroundColor(): string|array
{
$color = Hex::fromString($this->foregroundColor)->toRgba();
return [$color->red(), $color->blue(), $color->green()];
}
protected function createGdImageObject(int $width, int $height)
{
$image = imagecreate($width, $height);
$colorBackground = imagecolorallocate($image, 255, 255, 255);
imagecolortransparent($image, $colorBackground);
return $image;
}
/**
* @throws \ImagickException
*/
protected function createImagickImageObject(int $width, int $height): Imagick
{
$image = new Imagick;
$image->newImage($width, $height, 'none', 'PNG');
return $image;
}
protected function generateGdImage($image): void
{
imagepng($image);
imagedestroy($image);
}
}

View File

@@ -0,0 +1,50 @@
<?php
namespace AgeekDev\Barcode\Drivers;
use AgeekDev\Barcode\AbstractGenerator;
use AgeekDev\Barcode\BarcodeBar;
class SVG extends AbstractGenerator
{
/**
* Return SVG string representation of barcode.
*
* @param string $text code to print
*/
public function generate(string $text): string
{
$barcodeData = $this->getBarcodeData($text, $this->type);
// replace table for special characters
$repstr = ["\0" => '', '&' => '&amp;', '<' => '&lt;', '>' => '&gt;'];
$width = round(($barcodeData->getWidth() * $this->widthFactor), 3);
$svg = '<?xml version="1.0" standalone="no" ?>'.PHP_EOL;
$svg .= '<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">'.PHP_EOL;
$svg .= '<svg width="'.$width.'" height="'.$this->height.'" viewBox="0 0 '.$width.' '.$this->height.'" version="1.1" xmlns="http://www.w3.org/2000/svg">'.PHP_EOL;
$svg .= "\t".'<desc>'.strtr($barcodeData->getBarcode(), $repstr).'</desc>'.PHP_EOL;
$svg .= "\t".'<g id="bars" fill="'.$this->foregroundColor.'" stroke="none">'.PHP_EOL;
// print bars
$positionHorizontal = 0;
/** @var BarcodeBar $bar */
foreach ($barcodeData->getBars() as $bar) {
$barWidth = round(($bar->getWidth() * $this->widthFactor), 3);
$barHeight = round(($bar->getHeight() * $this->height / $barcodeData->getHeight()), 3);
if ($bar->isBar() && $barWidth > 0) {
$positionVertical = round(($bar->getPositionVertical() * $this->height / $barcodeData->getHeight()), 3);
// draw a vertical bar
$svg .= "\t\t".'<rect x="'.$positionHorizontal.'" y="'.$positionVertical.'" width="'.$barWidth.'" height="'.$barHeight.'" />'.PHP_EOL;
}
$positionHorizontal += $barWidth;
}
$svg .= "\t</g>".PHP_EOL;
$svg .= '</svg>'.PHP_EOL;
return $svg;
}
}

View File

@@ -0,0 +1,168 @@
<?php
namespace AgeekDev\Barcode\Enums;
use AgeekDev\Barcode\Types\TypeCodabar;
use AgeekDev\Barcode\Types\TypeCode11;
use AgeekDev\Barcode\Types\TypeCode128;
use AgeekDev\Barcode\Types\TypeCode128A;
use AgeekDev\Barcode\Types\TypeCode128B;
use AgeekDev\Barcode\Types\TypeCode128C;
use AgeekDev\Barcode\Types\TypeCode32;
use AgeekDev\Barcode\Types\TypeCode39;
use AgeekDev\Barcode\Types\TypeCode39Checksum;
use AgeekDev\Barcode\Types\TypeCode39Extended;
use AgeekDev\Barcode\Types\TypeCode39ExtendedChecksum;
use AgeekDev\Barcode\Types\TypeCode93;
use AgeekDev\Barcode\Types\TypeEan13;
use AgeekDev\Barcode\Types\TypeEan8;
use AgeekDev\Barcode\Types\TypeIntelligentMailBarcode;
use AgeekDev\Barcode\Types\TypeInterface;
use AgeekDev\Barcode\Types\TypeInterleaved25;
use AgeekDev\Barcode\Types\TypeInterleaved25Checksum;
use AgeekDev\Barcode\Types\TypeKix;
use AgeekDev\Barcode\Types\TypeMsi;
use AgeekDev\Barcode\Types\TypeMsiChecksum;
use AgeekDev\Barcode\Types\TypePharmacode;
use AgeekDev\Barcode\Types\TypePharmacodeTwoCode;
use AgeekDev\Barcode\Types\TypePlanet;
use AgeekDev\Barcode\Types\TypePostnet;
use AgeekDev\Barcode\Types\TypeRms4cc;
use AgeekDev\Barcode\Types\TypeStandard2of5;
use AgeekDev\Barcode\Types\TypeStandard2of5Checksum;
use AgeekDev\Barcode\Types\TypeUpcA;
use AgeekDev\Barcode\Types\TypeUpcE;
use AgeekDev\Barcode\Types\TypeUpcExtension2;
use AgeekDev\Barcode\Types\TypeUpcExtension5;
enum BarcodeType: string
{
case CODE_32 = 'C32';
case CODE_39 = 'C39';
case CODE_39_CHECKSUM = 'C39+';
case CODE_39E = 'C39E'; // CODE 39 EXTENDED
case CODE_39E_CHECKSUM = 'C39E+'; // CODE 39 EXTENDED + CHECKSUM
case CODE_93 = 'C93';
case STANDARD_2_5 = 'S25';
case STANDARD_2_5_CHECKSUM = 'S25+';
case INTERLEAVED_2_5 = 'I25';
case INTERLEAVED_2_5_CHECKSUM = 'I25+';
case CODE_128 = 'C128';
case CODE_128_A = 'C128A';
case CODE_128_B = 'C128B';
case CODE_128_C = 'C128C';
case EAN_2 = 'EAN2'; // 2-Digits UPC-Based Extention
case EAN_5 = 'EAN5'; // 5-Digits UPC-Based Extention
case EAN_8 = 'EAN8';
case EAN_13 = 'EAN13';
case UPC_A = 'UPCA';
case UPC_E = 'UPCE';
case MSI = 'MSI'; // MSI (Variation of Plessey code)
case MSI_CHECKSUM = 'MSI+'; // MSI + CHECKSUM (modulo 11)
case POSTNET = 'POSTNET';
case PLANET = 'PLANET';
case RMS4CC = 'RMS4CC'; // RMS4CC (Royal Mail 4-state Customer Code) - CBC (Customer Bar Code)
case KIX = 'KIX'; // KIX (Klant index - Customer index)
case IMB = 'IMB'; // IMB - Intelligent Mail Barcode - Onecode - USPS-B-3200
case CODABAR = 'CODABAR';
case CODE_11 = 'CODE11';
case PHARMA_CODE = 'PHARMA';
case PHARMA_CODE_TWO_TRACKS = 'PHARMA2T';
public function class(): TypeInterface
{
return match ($this) {
self::CODE_32 => new TypeCode32,
self::CODE_39 => new TypeCode39,
self::CODE_39_CHECKSUM => new TypeCode39Checksum,
self::CODE_39E => new TypeCode39Extended,
self::CODE_39E_CHECKSUM => new TypeCode39ExtendedChecksum,
self::CODE_93 => new TypeCode93,
self::STANDARD_2_5 => new TypeStandard2of5,
self::STANDARD_2_5_CHECKSUM => new TypeStandard2of5Checksum,
self::INTERLEAVED_2_5 => new TypeInterleaved25,
self::INTERLEAVED_2_5_CHECKSUM => new TypeInterleaved25Checksum,
self::CODE_128 => new TypeCode128,
self::CODE_128_A => new TypeCode128A,
self::CODE_128_B => new TypeCode128B,
self::CODE_128_C => new TypeCode128C,
self::EAN_2 => new TypeUpcExtension2,
self::EAN_5 => new TypeUpcExtension5,
self::EAN_8 => new TypeEan8,
self::EAN_13 => new TypeEan13,
self::UPC_A => new TypeUpcA,
self::UPC_E => new TypeUpcE,
self::MSI => new TypeMsi,
self::MSI_CHECKSUM => new TypeMsiChecksum,
self::POSTNET => new TypePostnet,
self::PLANET => new TypePlanet,
self::RMS4CC => new TypeRms4cc,
self::KIX => new TypeKix,
self::IMB => new TypeIntelligentMailBarcode,
self::CODABAR => new TypeCodabar,
self::CODE_11 => new TypeCode11,
self::PHARMA_CODE => new TypePharmacode,
self::PHARMA_CODE_TWO_TRACKS => new TypePharmacodeTwoCode,
};
}
}

View File

@@ -0,0 +1,171 @@
<?php
namespace AgeekDev\Barcode\Enums;
use AgeekDev\Barcode\Types\TypeCodabar;
use AgeekDev\Barcode\Types\TypeCode11;
use AgeekDev\Barcode\Types\TypeCode128;
use AgeekDev\Barcode\Types\TypeCode128A;
use AgeekDev\Barcode\Types\TypeCode128B;
use AgeekDev\Barcode\Types\TypeCode128C;
use AgeekDev\Barcode\Types\TypeCode32;
use AgeekDev\Barcode\Types\TypeCode39;
use AgeekDev\Barcode\Types\TypeCode39Checksum;
use AgeekDev\Barcode\Types\TypeCode39Extended;
use AgeekDev\Barcode\Types\TypeCode39ExtendedChecksum;
use AgeekDev\Barcode\Types\TypeCode93;
use AgeekDev\Barcode\Types\TypeEan13;
use AgeekDev\Barcode\Types\TypeEan8;
use AgeekDev\Barcode\Types\TypeIntelligentMailBarcode;
use AgeekDev\Barcode\Types\TypeInterface;
use AgeekDev\Barcode\Types\TypeInterleaved25;
use AgeekDev\Barcode\Types\TypeInterleaved25Checksum;
use AgeekDev\Barcode\Types\TypeKix;
use AgeekDev\Barcode\Types\TypeMsi;
use AgeekDev\Barcode\Types\TypeMsiChecksum;
use AgeekDev\Barcode\Types\TypePharmacode;
use AgeekDev\Barcode\Types\TypePharmacodeTwoCode;
use AgeekDev\Barcode\Types\TypePlanet;
use AgeekDev\Barcode\Types\TypePostnet;
use AgeekDev\Barcode\Types\TypeRms4cc;
use AgeekDev\Barcode\Types\TypeStandard2of5;
use AgeekDev\Barcode\Types\TypeStandard2of5Checksum;
use AgeekDev\Barcode\Types\TypeUpcA;
use AgeekDev\Barcode\Types\TypeUpcE;
use AgeekDev\Barcode\Types\TypeUpcExtension2;
use AgeekDev\Barcode\Types\TypeUpcExtension5;
/**
* @deprecated see BarcodeType
*/
enum Type: string
{
case TYPE_CODE_32 = 'C32';
case TYPE_CODE_39 = 'C39';
case TYPE_CODE_39_CHECKSUM = 'C39+';
case TYPE_CODE_39E = 'C39E'; // CODE 39 EXTENDED
case TYPE_CODE_39E_CHECKSUM = 'C39E+'; // CODE 39 EXTENDED + CHECKSUM
case TYPE_CODE_93 = 'C93';
case TYPE_STANDARD_2_5 = 'S25';
case TYPE_STANDARD_2_5_CHECKSUM = 'S25+';
case TYPE_INTERLEAVED_2_5 = 'I25';
case TYPE_INTERLEAVED_2_5_CHECKSUM = 'I25+';
case TYPE_CODE_128 = 'C128';
case TYPE_CODE_128_A = 'C128A';
case TYPE_CODE_128_B = 'C128B';
case TYPE_CODE_128_C = 'C128C';
case TYPE_EAN_2 = 'EAN2'; // 2-Digits UPC-Based Extention
case TYPE_EAN_5 = 'EAN5'; // 5-Digits UPC-Based Extention
case TYPE_EAN_8 = 'EAN8';
case TYPE_EAN_13 = 'EAN13';
case TYPE_UPC_A = 'UPCA';
case TYPE_UPC_E = 'UPCE';
case TYPE_MSI = 'MSI'; // MSI (Variation of Plessey code)
case TYPE_MSI_CHECKSUM = 'MSI+'; // MSI + CHECKSUM (modulo 11)
case TYPE_POSTNET = 'POSTNET';
case TYPE_PLANET = 'PLANET';
case TYPE_RMS4CC = 'RMS4CC'; // RMS4CC (Royal Mail 4-state Customer Code) - CBC (Customer Bar Code)
case TYPE_KIX = 'KIX'; // KIX (Klant index - Customer index)
case TYPE_IMB = 'IMB'; // IMB - Intelligent Mail Barcode - Onecode - USPS-B-3200
case TYPE_CODABAR = 'CODABAR';
case TYPE_CODE_11 = 'CODE11';
case TYPE_PHARMA_CODE = 'PHARMA';
case TYPE_PHARMA_CODE_TWO_TRACKS = 'PHARMA2T';
public function class(): TypeInterface
{
return match ($this) {
self::TYPE_CODE_32 => new TypeCode32,
self::TYPE_CODE_39 => new TypeCode39,
self::TYPE_CODE_39_CHECKSUM => new TypeCode39Checksum,
self::TYPE_CODE_39E => new TypeCode39Extended,
self::TYPE_CODE_39E_CHECKSUM => new TypeCode39ExtendedChecksum,
self::TYPE_CODE_93 => new TypeCode93,
self::TYPE_STANDARD_2_5 => new TypeStandard2of5,
self::TYPE_STANDARD_2_5_CHECKSUM => new TypeStandard2of5Checksum,
self::TYPE_INTERLEAVED_2_5 => new TypeInterleaved25,
self::TYPE_INTERLEAVED_2_5_CHECKSUM => new TypeInterleaved25Checksum,
self::TYPE_CODE_128 => new TypeCode128,
self::TYPE_CODE_128_A => new TypeCode128A,
self::TYPE_CODE_128_B => new TypeCode128B,
self::TYPE_CODE_128_C => new TypeCode128C,
self::TYPE_EAN_2 => new TypeUpcExtension2,
self::TYPE_EAN_5 => new TypeUpcExtension5,
self::TYPE_EAN_8 => new TypeEan8,
self::TYPE_EAN_13 => new TypeEan13,
self::TYPE_UPC_A => new TypeUpcA,
self::TYPE_UPC_E => new TypeUpcE,
self::TYPE_MSI => new TypeMsi,
self::TYPE_MSI_CHECKSUM => new TypeMsiChecksum,
self::TYPE_POSTNET => new TypePostnet,
self::TYPE_PLANET => new TypePlanet,
self::TYPE_RMS4CC => new TypeRms4cc,
self::TYPE_KIX => new TypeKix,
self::TYPE_IMB => new TypeIntelligentMailBarcode,
self::TYPE_CODABAR => new TypeCodabar,
self::TYPE_CODE_11 => new TypeCode11,
self::TYPE_PHARMA_CODE => new TypePharmacode,
self::TYPE_PHARMA_CODE_TWO_TRACKS => new TypePharmacodeTwoCode,
};
}
}

View File

@@ -0,0 +1,5 @@
<?php
namespace AgeekDev\Barcode\Exceptions;
class BarcodeException extends \Exception {}

View File

@@ -0,0 +1,5 @@
<?php
namespace AgeekDev\Barcode\Exceptions;
class InvalidCharacterException extends BarcodeException {}

View File

@@ -0,0 +1,5 @@
<?php
namespace AgeekDev\Barcode\Exceptions;
class InvalidCheckDigitException extends BarcodeException {}

View File

@@ -0,0 +1,5 @@
<?php
namespace AgeekDev\Barcode\Exceptions;
class InvalidFormatException extends BarcodeException {}

View File

@@ -0,0 +1,5 @@
<?php
namespace AgeekDev\Barcode\Exceptions;
class InvalidLengthException extends BarcodeException {}

View File

@@ -0,0 +1,5 @@
<?php
namespace AgeekDev\Barcode\Exceptions;
class UnknownTypeException extends BarcodeException {}

View File

@@ -0,0 +1,28 @@
<?php
namespace AgeekDev\Barcode\Facades;
use AgeekDev\Barcode\Contracts\ImageType;
use AgeekDev\Barcode\Enums\BarcodeType;
use AgeekDev\Barcode\Enums\Type;
use Illuminate\Support\Facades\Facade;
/**
* @method static ImageType foregroundColor(string $foregroundColor)
* @method static ImageType height(int $height)
* @method static ImageType widthFactor(int $widthFactor)
* @method static ImageType type(BarcodeType|Type $type)
* @method static ImageType imageType(?string $driver)
* @method static ImageType useImagick()
* @method static ImageType useGd()
* @method static string generate(string $text)
*
* @see \AgeekDev\Barcode\BarcodeManager
*/
class Barcode extends Facade
{
protected static function getFacadeAccessor(): string
{
return 'laravel-barcode';
}
}

View File

@@ -0,0 +1,25 @@
<?php
namespace AgeekDev\Barcode\Helpers;
class BarcodeHelper
{
public static function getChecksum(string $code): int
{
$len = strlen($code);
$sum = 0;
for ($i = 0; $i < $len; $i += 2) {
$sum .= $code[$i];
}
$sum *= 3;
for ($i = 1; $i < $len; $i += 2) {
$sum .= ($code[$i]);
}
$r = $sum % 10;
if ($r > 0) {
$r = (10 - $r);
}
return $r;
}
}

View File

@@ -0,0 +1,40 @@
<?php
namespace AgeekDev\Barcode\Helpers;
use AgeekDev\Barcode\Barcode;
use AgeekDev\Barcode\BarcodeBar;
/**
* Convert binary barcode sequence string to Barcode representation.
*/
class BinarySequenceConverter
{
public static function convert(string $code, string $sequence): Barcode
{
$barcode = new Barcode($code);
return self::generate($sequence, $barcode);
}
public static function generate(string $sequence, Barcode $barcode): Barcode
{
$len = strlen($sequence);
$barWidth = 0;
for ($i = 0; $i < $len; $i++) {
$barWidth++;
if (($i === ($len - 1)) || (($i < ($len - 1)) && ($sequence[$i] !== $sequence[($i + 1)]))) {
if ($sequence[$i] === '1') {
$drawBar = true;
} else {
$drawBar = false;
}
$barcode->addBar(new BarcodeBar($barWidth, 1, $drawBar));
$barWidth = 0;
}
}
return $barcode;
}
}

View File

@@ -0,0 +1,67 @@
<?php
namespace AgeekDev\Barcode\Types;
use AgeekDev\Barcode\Barcode;
use AgeekDev\Barcode\BarcodeBar;
use AgeekDev\Barcode\Exceptions\InvalidCharacterException;
/*
* CODABAR barcodes.
* Older code often used in library systems, sometimes in blood banks
*/
class TypeCodabar implements TypeInterface
{
protected array $conversionTable = [
'0' => '11111221',
'1' => '11112211',
'2' => '11121121',
'3' => '22111111',
'4' => '11211211',
'5' => '21111211',
'6' => '12111121',
'7' => '12112111',
'8' => '12211111',
'9' => '21121111',
'-' => '11122111',
'$' => '11221111',
':' => '21112121',
'/' => '21211121',
'.' => '21212111',
'+' => '11222221',
'A' => '11221211',
'B' => '12121121',
'C' => '11121221',
'D' => '11122211',
];
/**
* @throws InvalidCharacterException
*/
public function getBarcodeData(string $code): Barcode
{
$barcode = new Barcode($code);
$code = 'A'.strtoupper($code).'A';
for ($i = 0, $iMax = strlen($code); $i < $iMax; $i++) {
if (! isset($this->conversionTable[$code[$i]])) {
throw new InvalidCharacterException('Char '.$code[$i].' is unsupported');
}
$seq = $this->conversionTable[$code[$i]];
for ($j = 0; $j < 8; $j++) {
if (($j % 2) === 0) {
$drawBar = true;
} else {
$drawBar = false;
}
$barWidth = $seq[$j];
$barcode->addBar(new BarcodeBar($barWidth, 1, $drawBar));
}
}
return $barcode;
}
}

View File

@@ -0,0 +1,114 @@
<?php
namespace AgeekDev\Barcode\Types;
use AgeekDev\Barcode\Barcode;
use AgeekDev\Barcode\BarcodeBar;
use AgeekDev\Barcode\Exceptions\InvalidCharacterException;
/*
* CODE11 barcodes.
* Used primarily for labeling telecommunications equipment
*/
class TypeCode11 implements TypeInterface
{
protected array $conversionTable = [
'0' => '111121',
'1' => '211121',
'2' => '121121',
'3' => '221111',
'4' => '112121',
'5' => '212111',
'6' => '122111',
'7' => '111221',
'8' => '211211',
'9' => '211111',
'-' => '112111',
'S' => '112211',
];
/**
* @throws InvalidCharacterException
*/
public function getBarcodeData(string $code): Barcode
{
$barcode = new Barcode($code);
$code .= $this->getCheckDigitC($code);
$code .= $this->getCheckDigitK($code);
$code = 'S'.$code.'S';
for ($i = 0, $iMax = strlen($code); $i < $iMax; $i++) {
if (! isset($this->conversionTable[$code[$i]])) {
throw new InvalidCharacterException('Char '.$code[$i].' is unsupported');
}
$seq = $this->conversionTable[$code[$i]];
for ($j = 0, $jMax = strlen($seq); $j < $jMax; $j++) {
if (($j % 2) === 0) {
$drawBar = true;
} else {
$drawBar = false;
}
$barWidth = $seq[$j];
$barcode->addBar(new BarcodeBar($barWidth, 1, $drawBar));
}
}
return $barcode;
}
private function getCheckDigitC(string $code): string
{
$p = 1;
$check = 0;
for ($i = (strlen($code) - 1); $i >= 0; $i--) {
$digit = $code[$i];
if ($digit === '-') {
$dval = 10;
} else {
$dval = (int) $digit;
}
$check += ($dval * $p);
$p++;
if ($p > 10) {
$p = 1;
}
}
$check %= 11;
if ($check === 10) {
$check = '-';
}
return $check;
}
private function getCheckDigitK(string $code): string
{
if (strlen($code) <= 10) {
return '';
}
$p = 1;
$check = 0;
for ($i = (strlen($code) - 1); $i >= 0; $i--) {
$digit = $code[$i];
if ($digit === '-') {
$dval = 10;
} else {
$dval = (int) $digit;
}
$check += ($dval * $p);
$p++;
if ($p > 9) {
$p = 1;
}
}
$check %= 11;
return (string) $check;
}
}

View File

@@ -0,0 +1,415 @@
<?php
namespace AgeekDev\Barcode\Types;
use AgeekDev\Barcode\Barcode;
use AgeekDev\Barcode\BarcodeBar;
use AgeekDev\Barcode\Exceptions\InvalidCharacterException;
use AgeekDev\Barcode\Exceptions\InvalidLengthException;
/*
* C128 barcodes.
* Very capable code, excellent density, high reliability; in very wide use world-wide
*
* @param $code (string) code to represent.
* @param $type (string) barcode type: A, B, C or empty for automatic switch (AUTO mode)
*/
class TypeCode128 implements TypeInterface
{
protected ?string $type = null;
protected array $conversionTable = [
'212222', /* 00 */
'222122', /* 01 */
'222221', /* 02 */
'121223', /* 03 */
'121322', /* 04 */
'131222', /* 05 */
'122213', /* 06 */
'122312', /* 07 */
'132212', /* 08 */
'221213', /* 09 */
'221312', /* 10 */
'231212', /* 11 */
'112232', /* 12 */
'122132', /* 13 */
'122231', /* 14 */
'113222', /* 15 */
'123122', /* 16 */
'123221', /* 17 */
'223211', /* 18 */
'221132', /* 19 */
'221231', /* 20 */
'213212', /* 21 */
'223112', /* 22 */
'312131', /* 23 */
'311222', /* 24 */
'321122', /* 25 */
'321221', /* 26 */
'312212', /* 27 */
'322112', /* 28 */
'322211', /* 29 */
'212123', /* 30 */
'212321', /* 31 */
'232121', /* 32 */
'111323', /* 33 */
'131123', /* 34 */
'131321', /* 35 */
'112313', /* 36 */
'132113', /* 37 */
'132311', /* 38 */
'211313', /* 39 */
'231113', /* 40 */
'231311', /* 41 */
'112133', /* 42 */
'112331', /* 43 */
'132131', /* 44 */
'113123', /* 45 */
'113321', /* 46 */
'133121', /* 47 */
'313121', /* 48 */
'211331', /* 49 */
'231131', /* 50 */
'213113', /* 51 */
'213311', /* 52 */
'213131', /* 53 */
'311123', /* 54 */
'311321', /* 55 */
'331121', /* 56 */
'312113', /* 57 */
'312311', /* 58 */
'332111', /* 59 */
'314111', /* 60 */
'221411', /* 61 */
'431111', /* 62 */
'111224', /* 63 */
'111422', /* 64 */
'121124', /* 65 */
'121421', /* 66 */
'141122', /* 67 */
'141221', /* 68 */
'112214', /* 69 */
'112412', /* 70 */
'122114', /* 71 */
'122411', /* 72 */
'142112', /* 73 */
'142211', /* 74 */
'241211', /* 75 */
'221114', /* 76 */
'413111', /* 77 */
'241112', /* 78 */
'134111', /* 79 */
'111242', /* 80 */
'121142', /* 81 */
'121241', /* 82 */
'114212', /* 83 */
'124112', /* 84 */
'124211', /* 85 */
'411212', /* 86 */
'421112', /* 87 */
'421211', /* 88 */
'212141', /* 89 */
'214121', /* 90 */
'412121', /* 91 */
'111143', /* 92 */
'111341', /* 93 */
'131141', /* 94 */
'114113', /* 95 */
'114311', /* 96 */
'411113', /* 97 */
'411311', /* 98 */
'113141', /* 99 */
'114131', /* 100 */
'311141', /* 101 */
'411131', /* 102 */
'211412', /* 103 START A */
'211214', /* 104 START B */
'211232', /* 105 START C */
'233111', /* STOP */
'200000', /* END */
];
/**
* @throws InvalidCharacterException
* @throws InvalidLengthException
*/
public function getBarcodeData(string $code): Barcode
{
if (trim($code) === '') {
throw new InvalidLengthException('You should provide a barcode string.');
}
// ASCII characters for code A (ASCII 00 - 95)
$keys_a = ' !"#$%&\'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_';
$keys_a .= chr(0).chr(1).chr(2).chr(3).chr(4).chr(5).chr(6).chr(7).chr(8).chr(9);
$keys_a .= chr(10).chr(11).chr(12).chr(13).chr(14).chr(15).chr(16).chr(17).chr(18).chr(19);
$keys_a .= chr(20).chr(21).chr(22).chr(23).chr(24).chr(25).chr(26).chr(27).chr(28).chr(29);
$keys_a .= chr(30).chr(31);
// ASCII characters for code B (ASCII 32 - 127)
$keys_b = ' !"#$%&\'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~'.chr(127);
// special codes
$fnc_a = [241 => 102, 242 => 97, 243 => 96, 244 => 101];
$fnc_b = [241 => 102, 242 => 97, 243 => 96, 244 => 100];
// array of symbols
$code_data = [];
// length of the code
$len = strlen($code);
switch (strtoupper($this->type ?? '')) {
case 'A':
$startid = 103;
for ($i = 0; $i < $len; $i++) {
$char = $code[$i];
$char_id = ord($char);
if (($char_id <= 244) && ($char_id >= 241)) {
$code_data[] = $fnc_a[$char_id];
} elseif ($char_id <= 95) {
$code_data[] = strpos($keys_a, $char);
} else {
throw new InvalidCharacterException('Char '.$char.' is unsupported');
}
}
break;
case 'B':
$startid = 104;
for ($i = 0; $i < $len; $i++) {
$char = $code[$i];
$char_id = ord($char);
if (($char_id >= 241) && ($char_id <= 244)) {
$code_data[] = $fnc_b[$char_id];
} elseif (($char_id >= 32) && ($char_id <= 127)) {
$code_data[] = strpos($keys_b, $char);
} else {
throw new InvalidCharacterException('Char '.$char.' is unsupported');
}
}
break;
case 'C':
$startid = 105;
if (ord($code[0]) === 241) {
$code_data[] = 102;
$code = substr($code, 1);
$len--;
}
if (($len % 2) !== 0) {
throw new InvalidLengthException('Length must be even');
}
for ($i = 0; $i < $len; $i += 2) {
$chrnum = $code[$i].$code[$i + 1];
if (preg_match('/(\d{2})/', $chrnum) > 0) {
$code_data[] = (int) $chrnum;
} else {
throw new InvalidCharacterException;
}
}
break;
default:
// split code into sequences
$sequence = [];
// get numeric sequences (if any)
$numseq = [];
preg_match_all('/(\d{4,})/', $code, $numseq, PREG_OFFSET_CAPTURE);
if (! empty($numseq[1])) {
$end_offset = 0;
foreach ($numseq[1] as $val) {
$offset = $val[1];
// numeric sequence
$slen = strlen($val[0]);
if (($slen % 2) != 0) {
// the length must be even
$offset++;
$val[0] = substr($val[0], 1);
}
if ($offset > $end_offset) {
// non numeric sequence
$sequence = array_merge($sequence, $this->get128ABsequence(substr($code, $end_offset, ($offset - $end_offset))));
}
// numeric sequence fallback
$slen = strlen($val[0]);
if (($slen % 2) != 0) {
// the length must be even
$slen--;
}
$sequence[] = ['C', substr($code, $offset, $slen), $slen];
$end_offset = $offset + $slen;
}
if ($end_offset < $len) {
$sequence = array_merge($sequence, $this->get128ABsequence(substr($code, $end_offset)));
}
} else {
// text code (non C mode)
$sequence = array_merge($sequence, $this->get128ABsequence($code));
}
$startid = 0;
// process the sequence
foreach ($sequence as $key => $seq) {
switch ($seq[0]) {
case 'A':
if ($key === 0) {
$startid = 103;
} elseif ($sequence[($key - 1)][0] !== 'A') {
if (($seq[2] === 1) && ($key > 0) && ($sequence[($key - 1)][0] === 'B') && (! isset($sequence[($key - 1)][3]))) {
// single character shift
$code_data[] = 98;
// mark shift
$sequence[$key][3] = true;
} elseif (! isset($sequence[($key - 1)][3])) {
$code_data[] = 101;
}
}
for ($i = 0; $i < $seq[2]; $i++) {
$char = $seq[1][$i];
$char_id = ord($char);
if (($char_id >= 241) && ($char_id <= 244)) {
$code_data[] = $fnc_a[$char_id];
} else {
$code_data[] = strpos($keys_a, $char);
}
}
break;
case 'B':
if ($key === 0) {
$tmpchr = ord($seq[1][0]);
if (($seq[2] === 1) && ($tmpchr >= 241) && ($tmpchr <= 244) && isset($sequence[($key + 1)]) && ($sequence[($key + 1)][0] !== 'B')) {
switch ($sequence[($key + 1)][0]) {
case 'A':
$startid = 103;
$sequence[$key][0] = 'A';
$code_data[] = $fnc_a[$tmpchr];
break;
case 'C':
$startid = 105;
$sequence[$key][0] = 'C';
$code_data[] = $fnc_a[$tmpchr];
break;
}
break;
}
$startid = 104;
} elseif ($sequence[($key - 1)][0] !== 'B') {
if (($seq[2] === 1) && ($key > 0) && ($sequence[($key - 1)][0] === 'A') && (! isset($sequence[($key - 1)][3]))) {
// single character shift
$code_data[] = 98;
// mark shift
$sequence[$key][3] = true;
} elseif (! isset($sequence[($key - 1)][3])) {
$code_data[] = 100;
}
}
for ($i = 0; $i < $seq[2]; $i++) {
$char = $seq[1][$i];
$char_id = ord($char);
if (($char_id >= 241) && ($char_id <= 244)) {
$code_data[] = $fnc_b[$char_id];
} else {
$code_data[] = strpos($keys_b, $char);
}
}
break;
case 'C':
if ($key === 0) {
$startid = 105;
} elseif ($sequence[($key - 1)][0] !== 'C') {
$code_data[] = 99;
}
for ($i = 0; $i < $seq[2]; $i += 2) {
$chrnum = $seq[1][$i].$seq[1][$i + 1];
$code_data[] = (int) $chrnum;
}
break;
}
}
}
// calculate check character
$sum = $startid;
foreach ($code_data as $key => $val) {
$sum += ($val * ($key + 1));
}
// add check character
$code_data[] = ($sum % 103);
// add stop sequence
$code_data[] = 106;
$code_data[] = 107;
// add start code at the beginning
array_unshift($code_data, $startid);
// build barcode array
$barcode = new Barcode($code);
foreach ($code_data as $val) {
$seq = $this->conversionTable[$val];
for ($j = 0; $j < 6; $j++) {
if (($j % 2) === 0) {
$t = true; // bar
} else {
$t = false; // space
}
$w = $seq[$j];
$barcode->addBar(new BarcodeBar($w, 1, $t));
}
}
return $barcode;
}
/**
* Split text code in A/B sequence for 128 code
*
* @param $code (string) code to split.
*/
protected function get128ABsequence(string $code): array
{
$len = strlen($code);
$sequence = [];
// get A sequences (if any)
$numseq = [];
preg_match_all('/([\x00-\x1f])/', $code, $numseq, PREG_OFFSET_CAPTURE);
if (! empty($numseq[1])) {
$end_offset = 0;
foreach ($numseq[1] as $val) {
$offset = $val[1];
if ($offset > $end_offset) {
// B sequence
$sequence[] = [
'B',
substr($code, $end_offset, ($offset - $end_offset)),
($offset - $end_offset),
];
}
// A sequence
$slen = strlen($val[0]);
$sequence[] = ['A', substr($code, $offset, $slen), $slen];
$end_offset = $offset + $slen;
}
if ($end_offset < $len) {
$sequence[] = ['B', substr($code, $end_offset), ($len - $end_offset)];
}
} else {
// only B sequence
$sequence[] = ['B', $code, $len];
}
return $sequence;
}
}

View File

@@ -0,0 +1,16 @@
<?php
namespace AgeekDev\Barcode\Types;
/*
* C128 barcodes.
* Very capable code, excellent density, high reliability; in very wide use world-wide
*
* @param $code (string) code to represent.
* @param $type (string) barcode type: A, B, C or empty for automatic switch (AUTO mode)
*/
class TypeCode128A extends TypeCode128
{
protected ?string $type = 'A';
}

View File

@@ -0,0 +1,16 @@
<?php
namespace AgeekDev\Barcode\Types;
/*
* C128 barcodes.
* Very capable code, excellent density, high reliability; in very wide use world-wide
*
* @param $code (string) code to represent.
* @param $type (string) barcode type: A, B, C or empty for automatic switch (AUTO mode)
*/
class TypeCode128B extends TypeCode128
{
protected ?string $type = 'B';
}

View File

@@ -0,0 +1,16 @@
<?php
namespace AgeekDev\Barcode\Types;
/*
* C128 barcodes.
* Very capable code, excellent density, high reliability; in very wide use world-wide
*
* @param $code (string) code to represent.
* @param $type (string) barcode type: A, B, C or empty for automatic switch (AUTO mode)
*/
class TypeCode128C extends TypeCode128
{
protected ?string $type = 'C';
}

View File

@@ -0,0 +1,60 @@
<?php
namespace AgeekDev\Barcode\Types;
use AgeekDev\Barcode\Barcode;
/*
* CODE 32 - italian pharmaceutical
* General-purpose code in very wide use world-wide
*/
class TypeCode32 extends TypeCode39
{
protected array $conversionTable32 = [
'0' => '0',
'1' => '1',
'2' => '2',
'3' => '3',
'4' => '4',
'5' => '5',
'6' => '6',
'7' => '7',
'8' => '8',
'9' => '9',
'10' => 'B',
'11' => 'C',
'12' => 'D',
'13' => 'F',
'14' => 'G',
'15' => 'H',
'16' => 'J',
'17' => 'K',
'18' => 'L',
'19' => 'M',
'20' => 'N',
'21' => 'P',
'22' => 'Q',
'23' => 'R',
'24' => 'S',
'25' => 'T',
'26' => 'U',
'27' => 'V',
'28' => 'W',
'29' => 'X',
'30' => 'Y',
'31' => 'Z',
];
public function getBarcodeData(string $code): Barcode
{
$code39 = '';
$codeElab = $code;
for ($e = 5; $e >= 0; $e--) {
$code39 .= $this->conversionTable32[(int) ($codeElab / (32 ** $e))];
$codeElab %= 32 ** $e;
}
return parent::getBarcodeData($code39);
}
}

View File

@@ -0,0 +1,330 @@
<?php
namespace AgeekDev\Barcode\Types;
use AgeekDev\Barcode\Barcode;
use AgeekDev\Barcode\BarcodeBar;
use AgeekDev\Barcode\Exceptions\InvalidCharacterException;
use AgeekDev\Barcode\Exceptions\InvalidLengthException;
/*
* CODE 39 - ANSI MH10.8M-1983 - USD-3 - 3 of 9.
* General-purpose code in very wide use world-wide
*/
class TypeCode39 implements TypeInterface
{
protected bool $extended = false;
protected bool $checksum = false;
protected array $conversionTable = [
'0' => '111331311',
'1' => '311311113',
'2' => '113311113',
'3' => '313311111',
'4' => '111331113',
'5' => '311331111',
'6' => '113331111',
'7' => '111311313',
'8' => '311311311',
'9' => '113311311',
'A' => '311113113',
'B' => '113113113',
'C' => '313113111',
'D' => '111133113',
'E' => '311133111',
'F' => '113133111',
'G' => '111113313',
'H' => '311113311',
'I' => '113113311',
'J' => '111133311',
'K' => '311111133',
'L' => '113111133',
'M' => '313111131',
'N' => '111131133',
'O' => '311131131',
'P' => '113131131',
'Q' => '111111333',
'R' => '311111331',
'S' => '113111331',
'T' => '111131331',
'U' => '331111113',
'V' => '133111113',
'W' => '333111111',
'X' => '131131113',
'Y' => '331131111',
'Z' => '133131111',
'-' => '131111313',
'.' => '331111311',
' ' => '133111311',
'$' => '131313111',
'/' => '131311131',
'+' => '131113131',
'%' => '111313131',
'*' => '131131311',
];
/**
* @throws InvalidCharacterException
* @throws InvalidLengthException
*/
public function getBarcodeData(string $code): Barcode
{
if (trim($code) === '') {
throw new InvalidLengthException('You should provide a barcode string.');
}
if ($this->extended) {
// extended mode
$code = $this->encode_code39_ext($code);
}
if ($this->checksum) {
// checksum
$code .= $this->checksum_code39($code);
}
// add start and stop codes
$code = '*'.$code.'*';
$barcode = new Barcode($code);
for ($i = 0, $iMax = strlen($code); $i < $iMax; $i++) {
$char = $code[$i];
if (! isset($this->conversionTable[$char])) {
throw new InvalidCharacterException('Char '.$char.' is unsupported');
}
for ($j = 0; $j < 9; $j++) {
if (($j % 2) === 0) {
$drawBar = true;
} else {
$drawBar = false;
}
$barWidth = $this->conversionTable[$char][$j];
$barcode->addBar(new BarcodeBar($barWidth, 1, $drawBar));
}
// inter character gap
$barcode->addBar(new BarcodeBar(1, 1, false));
}
return $barcode;
}
/**
* Encode a string to be used for CODE 39 Extended mode.
*
* @param string $code code to represent.
*
* @throws InvalidCharacterException
*/
protected function encode_code39_ext(string $code): string
{
$encode = [
chr(0) => '%U',
chr(1) => '$A',
chr(2) => '$B',
chr(3) => '$C',
chr(4) => '$D',
chr(5) => '$E',
chr(6) => '$F',
chr(7) => '$G',
chr(8) => '$H',
chr(9) => '$I',
chr(10) => '$J',
chr(11) => '$K',
chr(12) => '$L',
chr(13) => '$M',
chr(14) => '$N',
chr(15) => '$O',
chr(16) => '$P',
chr(17) => '$Q',
chr(18) => '$R',
chr(19) => '$S',
chr(20) => '$T',
chr(21) => '$U',
chr(22) => '$V',
chr(23) => '$W',
chr(24) => '$X',
chr(25) => '$Y',
chr(26) => '$Z',
chr(27) => '%A',
chr(28) => '%B',
chr(29) => '%C',
chr(30) => '%D',
chr(31) => '%E',
chr(32) => ' ',
chr(33) => '/A',
chr(34) => '/B',
chr(35) => '/C',
chr(36) => '/D',
chr(37) => '/E',
chr(38) => '/F',
chr(39) => '/G',
chr(40) => '/H',
chr(41) => '/I',
chr(42) => '/J',
chr(43) => '/K',
chr(44) => '/L',
chr(45) => '-',
chr(46) => '.',
chr(47) => '/O',
chr(48) => '0',
chr(49) => '1',
chr(50) => '2',
chr(51) => '3',
chr(52) => '4',
chr(53) => '5',
chr(54) => '6',
chr(55) => '7',
chr(56) => '8',
chr(57) => '9',
chr(58) => '/Z',
chr(59) => '%F',
chr(60) => '%G',
chr(61) => '%H',
chr(62) => '%I',
chr(63) => '%J',
chr(64) => '%V',
chr(65) => 'A',
chr(66) => 'B',
chr(67) => 'C',
chr(68) => 'D',
chr(69) => 'E',
chr(70) => 'F',
chr(71) => 'G',
chr(72) => 'H',
chr(73) => 'I',
chr(74) => 'J',
chr(75) => 'K',
chr(76) => 'L',
chr(77) => 'M',
chr(78) => 'N',
chr(79) => 'O',
chr(80) => 'P',
chr(81) => 'Q',
chr(82) => 'R',
chr(83) => 'S',
chr(84) => 'T',
chr(85) => 'U',
chr(86) => 'V',
chr(87) => 'W',
chr(88) => 'X',
chr(89) => 'Y',
chr(90) => 'Z',
chr(91) => '%K',
chr(92) => '%L',
chr(93) => '%M',
chr(94) => '%N',
chr(95) => '%O',
chr(96) => '%W',
chr(97) => '+A',
chr(98) => '+B',
chr(99) => '+C',
chr(100) => '+D',
chr(101) => '+E',
chr(102) => '+F',
chr(103) => '+G',
chr(104) => '+H',
chr(105) => '+I',
chr(106) => '+J',
chr(107) => '+K',
chr(108) => '+L',
chr(109) => '+M',
chr(110) => '+N',
chr(111) => '+O',
chr(112) => '+P',
chr(113) => '+Q',
chr(114) => '+R',
chr(115) => '+S',
chr(116) => '+T',
chr(117) => '+U',
chr(118) => '+V',
chr(119) => '+W',
chr(120) => '+X',
chr(121) => '+Y',
chr(122) => '+Z',
chr(123) => '%P',
chr(124) => '%Q',
chr(125) => '%R',
chr(126) => '%S',
chr(127) => '%T',
];
$code_ext = '';
for ($i = 0, $iMax = strlen($code); $i < $iMax; $i++) {
if (ord($code[$i]) > 127) {
throw new InvalidCharacterException('Only supports till char 127');
}
$code_ext .= $encode[$code[$i]];
}
return $code_ext;
}
/**
* Calculate CODE 39 checksum (modulo 43).
*
* @param string $code code to represent.
*/
protected function checksum_code39(string $code): string
{
$chars = [
'0',
'1',
'2',
'3',
'4',
'5',
'6',
'7',
'8',
'9',
'A',
'B',
'C',
'D',
'E',
'F',
'G',
'H',
'I',
'J',
'K',
'L',
'M',
'N',
'O',
'P',
'Q',
'R',
'S',
'T',
'U',
'V',
'W',
'X',
'Y',
'Z',
'-',
'.',
' ',
'$',
'/',
'+',
'%',
];
$sum = 0;
for ($i = 0, $iMax = strlen($code); $i < $iMax; $i++) {
$k = array_keys($chars, $code[$i]);
$sum += $k[0];
}
$j = ($sum % 43);
return $chars[$j];
}
}

View File

@@ -0,0 +1,15 @@
<?php
namespace AgeekDev\Barcode\Types;
/*
* CODE 39 - ANSI MH10.8M-1983 - USD-3 - 3 of 9.
* General-purpose code in very wide use world-wide
*/
class TypeCode39Checksum extends TypeCode39
{
protected bool $extended = false;
protected bool $checksum = true;
}

View File

@@ -0,0 +1,15 @@
<?php
namespace AgeekDev\Barcode\Types;
/*
* CODE 39 - ANSI MH10.8M-1983 - USD-3 - 3 of 9.
* General-purpose code in very wide use world-wide
*/
class TypeCode39Extended extends TypeCode39
{
protected bool $extended = true;
protected bool $checksum = false;
}

View File

@@ -0,0 +1,15 @@
<?php
namespace AgeekDev\Barcode\Types;
/*
* CODE 39 - ANSI MH10.8M-1983 - USD-3 - 3 of 9.
* General-purpose code in very wide use world-wide
*/
class TypeCode39ExtendedChecksum extends TypeCode39
{
protected bool $extended = true;
protected bool $checksum = true;
}

View File

@@ -0,0 +1,286 @@
<?php
namespace AgeekDev\Barcode\Types;
use AgeekDev\Barcode\Barcode;
use AgeekDev\Barcode\BarcodeBar;
use AgeekDev\Barcode\Exceptions\InvalidCharacterException;
/*
* CODE 93 - USS-93
* Compact code similar to Code 39
*
* reference: https://en.wikipedia.org/wiki/Code_93#Full_ASCII_Code_93
*/
class TypeCode93 implements TypeInterface
{
protected array $conversionTable = [
48 => '131112', // 0
49 => '111213', // 1
50 => '111312', // 2
51 => '111411', // 3
52 => '121113', // 4
53 => '121212', // 5
54 => '121311', // 6
55 => '111114', // 7
56 => '131211', // 8
57 => '141111', // 9
65 => '211113', // A
66 => '211212', // B
67 => '211311', // C
68 => '221112', // D
69 => '221211', // E
70 => '231111', // F
71 => '112113', // G
72 => '112212', // H
73 => '112311', // I
74 => '122112', // J
75 => '132111', // K
76 => '111123', // L
77 => '111222', // M
78 => '111321', // N
79 => '121122', // O
80 => '131121', // P
81 => '212112', // Q
82 => '212211', // R
83 => '211122', // S
84 => '211221', // T
85 => '221121', // U
86 => '222111', // V
87 => '112122', // W
88 => '112221', // X
89 => '122121', // Y
90 => '123111', // Z
45 => '121131', // -
46 => '311112', // .
32 => '311211', //
36 => '321111', // $
47 => '112131', // /
43 => '113121', // +
37 => '211131', // %
97 => '121221', // ($)
98 => '312111', // (%)
99 => '311121', // (/)
100 => '122211', // (+)
42 => '111141', // start-stop
];
/**
* @throws InvalidCharacterException
*/
public function getBarcodeData(string $code): Barcode
{
$encode = [
chr(0) => 'bU',
chr(1) => 'aA',
chr(2) => 'aB',
chr(3) => 'aC',
chr(4) => 'aD',
chr(5) => 'aE',
chr(6) => 'aF',
chr(7) => 'aG',
chr(8) => 'aH',
chr(9) => 'aI',
chr(10) => 'aJ',
chr(11) => 'aK',
chr(12) => 'aL',
chr(13) => 'aM',
chr(14) => 'aN',
chr(15) => 'aO',
chr(16) => 'aP',
chr(17) => 'aQ',
chr(18) => 'aR',
chr(19) => 'aS',
chr(20) => 'aT',
chr(21) => 'aU',
chr(22) => 'aV',
chr(23) => 'aW',
chr(24) => 'aX',
chr(25) => 'aY',
chr(26) => 'aZ',
chr(27) => 'bA',
chr(28) => 'bB',
chr(29) => 'bC',
chr(30) => 'bD',
chr(31) => 'bE',
chr(32) => ' ',
chr(33) => 'cA',
chr(34) => 'cB',
chr(35) => 'cC',
chr(36) => '$',
chr(37) => '%',
chr(38) => 'cF',
chr(39) => 'cG',
chr(40) => 'cH',
chr(41) => 'cI',
chr(42) => 'cJ',
chr(43) => '+',
chr(44) => 'cL',
chr(45) => '-',
chr(46) => '.',
chr(47) => '/',
chr(48) => '0',
chr(49) => '1',
chr(50) => '2',
chr(51) => '3',
chr(52) => '4',
chr(53) => '5',
chr(54) => '6',
chr(55) => '7',
chr(56) => '8',
chr(57) => '9',
chr(58) => 'cZ',
chr(59) => 'bF',
chr(60) => 'bG',
chr(61) => 'bH',
chr(62) => 'bI',
chr(63) => 'bJ',
chr(64) => 'bV',
chr(65) => 'A',
chr(66) => 'B',
chr(67) => 'C',
chr(68) => 'D',
chr(69) => 'E',
chr(70) => 'F',
chr(71) => 'G',
chr(72) => 'H',
chr(73) => 'I',
chr(74) => 'J',
chr(75) => 'K',
chr(76) => 'L',
chr(77) => 'M',
chr(78) => 'N',
chr(79) => 'O',
chr(80) => 'P',
chr(81) => 'Q',
chr(82) => 'R',
chr(83) => 'S',
chr(84) => 'T',
chr(85) => 'U',
chr(86) => 'V',
chr(87) => 'W',
chr(88) => 'X',
chr(89) => 'Y',
chr(90) => 'Z',
chr(91) => 'bK',
chr(92) => 'bL',
chr(93) => 'bM',
chr(94) => 'bN',
chr(95) => 'bO',
chr(96) => 'bW',
chr(97) => 'dA',
chr(98) => 'dB',
chr(99) => 'dC',
chr(100) => 'dD',
chr(101) => 'dE',
chr(102) => 'dF',
chr(103) => 'dG',
chr(104) => 'dH',
chr(105) => 'dI',
chr(106) => 'dJ',
chr(107) => 'dK',
chr(108) => 'dL',
chr(109) => 'dM',
chr(110) => 'dN',
chr(111) => 'dO',
chr(112) => 'dP',
chr(113) => 'dQ',
chr(114) => 'dR',
chr(115) => 'dS',
chr(116) => 'dT',
chr(117) => 'dU',
chr(118) => 'dV',
chr(119) => 'dW',
chr(120) => 'dX',
chr(121) => 'dY',
chr(122) => 'dZ',
chr(123) => 'bP',
chr(124) => 'bQ',
chr(125) => 'bR',
chr(126) => 'bS',
chr(127) => 'bT',
];
$code_ext = '';
$clen = strlen($code);
for ($i = 0; $i < $clen; $i++) {
if (ord($code[$i]) > 127) {
throw new InvalidCharacterException('Only supports till char 127');
}
$code_ext .= $encode[$code[$i]];
}
// checksum
$code_ext .= $this->checksum_code93($code_ext);
// add start and stop codes
$code = '*'.$code_ext.'*';
$barcode = new Barcode($code);
for ($i = 0, $iMax = strlen($code); $i < $iMax; $i++) {
$char = ord($code[$i]);
if (! isset($this->conversionTable[$char])) {
throw new InvalidCharacterException('Char '.$char.' is unsupported');
}
for ($j = 0; $j < 6; $j++) {
if (($j % 2) === 0) {
$drawBar = true;
} else {
$drawBar = false;
}
$barWidth = $this->conversionTable[$char][$j];
$barcode->addBar(new BarcodeBar($barWidth, 1, $drawBar));
}
}
$barcode->addBar(new BarcodeBar(1, 1, true));
return $barcode;
}
/**
* Calculate CODE 93 checksum (modulo 47).
*
* @param $code (string) code to represent.
*/
protected function checksum_code93(string $code): string
{
$chars = ['0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', '-', '.', ' ', '$', '/', '+', '%', 'a', 'b', 'c', 'd'];
// calculate check digit C
$len = strlen($code);
$p = 1;
$check = 0;
for ($i = ($len - 1); $i >= 0; $i--) {
$k = array_keys($chars, $code[$i]);
$check += ($k[0] * $p);
$p++;
if ($p > 20) {
$p = 1;
}
}
$check %= 47;
$c = $chars[$check];
$code .= $c;
// calculate check digit K
$p = 1;
$check = 0;
for ($i = $len; $i >= 0; $i--) {
$k = array_keys($chars, $code[$i]);
$check += ($k[0] * $p);
$p++;
if ($p > 15) {
$p = 1;
}
}
$check %= 47;
$k = $chars[$check];
return $c.$k;
}
}

View File

@@ -0,0 +1,22 @@
<?php
namespace AgeekDev\Barcode\Types;
/*
* EAN13 and UPC-A barcodes.
* EAN13: European Article Numbering international retail product code
* UPC-A: Universal product code seen on almost all retail products in the USA and Canada
* UPC-E: Short version of UPC symbol
*
* @param $code (string) code to represent.
* @param $len (string) barcode type: 6 = UPC-E, 8 = EAN8, 13 = EAN13, 12 = UPC-A
*/
class TypeEan13 extends TypeEanUpcBase
{
protected int $length = 13;
protected bool $upca = false;
protected bool $upce = false;
}

View File

@@ -0,0 +1,22 @@
<?php
namespace AgeekDev\Barcode\Types;
/*
* EAN13 and UPC-A barcodes.
* EAN13: European Article Numbering international retail product code
* UPC-A: Universal product code seen on almost all retail products in the USA and Canada
* UPC-E: Short version of UPC symbol
*
* @param $code (string) code to represent.
* @param $len (string) barcode type: 6 = UPC-E, 8 = EAN8, 13 = EAN13, 12 = UPC-A
*/
class TypeEan8 extends TypeEanUpcBase
{
protected int $length = 8;
protected bool $upca = false;
protected bool $upce = false;
}

View File

@@ -0,0 +1,224 @@
<?php
namespace AgeekDev\Barcode\Types;
use AgeekDev\Barcode\Barcode;
use AgeekDev\Barcode\Exceptions\InvalidCharacterException;
use AgeekDev\Barcode\Exceptions\InvalidCheckDigitException;
use AgeekDev\Barcode\Exceptions\InvalidLengthException;
use AgeekDev\Barcode\Helpers\BinarySequenceConverter;
/*
* EAN13 and UPC-A barcodes.
* EAN13: European Article Numbering international retail product code
* UPC-A: Universal product code seen on almost all retail products in the USA and Canada
* UPC-E: Short version of UPC symbol
*
* @param $code (string) code to represent.
* @param $len (string) barcode type: 6 = UPC-E, 8 = EAN8, 13 = EAN13, 12 = UPC-A
*/
abstract class TypeEanUpcBase implements TypeInterface
{
protected int $length = 13;
protected bool $upca = false;
protected bool $upce = false;
/**
* @throws InvalidCheckDigitException
* @throws InvalidCharacterException
* @throws InvalidLengthException
*/
public function getBarcodeData(string $code): Barcode
{
if (trim($code) === '') {
throw new InvalidLengthException('You should provide a barcode string.');
}
$length = $this->length;
$dataLength = $length - 1;
// Add zero padding in front
$code = str_pad($code, $dataLength, '0', STR_PAD_LEFT);
$checksumDigit = $this->calculateChecksumDigit($code);
if (strlen($code) === $dataLength) {
$code .= $checksumDigit;
} elseif ($checksumDigit !== (int) $code[$dataLength]) {
// If length of given barcode is same as final length, barcode is including checksum
// Make sure that checksum is the same as we calculated
throw new InvalidCheckDigitException;
}
if ($this->upca || $this->upce) {
$code = '0'.$code;
$length++;
}
if ($this->upce) {
// convert UPC-A to UPC-E
$tmp = substr($code, 4, 3);
if (($tmp === '000') || ($tmp === '100') || ($tmp === '200')) {
// manufacturer code ends in 000, 100, or 200
$upce_code = substr($code, 2, 2).substr($code, 9, 3).$code[4];
} else {
$tmp = substr($code, 5, 2);
if ($tmp === '00') {
// manufacturer code ends in 00
$upce_code = substr($code, 2, 3).substr($code, 10, 2).'3';
} else {
$tmp = $code[6];
if ($tmp === '0') {
// manufacturer code ends in 0
$upce_code = substr($code, 2, 4).$code[11].'4';
} else {
// manufacturer code does not end in zero
$upce_code = substr($code, 2, 5).$code[11];
}
}
}
}
// Convert digits to bars
$codes = [
'A' => [ // left odd parity
'0' => '0001101',
'1' => '0011001',
'2' => '0010011',
'3' => '0111101',
'4' => '0100011',
'5' => '0110001',
'6' => '0101111',
'7' => '0111011',
'8' => '0110111',
'9' => '0001011',
],
'B' => [ // left even parity
'0' => '0100111',
'1' => '0110011',
'2' => '0011011',
'3' => '0100001',
'4' => '0011101',
'5' => '0111001',
'6' => '0000101',
'7' => '0010001',
'8' => '0001001',
'9' => '0010111',
],
'C' => [ // right
'0' => '1110010',
'1' => '1100110',
'2' => '1101100',
'3' => '1000010',
'4' => '1011100',
'5' => '1001110',
'6' => '1010000',
'7' => '1000100',
'8' => '1001000',
'9' => '1110100',
],
];
$parities = [
'0' => ['A', 'A', 'A', 'A', 'A', 'A'],
'1' => ['A', 'A', 'B', 'A', 'B', 'B'],
'2' => ['A', 'A', 'B', 'B', 'A', 'B'],
'3' => ['A', 'A', 'B', 'B', 'B', 'A'],
'4' => ['A', 'B', 'A', 'A', 'B', 'B'],
'5' => ['A', 'B', 'B', 'A', 'A', 'B'],
'6' => ['A', 'B', 'B', 'B', 'A', 'A'],
'7' => ['A', 'B', 'A', 'B', 'A', 'B'],
'8' => ['A', 'B', 'A', 'B', 'B', 'A'],
'9' => ['A', 'B', 'B', 'A', 'B', 'A'],
];
$upce_parities = [
[
'0' => ['B', 'B', 'B', 'A', 'A', 'A'],
'1' => ['B', 'B', 'A', 'B', 'A', 'A'],
'2' => ['B', 'B', 'A', 'A', 'B', 'A'],
'3' => ['B', 'B', 'A', 'A', 'A', 'B'],
'4' => ['B', 'A', 'B', 'B', 'A', 'A'],
'5' => ['B', 'A', 'A', 'B', 'B', 'A'],
'6' => ['B', 'A', 'A', 'A', 'B', 'B'],
'7' => ['B', 'A', 'B', 'A', 'B', 'A'],
'8' => ['B', 'A', 'B', 'A', 'A', 'B'],
'9' => ['B', 'A', 'A', 'B', 'A', 'B'],
],
[
'0' => ['A', 'A', 'A', 'B', 'B', 'B'],
'1' => ['A', 'A', 'B', 'A', 'B', 'B'],
'2' => ['A', 'A', 'B', 'B', 'A', 'B'],
'3' => ['A', 'A', 'B', 'B', 'B', 'A'],
'4' => ['A', 'B', 'A', 'A', 'B', 'B'],
'5' => ['A', 'B', 'B', 'A', 'A', 'B'],
'6' => ['A', 'B', 'B', 'B', 'A', 'A'],
'7' => ['A', 'B', 'A', 'B', 'A', 'B'],
'8' => ['A', 'B', 'A', 'B', 'B', 'A'],
'9' => ['A', 'B', 'B', 'A', 'B', 'A'],
],
];
$seq = '101'; // left guard bar
if ($this->upce) {
$barcode = new Barcode($upce_code);
$p = $upce_parities[$code[1]][$checksumDigit];
for ($i = 0; $i < 6; $i++) {
$seq .= $codes[$p[$i]][$upce_code[$i]];
}
$seq .= '010101'; // right guard bar
} else {
$barcode = new Barcode($code);
$half_len = (int) ceil($length / 2);
if ($length === 8) {
for ($i = 0; $i < $half_len; $i++) {
$seq .= $codes['A'][$code[$i]];
}
} else {
$p = $parities[$code[0]];
for ($i = 1; $i < $half_len; $i++) {
$seq .= $codes[$p[$i - 1]][$code[$i]];
}
}
$seq .= '01010'; // center guard bar
for ($i = $half_len; $i < $length; $i++) {
if (! isset($codes['C'][$code[$i]])) {
throw new InvalidCharacterException('Char '.$code[$i].' not allowed');
}
$seq .= $codes['C'][$code[$i]];
}
$seq .= '101'; // right guard bar
}
return BinarySequenceConverter::generate($seq, $barcode);
}
protected function calculateChecksumDigit(string $code): int
{
// calculate check digit
$sum_a = 0;
for ($i = 1; $i < $this->length - 1; $i += 2) {
$sum_a += (int) $code[$i];
}
if ($this->length > 12) {
$sum_a *= 3;
}
$sum_b = 0;
for ($i = 0; $i < $this->length - 1; $i += 2) {
$sum_b += (int) $code[$i];
}
if ($this->length < 13) {
$sum_b *= 3;
}
$checksumDigit = ($sum_a + $sum_b) % 10;
if ($checksumDigit > 0) {
$checksumDigit = (10 - $checksumDigit);
}
return $checksumDigit;
}
}

View File

@@ -0,0 +1,549 @@
<?php
namespace AgeekDev\Barcode\Types;
use AgeekDev\Barcode\Barcode;
use AgeekDev\Barcode\BarcodeBar;
use AgeekDev\Barcode\Exceptions\BarcodeException;
/*
* IMB - Intelligent Mail Barcode - Onecode - USPS-B-3200
* (requires PHP bcmath extension)
* Intelligent Mail barcode is a 65-bar code for use on mail in the United States.
* The fields are described as follows:<ul><li>The Barcode Identifier shall be assigned by USPS to encode the
* presort identification that is currently printed in human-readable form on the optional endorsement line (OEL)
* as well as for future USPS use. This shall be two digits, with the second digit in the range of 04. The
* allowable encoding ranges shall be 0004, 1014, 2024, 3034, 4044, 5054, 6064, 7074, 8084, and
* 9094.</li><li>The Service Type Identifier shall be assigned by USPS for any combination of services requested
* on the mailpiece. The allowable encoding range shall be 000http://it2.php.net/manual/en/function.dechex.php999.
* Each 3-digit value shall correspond to a particular mail class with a particular combination of service(s). Each
* service program, such as OneCode Confirm and OneCode ACS, shall provide the list of Service Type Identifier
* values.</li><li>The Mailer or Customer Identifier shall be assigned by USPS as a unique, 6 or 9 digits number
* that identifies a business entity. The allowable encoding range for the 6 digit Mailer ID shall be 000000-
* 899999, while the allowable encoding range for the 9 digit Mailer ID shall be 900000000-999999999.</li><li>The
* Serial or Sequence Number shall be assigned by the mailer for uniquely identifying and tracking mailpieces. The
* allowable encoding range shall be 000000000999999999 when used with a 6 digit Mailer ID and 000000-999999 when
* used with a 9 digit Mailer ID. e. The Delivery Point ZIP Code shall be assigned by the mailer for routing the
* mailpiece. This shall replace POSTNET for routing the mailpiece to its final delivery point. The length may be
* 0, 5, 9, or 11 digits. The allowable encoding ranges shall be no ZIP Code, 0000099999, 000000000999999999,
* and 0000000000099999999999.</li></ul>
*
* code to print, separate the ZIP (routing code) from the rest using a minus char '-'
* (BarcodeID_ServiceTypeID_MailerID_SerialNumber-RoutingCode)
*/
class TypeIntelligentMailBarcode implements TypeInterface
{
/**
* @throws BarcodeException
*/
public function getBarcodeData(string $code): Barcode
{
$asc_chr = [
4,
0,
2,
6,
3,
5,
1,
9,
8,
7,
1,
2,
0,
6,
4,
8,
2,
9,
5,
3,
0,
1,
3,
7,
4,
6,
8,
9,
2,
0,
5,
1,
9,
4,
3,
8,
6,
7,
1,
2,
4,
3,
9,
5,
7,
8,
3,
0,
2,
1,
4,
0,
9,
1,
7,
0,
2,
4,
6,
3,
7,
1,
9,
5,
8,
];
$dsc_chr = [
7,
1,
9,
5,
8,
0,
2,
4,
6,
3,
5,
8,
9,
7,
3,
0,
6,
1,
7,
4,
6,
8,
9,
2,
5,
1,
7,
5,
4,
3,
8,
7,
6,
0,
2,
5,
4,
9,
3,
0,
1,
6,
8,
2,
0,
4,
5,
9,
6,
7,
5,
2,
6,
3,
8,
5,
1,
9,
8,
7,
4,
0,
2,
6,
3,
];
$asc_pos = [
3,
0,
8,
11,
1,
12,
8,
11,
10,
6,
4,
12,
2,
7,
9,
6,
7,
9,
2,
8,
4,
0,
12,
7,
10,
9,
0,
7,
10,
5,
7,
9,
6,
8,
2,
12,
1,
4,
2,
0,
1,
5,
4,
6,
12,
1,
0,
9,
4,
7,
5,
10,
2,
6,
9,
11,
2,
12,
6,
7,
5,
11,
0,
3,
2,
];
$dsc_pos = [
2,
10,
12,
5,
9,
1,
5,
4,
3,
9,
11,
5,
10,
1,
6,
3,
4,
1,
10,
0,
2,
11,
8,
6,
1,
12,
3,
8,
6,
4,
4,
11,
0,
6,
1,
9,
11,
5,
3,
7,
3,
10,
7,
11,
8,
2,
10,
3,
5,
8,
0,
3,
12,
11,
8,
4,
5,
1,
3,
0,
7,
12,
9,
8,
10,
];
$code_arr = explode('-', $code);
$tracking_number = $code_arr[0];
$routing_code = $code_arr[1] ?? '';
// Conversion of Routing Code
$binary_code = match (strlen($routing_code)) {
0 => 0,
5 => bcadd($routing_code, '1'),
9 => bcadd($routing_code, '100001'),
11 => bcadd($routing_code, '1000100001'),
default => throw new BarcodeException('Routing code unknown'),
};
$binary_code = bcmul($binary_code, 10);
$binary_code = bcadd($binary_code, $tracking_number[0]);
$binary_code = bcmul($binary_code, 5);
$binary_code = bcadd($binary_code, $tracking_number[1]);
$binary_code .= substr($tracking_number, 2, 18);
// convert to hexadecimal
$binary_code = $this->dec_to_hex($binary_code);
// pad to get 13 bytes
$binary_code = str_pad($binary_code, 26, '0', STR_PAD_LEFT);
// convert string to array of bytes
$binary_code_arr = chunk_split($binary_code, 2, "\r");
$binary_code_arr = substr($binary_code_arr, 0, -1);
$binary_code_arr = explode("\r", $binary_code_arr);
// calculate frame check sequence
$fcs = $this->imb_crc11fcs($binary_code_arr);
// exclude first 2 bits from first byte
$first_byte = sprintf('%2s', dechex((hexdec($binary_code_arr[0]) << 2) >> 2));
$binary_code_102bit = $first_byte.substr($binary_code, 2);
// convert binary data to codewords
$codewords = [];
$data = $this->hex_to_dec($binary_code_102bit);
$codewords[0] = bcmod($data, 636) * 2;
$data = bcdiv($data, 636);
for ($i = 1; $i < 9; $i++) {
$codewords[$i] = bcmod($data, 1365);
$data = bcdiv($data, 1365);
}
$codewords[9] = $data;
if (($fcs >> 10) === 1) {
$codewords[9] += 659;
}
// generate lookup tables
$table2of13 = $this->imb_tables(2, 78);
$table5of13 = $this->imb_tables(5, 1287);
// convert codewords to characters
$characters = [];
$bitmask = 512;
foreach ($codewords as $val) {
if ($val <= 1286) {
$chrcode = $table5of13[$val];
} else {
$chrcode = $table2of13[($val - 1287)];
}
if (($fcs & $bitmask) > 0) {
// bitwise invert
$chrcode = ((~$chrcode) & 8191);
}
$characters[] = $chrcode;
$bitmask /= 2;
}
$characters = array_reverse($characters);
// build bars
$barcode = new Barcode($code);
for ($i = 0; $i < 65; $i++) {
$asc = (($characters[$asc_chr[$i]] & (2 ** $asc_pos[$i])) > 0);
$dsc = (($characters[$dsc_chr[$i]] & (2 ** $dsc_pos[$i])) > 0);
if ($asc && $dsc) {
// full bar (F)
$p = 0;
$h = 3;
} elseif ($asc) {
// ascender (A)
$p = 0;
$h = 2;
} elseif ($dsc) {
// descender (D)
$p = 1;
$h = 2;
} else {
// tracker (T)
$p = 1;
$h = 1;
}
$barcode->addBar(new BarcodeBar(1, $h, true, $p));
if ($i < 64) {
$barcode->addBar(new BarcodeBar(1, 2, false, 0));
}
}
return $barcode;
}
/**
* Convert large integer number to hexadecimal representation.
* (requires PHP bcmath extension)
*
* @param $number (string) number to convert specified as a string
*/
protected function dec_to_hex(string $number): string
{
if ($number === '0') {
return '00';
}
$hex = [];
while ($number > 0) {
$hex[] = strtoupper(dechex(bcmod($number, '16')));
$number = bcdiv($number, '16');
}
$hex = array_reverse($hex);
return implode($hex);
}
/**
* Intelligent Mail Barcode calculation of Frame Check Sequence
*
* @param $code_arr array of hexadecimal values (13 bytes holding 102 bits right justified).
* @return int 11 bit Frame Check Sequence as integer (decimal base)
*/
protected function imb_crc11fcs(array $code_arr): int
{
$genpoly = 0x0F35; // generator polynomial
$fcs = 0x07FF; // Frame Check Sequence
// do most significant byte skipping the 2 most significant bits
$data = hexdec($code_arr[0]) << 5;
for ($bit = 2; $bit < 8; $bit++) {
if (($fcs ^ $data) & 0x400) {
$fcs = ($fcs << 1) ^ $genpoly;
} else {
$fcs <<= 1;
}
$fcs &= 0x7FF;
$data <<= 1;
}
// do rest of bytes
for ($byte = 1; $byte < 13; $byte++) {
$data = hexdec($code_arr[$byte]) << 3;
for ($bit = 0; $bit < 8; $bit++) {
if (($fcs ^ $data) & 0x400) {
$fcs = ($fcs << 1) ^ $genpoly;
} else {
$fcs <<= 1;
}
$fcs &= 0x7FF;
$data <<= 1;
}
}
return $fcs;
}
/**
* Convert large hexadecimal number to decimal representation (string).
* (requires PHP bcmath extension)
*
* @param $hex (string) hexadecimal number to convert specified as a string
* @return int|string hexadecimal representation
*/
protected function hex_to_dec(string $hex): int|string
{
$dec = 0;
$bitval = 1;
$len = strlen($hex);
for ($pos = ($len - 1); $pos >= 0; $pos--) {
$dec = bcadd($dec, bcmul(hexdec($hex[$pos]), $bitval));
$bitval = bcmul($bitval, 16);
}
return $dec;
}
/**
* generate Nof13 tables used for Intelligent Mail Barcode
*
* @param $n (int) is the type of table: 2 for 2of13 table, 5 for 5of13table
* @param $size (int) size of table (78 for n=2 and 1287 for n=5)
*/
protected function imb_tables(int $n, int $size): array
{
$table = [];
$lli = 0; // LUT lower index
$lui = $size - 1; // LUT upper index
for ($count = 0; $count < 8192; $count++) {
$bit_count = 0;
for ($bit_index = 0; $bit_index < 13; $bit_index++) {
$bit_count += (int) (($count & (1 << $bit_index)) !== 0);
}
// if we don't have the right number of bits on, go on to the next value
if ($bit_count === $n) {
$reverse = ($this->imb_reverse_us($count) >> 3);
// if the reverse is less than count, we have already visited this pair before
if ($reverse >= $count) {
// If count is symmetric, place it at the first free slot from the end of the list.
// Otherwise, place it at the first free slot from the beginning of the list && place $reverse ath the next free slot from the beginning of the list
if ($reverse === $count) {
$table[$lui] = $count;
$lui--;
} else {
$table[$lli] = $count;
$lli++;
$table[$lli] = $reverse;
$lli++;
}
}
}
}
return $table;
}
/**
* Reverse unsigned short value
*
* @param $num (int) value to reverse
*/
protected function imb_reverse_us(int $num): int
{
$rev = 0;
for ($i = 0; $i < 16; $i++) {
$rev <<= 1;
$rev |= ($num & 1);
$num >>= 1;
}
return $rev;
}
}

View File

@@ -0,0 +1,10 @@
<?php
namespace AgeekDev\Barcode\Types;
use AgeekDev\Barcode\Barcode;
interface TypeInterface
{
public function getBarcodeData(string $code): Barcode;
}

View File

@@ -0,0 +1,17 @@
<?php
namespace AgeekDev\Barcode\Types;
/*
* Interleaved 2 of 5 barcodes.
* Compact numeric code, widely used in industry, air cargo
* Contains digits (0 to 9) and encodes the data in the width of both bars and spaces.
*/
class TypeInterleaved25 extends TypeInterleaved25Checksum
{
protected function getChecksum(string $code): string
{
return '';
}
}

View File

@@ -0,0 +1,79 @@
<?php
namespace AgeekDev\Barcode\Types;
use AgeekDev\Barcode\Barcode;
use AgeekDev\Barcode\BarcodeBar;
use AgeekDev\Barcode\Exceptions\InvalidCharacterException;
use AgeekDev\Barcode\Helpers\BarcodeHelper;
/*
* Interleaved 2 of 5 barcodes.
* Compact numeric code, widely used in industry, air cargo
* Contains digits (0 to 9) and encodes the data in the width of both bars and spaces.
*/
class TypeInterleaved25Checksum implements TypeInterface
{
/**
* @throws InvalidCharacterException
*/
public function getBarcodeData(string $code): Barcode
{
$chr['0'] = '11221';
$chr['1'] = '21112';
$chr['2'] = '12112';
$chr['3'] = '22111';
$chr['4'] = '11212';
$chr['5'] = '21211';
$chr['6'] = '12211';
$chr['7'] = '11122';
$chr['8'] = '21121';
$chr['9'] = '12121';
$chr['A'] = '11';
$chr['Z'] = '21';
// add checksum
$code .= $this->getChecksum($code);
if ((strlen($code) % 2) != 0) {
// add leading zero if code-length is odd
$code = '0'.$code;
}
// add start and stop codes
$code = 'AA'.strtolower($code).'ZA';
$barcode = new Barcode($code);
for ($i = 0, $iMax = strlen($code); $i < $iMax; $i = ($i + 2)) {
$char_bar = $code[$i];
$char_space = $code[$i + 1];
if (! isset($chr[$char_bar], $chr[$char_space])) {
throw new InvalidCharacterException;
}
// create a bar-space sequence
$seq = '';
$chrlen = strlen($chr[$char_bar]);
for ($s = 0; $s < $chrlen; $s++) {
$seq .= $chr[$char_bar][$s].$chr[$char_space][$s];
}
for ($j = 0, $jMax = strlen($seq); $j < $jMax; $j++) {
if (($j % 2) === 0) {
$t = true; // bar
} else {
$t = false; // space
}
$w = $seq[$j];
$barcode->addBar(new BarcodeBar($w, 1, $t));
}
}
return $barcode;
}
protected function getChecksum(string $code): string
{
return (string) BarcodeHelper::getChecksum($code);
}
}

View File

@@ -0,0 +1,16 @@
<?php
namespace AgeekDev\Barcode\Types;
/*
* RMS4CC - CBC - KIX
* RMS4CC (Royal Mail 4-state Customer Code) - CBC (Customer Bar Code) - KIX (Klant index - Customer index)
* RM4SCC is the name of the barcode symbology used by the Royal Mail for its Cleanmail service.
* @param $kix (boolean) if true prints the KIX variation (doesn't use the start and end symbols, and the checksum)
* - in this case the house number must be sufficed with an X and placed at the end of the code.
*/
class TypeKix extends TypeRms4cc
{
protected bool $kix = true;
}

View File

@@ -0,0 +1,17 @@
<?php
namespace AgeekDev\Barcode\Types;
/*
* MSI.
* Variation of Plessey code, with similar applications
* Contains digits (0 to 9) and encodes the data only in the width of bars.
*
* @param $code (string) code to represent.
* @param $checksum (boolean) if true add a checksum to the code (modulo 11)
*/
class TypeMsi extends TypeMsiChecksum
{
protected bool $checksum = false;
}

View File

@@ -0,0 +1,74 @@
<?php
namespace AgeekDev\Barcode\Types;
use AgeekDev\Barcode\Barcode;
use AgeekDev\Barcode\Exceptions\InvalidCharacterException;
use AgeekDev\Barcode\Helpers\BinarySequenceConverter;
/*
* MSI.
* Variation of Plessey code, with similar applications
* Contains digits (0 to 9) and encodes the data only in the width of bars.
*
* @param $code (string) code to represent.
* @param $checksum (boolean) if true add a checksum to the code (modulo 11)
*/
class TypeMsiChecksum implements TypeInterface
{
protected bool $checksum = true;
/**
* @throws InvalidCharacterException
*/
public function getBarcodeData(string $code): Barcode
{
$chr['0'] = '100100100100';
$chr['1'] = '100100100110';
$chr['2'] = '100100110100';
$chr['3'] = '100100110110';
$chr['4'] = '100110100100';
$chr['5'] = '100110100110';
$chr['6'] = '100110110100';
$chr['7'] = '100110110110';
$chr['8'] = '110100100100';
$chr['9'] = '110100100110';
$chr['A'] = '110100110100';
$chr['B'] = '110100110110';
$chr['C'] = '110110100100';
$chr['D'] = '110110100110';
$chr['E'] = '110110110100';
$chr['F'] = '110110110110';
if ($this->checksum) {
// add checksum
$clen = strlen($code);
$p = 2;
$check = 0;
for ($i = ($clen - 1); $i >= 0; $i--) {
$check += (hexdec($code[$i]) * $p);
$p++;
if ($p > 7) {
$p = 2;
}
}
$check %= 11;
if ($check > 0) {
$check = 11 - $check;
}
$code .= $check;
}
$seq = '110'; // left guard
$clen = strlen($code);
for ($i = 0; $i < $clen; $i++) {
$digit = $code[$i];
if (! isset($chr[$digit])) {
throw new InvalidCharacterException('Char '.$digit.' is unsupported');
}
$seq .= $chr[$digit];
}
$seq .= '1001'; // right guard
return BinarySequenceConverter::convert($code, $seq);
}
}

View File

@@ -0,0 +1,36 @@
<?php
namespace AgeekDev\Barcode\Types;
use AgeekDev\Barcode\Barcode;
use AgeekDev\Barcode\Helpers\BinarySequenceConverter;
/*
* Pharmacode
* Contains digits (0 to 9)
*/
class TypePharmacode implements TypeInterface
{
public function getBarcodeData(string|int $code): Barcode
{
$code = (int) $code;
$seq = '';
while ($code > 0) {
if (($code % 2) === 0) {
$seq .= '11100';
$code -= 2;
} else {
$seq .= '100';
$code--;
}
$code /= 2;
}
$seq = substr($seq, 0, -2);
$seq = strrev($seq);
return BinarySequenceConverter::convert($code, $seq);
}
}

View File

@@ -0,0 +1,78 @@
<?php
namespace AgeekDev\Barcode\Types;
/*
* Pharmacode two-track
* Contains digits (0 to 9)
*/
use AgeekDev\Barcode\Barcode;
use AgeekDev\Barcode\BarcodeBar;
use AgeekDev\Barcode\Exceptions\InvalidLengthException;
class TypePharmacodeTwoCode implements TypeInterface
{
/**
* @throws InvalidLengthException
*/
public function getBarcodeData(string|float $code): Barcode
{
$code = (float) $code;
if ($code < 1) {
throw new InvalidLengthException('Pharmacode 2 needs a number of 1 or larger');
}
$seq = '';
do {
switch ($code % 3) {
case 0:
$seq .= '3';
$code = ($code - 3) / 3.0;
break;
case 1:
$seq .= '1';
$code = ($code - 1) / 3.0;
break;
case 2:
$seq .= '2';
$code = ($code - 2) / 3.0;
break;
}
} while ($code != 0);
$seq = strrev($seq);
$barcode = new Barcode($code);
$p = 0;
$h = 1;
for ($i = 0, $iMax = strlen($seq); $i < $iMax; $i++) {
switch ($seq[$i]) {
case '1':
$p = 1;
break;
case '2':
$p = 0;
break;
case '3':
$h = 2;
break;
}
$barcode->addBar(new BarcodeBar(1, $h, 1, $p));
if ($i < (strlen($seq) - 1)) {
$barcode->addBar(new BarcodeBar(1, 2, 0, 0));
}
}
return $barcode;
}
}

View File

@@ -0,0 +1,28 @@
<?php
namespace AgeekDev\Barcode\Types;
/*
* PLANET barcodes.
* Used by U.S. Postal Service for automated mail sorting
*
* @param $code (string) zip code to represent. Must be a string containing a zip code of the form DDDDD or
* DDDDD-DDDD.
* @param $planet (boolean) if true print the PLANET barcode, otherwise print POSTNET
*/
class TypePlanet extends TypePostnet
{
protected array $barlen = [
0 => [1, 1, 2, 2, 2],
1 => [2, 2, 2, 1, 1],
2 => [2, 2, 1, 2, 1],
3 => [2, 2, 1, 1, 2],
4 => [2, 1, 2, 2, 1],
5 => [2, 1, 2, 1, 2],
6 => [2, 1, 1, 2, 2],
7 => [1, 2, 2, 2, 1],
8 => [1, 2, 2, 1, 2],
9 => [1, 2, 1, 2, 2],
];
}

View File

@@ -0,0 +1,69 @@
<?php
namespace AgeekDev\Barcode\Types;
/*
* POSTNET and PLANET barcodes.
* Used by U.S. Postal Service for automated mail sorting
*
* @param $code (string) zip code to represent. Must be a string containing a zip code of the form DDDDD or
* DDDDD-DDDD.
* @param $planet (boolean) if true print the PLANET barcode, otherwise print POSTNET
*/
use AgeekDev\Barcode\Barcode;
use AgeekDev\Barcode\BarcodeBar;
class TypePostnet implements TypeInterface
{
protected array $barlen = [
0 => [2, 2, 1, 1, 1],
1 => [1, 1, 1, 2, 2],
2 => [1, 1, 2, 1, 2],
3 => [1, 1, 2, 2, 1],
4 => [1, 2, 1, 1, 2],
5 => [1, 2, 1, 2, 1],
6 => [1, 2, 2, 1, 1],
7 => [2, 1, 1, 1, 2],
8 => [2, 1, 1, 2, 1],
9 => [2, 1, 2, 1, 1],
];
public function getBarcodeData(string $code): Barcode
{
$code = str_replace(['-', ' '], '', $code);
$len = strlen($code);
$barcode = new Barcode($code);
// calculate checksum
$sum = 0;
for ($i = 0; $i < $len; $i++) {
$sum += (int) $code[$i];
}
$chkd = ($sum % 10);
if ($chkd > 0) {
$chkd = (10 - $chkd);
}
$code .= $chkd;
$len = strlen($code);
// start bar
$barcode->addBar(new BarcodeBar(1, 2, 1));
$barcode->addBar(new BarcodeBar(1, 2, 0));
for ($i = 0; $i < $len; $i++) {
for ($j = 0; $j < 5; $j++) {
$h = $this->barlen[$code[$i]][$j];
$p = floor(1 / $h);
$barcode->addBar(new BarcodeBar(1, $h, 1, $p));
$barcode->addBar(new BarcodeBar(1, 2, 0));
}
}
// end bar
$barcode->addBar(new BarcodeBar(1, 2, 1));
return $barcode;
}
}

View File

@@ -0,0 +1,165 @@
<?php
namespace AgeekDev\Barcode\Types;
/*
* RMS4CC - CBC - KIX
* RMS4CC (Royal Mail 4-state Customer Code) - CBC (Customer Bar Code) - KIX (Klant index - Customer index)
* RM4SCC is the name of the barcode symbology used by the Royal Mail for its Cleanmail service.
* @param $kix (boolean) if true prints the KIX variation (doesn't use the start and end symbols, and the checksum)
* - in this case the house number must be sufficed with an X and placed at the end of the code.
*/
use AgeekDev\Barcode\Barcode;
use AgeekDev\Barcode\BarcodeBar;
class TypeRms4cc implements TypeInterface
{
protected bool $kix = false;
public function getBarcodeData(string $code): Barcode
{
// bar mode
// 1 = pos 1, length 2
// 2 = pos 1, length 3
// 3 = pos 2, length 1
// 4 = pos 2, length 2
$barmode = [
'0' => [3, 3, 2, 2],
'1' => [3, 4, 1, 2],
'2' => [3, 4, 2, 1],
'3' => [4, 3, 1, 2],
'4' => [4, 3, 2, 1],
'5' => [4, 4, 1, 1],
'6' => [3, 1, 4, 2],
'7' => [3, 2, 3, 2],
'8' => [3, 2, 4, 1],
'9' => [4, 1, 3, 2],
'A' => [4, 1, 4, 1],
'B' => [4, 2, 3, 1],
'C' => [3, 1, 2, 4],
'D' => [3, 2, 1, 4],
'E' => [3, 2, 2, 3],
'F' => [4, 1, 1, 4],
'G' => [4, 1, 2, 3],
'H' => [4, 2, 1, 3],
'I' => [1, 3, 4, 2],
'J' => [1, 4, 3, 2],
'K' => [1, 4, 4, 1],
'L' => [2, 3, 3, 2],
'M' => [2, 3, 4, 1],
'N' => [2, 4, 3, 1],
'O' => [1, 3, 2, 4],
'P' => [1, 4, 1, 4],
'Q' => [1, 4, 2, 3],
'R' => [2, 3, 1, 4],
'S' => [2, 3, 2, 3],
'T' => [2, 4, 1, 3],
'U' => [1, 1, 4, 4],
'V' => [1, 2, 3, 4],
'W' => [1, 2, 4, 3],
'X' => [2, 1, 3, 4],
'Y' => [2, 1, 4, 3],
'Z' => [2, 2, 3, 3],
];
$code = strtoupper($code);
$len = strlen($code);
$barcode = new Barcode($code);
if (! $this->kix) {
// table for checksum calculation (row,col)
$checktable = [
'0' => [1, 1],
'1' => [1, 2],
'2' => [1, 3],
'3' => [1, 4],
'4' => [1, 5],
'5' => [1, 0],
'6' => [2, 1],
'7' => [2, 2],
'8' => [2, 3],
'9' => [2, 4],
'A' => [2, 5],
'B' => [2, 0],
'C' => [3, 1],
'D' => [3, 2],
'E' => [3, 3],
'F' => [3, 4],
'G' => [3, 5],
'H' => [3, 0],
'I' => [4, 1],
'J' => [4, 2],
'K' => [4, 3],
'L' => [4, 4],
'M' => [4, 5],
'N' => [4, 0],
'O' => [5, 1],
'P' => [5, 2],
'Q' => [5, 3],
'R' => [5, 4],
'S' => [5, 5],
'T' => [5, 0],
'U' => [0, 1],
'V' => [0, 2],
'W' => [0, 3],
'X' => [0, 4],
'Y' => [0, 5],
'Z' => [0, 0],
];
$row = 0;
$col = 0;
for ($i = 0; $i < $len; $i++) {
$row += $checktable[$code[$i]][0];
$col += $checktable[$code[$i]][1];
}
$row %= 6;
$col %= 6;
$chk = array_keys($checktable, [$row, $col]);
$code .= $chk[0];
$len++;
// start bar
$barcode->addBar(new BarcodeBar(1, 2, 1));
$barcode->addBar(new BarcodeBar(1, 2, 0));
}
for ($i = 0; $i < $len; $i++) {
for ($j = 0; $j < 4; $j++) {
switch ($barmode[$code[$i]][$j]) {
case 1:
$p = 0;
$h = 2;
break;
case 2:
$p = 0;
$h = 3;
break;
case 3:
$p = 1;
$h = 1;
break;
case 4:
$p = 1;
$h = 2;
break;
}
$barcode->addBar(new BarcodeBar(1, $h, 1, $p));
$barcode->addBar(new BarcodeBar(1, 2, 0));
}
}
if (! $this->kix) {
// stop bar
$barcode->addBar(new BarcodeBar(1, 3, 1));
}
return $barcode;
}
}

View File

@@ -0,0 +1,63 @@
<?php
namespace AgeekDev\Barcode\Types;
use AgeekDev\Barcode\Barcode;
use AgeekDev\Barcode\Exceptions\InvalidCharacterException;
use AgeekDev\Barcode\Helpers\BarcodeHelper;
use AgeekDev\Barcode\Helpers\BinarySequenceConverter;
/*
* Standard 2 of 5 barcodes.
* Used in airline ticket marking, photofinishing
* Contains digits (0 to 9) and encodes the data only in the width of bars.
*/
class TypeStandard2of5 implements TypeInterface
{
protected bool $checksum = false;
/**
* @throws InvalidCharacterException
*/
public function getBarcodeData(string $code): Barcode
{
$chr['0'] = '10101110111010';
$chr['1'] = '11101010101110';
$chr['2'] = '10111010101110';
$chr['3'] = '11101110101010';
$chr['4'] = '10101110101110';
$chr['5'] = '11101011101010';
$chr['6'] = '10111011101010';
$chr['7'] = '10101011101110';
$chr['8'] = '11101010111010';
$chr['9'] = '10111010111010';
if ($this->checksum) {
// add checksum
$code .= $this->checksum_s25($code);
}
$seq = '11011010';
for ($i = 0, $iMax = strlen($code); $i < $iMax; $i++) {
$digit = $code[$i];
if (! isset($chr[$digit])) {
throw new InvalidCharacterException('Char '.$digit.' is unsupported');
}
$seq .= $chr[$digit];
}
$seq .= '1101011';
return BinarySequenceConverter::convert($code, $seq);
}
/**
* Checksum for standard 2 of 5 barcodes.
*
* @param $code (string) code to process.
* @return int checksum.
*/
protected function checksum_s25(string $code): int
{
return BarcodeHelper::getChecksum($code);
}
}

View File

@@ -0,0 +1,14 @@
<?php
namespace AgeekDev\Barcode\Types;
/*
* Standard 2 of 5 barcodes.
* Used in airline ticket marking, photofinishing
* Contains digits (0 to 9) and encodes the data only in the width of bars.
*/
class TypeStandard2of5Checksum extends TypeStandard2of5
{
protected bool $checksum = true;
}

View File

@@ -0,0 +1,22 @@
<?php
namespace AgeekDev\Barcode\Types;
/*
* EAN13 and UPC-A barcodes.
* EAN13: European Article Numbering international retail product code
* UPC-A: Universal product code seen on almost all retail products in the USA and Canada
* UPC-E: Short version of UPC symbol
*
* @param $code (string) code to represent.
* @param $len (string) barcode type: 6 = UPC-E, 8 = EAN8, 13 = EAN13, 12 = UPC-A
*/
class TypeUpcA extends TypeEanUpcBase
{
protected int $length = 12;
protected bool $upca = true;
protected bool $upce = false;
}

View File

@@ -0,0 +1,22 @@
<?php
namespace AgeekDev\Barcode\Types;
/*
* EAN13 and UPC-A barcodes.
* EAN13: European Article Numbering international retail product code
* UPC-A: Universal product code seen on almost all retail products in the USA and Canada
* UPC-E: Short version of UPC symbol
*
* @param $code (string) code to represent.
* @param $len (string) barcode type: 6 = UPC-E, 8 = EAN8, 13 = EAN13, 12 = UPC-A
*/
class TypeUpcE extends TypeEanUpcBase
{
protected int $length = 12;
protected bool $upca = false;
protected bool $upce = true;
}

View File

@@ -0,0 +1,98 @@
<?php
namespace AgeekDev\Barcode\Types;
use AgeekDev\Barcode\Barcode;
use AgeekDev\Barcode\Exceptions\InvalidCheckDigitException;
use AgeekDev\Barcode\Helpers\BinarySequenceConverter;
/*
* UPC-Based Extensions
* 2-Digit Ext.: Used to indicate magazines and newspaper issue numbers
* 5-Digit Ext.: Used to mark suggested retail price of books
*/
class TypeUpcExtension2 implements TypeInterface
{
protected int $length = 2;
/**
* @throws InvalidCheckDigitException
*/
public function getBarcodeData(string $code): Barcode
{
$len = $this->length;
// Padding
$code = str_pad($code, $len, '0', STR_PAD_LEFT);
// calculate check digit
if ($len === 2) {
$r = (int) $code % 4;
} elseif ($len === 5) {
$r = (3 * ((int) $code[0] + (int) $code[2] + (int) $code[4])) + (9 * ((int) $code[1] + (int) $code[3]));
$r %= 10;
} else {
throw new InvalidCheckDigitException;
}
// Convert digits to bars
$codes = [
'A' => [ // left odd parity
'0' => '0001101',
'1' => '0011001',
'2' => '0010011',
'3' => '0111101',
'4' => '0100011',
'5' => '0110001',
'6' => '0101111',
'7' => '0111011',
'8' => '0110111',
'9' => '0001011',
],
'B' => [ // left even parity
'0' => '0100111',
'1' => '0110011',
'2' => '0011011',
'3' => '0100001',
'4' => '0011101',
'5' => '0111001',
'6' => '0000101',
'7' => '0010001',
'8' => '0001001',
'9' => '0010111',
],
];
$parities = [
2 => [
'0' => ['A', 'A'],
'1' => ['A', 'B'],
'2' => ['B', 'A'],
'3' => ['B', 'B'],
],
5 => [
'0' => ['B', 'B', 'A', 'A', 'A'],
'1' => ['B', 'A', 'B', 'A', 'A'],
'2' => ['B', 'A', 'A', 'B', 'A'],
'3' => ['B', 'A', 'A', 'A', 'B'],
'4' => ['A', 'B', 'B', 'A', 'A'],
'5' => ['A', 'A', 'B', 'B', 'A'],
'6' => ['A', 'A', 'A', 'B', 'B'],
'7' => ['A', 'B', 'A', 'B', 'A'],
'8' => ['A', 'B', 'A', 'A', 'B'],
'9' => ['A', 'A', 'B', 'A', 'B'],
],
];
$p = $parities[$len][$r];
$seq = '1011'; // left guard bar
$seq .= $codes[$p[0]][$code[0]];
for ($i = 1; $i < $len; $i++) {
$seq .= '01'; // separator
$seq .= $codes[$p[$i]][$code[$i]];
}
return BinarySequenceConverter::convert($code, $seq);
}
}

View File

@@ -0,0 +1,14 @@
<?php
namespace AgeekDev\Barcode\Types;
/*
* UPC-Based Extensions
* 2-Digit Ext.: Used to indicate magazines and newspaper issue numbers
* 5-Digit Ext.: Used to mark suggested retail price of books
*/
class TypeUpcExtension5 extends TypeUpcExtension2
{
protected int $length = 5;
}

View File

@@ -0,0 +1,21 @@
MIT License
Copyright (c) 2016 Anand Siddharth
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.

View File

@@ -0,0 +1,321 @@
# Laravel Paytm Wallet
[![Latest Stable Version](https://poser.pugx.org/anandsiddharth/laravel-paytm-wallet/v/stable)](https://packagist.org/packages/anandsiddharth/laravel-paytm-wallet)
[![Total Downloads](https://poser.pugx.org/anandsiddharth/laravel-paytm-wallet/downloads)](https://packagist.org/packages/anandsiddharth/laravel-paytm-wallet)
[![License](https://poser.pugx.org/anandsiddharth/laravel-paytm-wallet/license)](https://packagist.org/packages/anandsiddharth/laravel-paytm-wallet)
[![Join the chat at https://gitter.im/laravel-paytm-wallet/Lobby](https://badges.gitter.im/laravel-paytm-wallet/Lobby.svg)](https://gitter.im/laravel-paytm-wallet/Lobby?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
**For Laravel 5.0** use version `^1.0.0` <br />
**For Laravel 6.0** use version `^1.0.0` <br />
**For Laravel 7.0** use version `^1.0.0` <br />
**For Laravel 8.0** use version `^2.0.0` <br />
## Introduction
Integrate paytm wallet in your laravel application easily with this package. This package uses official Paytm PHP SDK's.
## License
Laravel Paytm Wallet open-sourced software licensed under the [MIT license](http://opensource.org/licenses/MIT)
## Getting Started
To get started add the following package to your `composer.json` file using this command.
composer require anandsiddharth/laravel-paytm-wallet
## Configuring
**Note: For Laravel 5.5 and above auto-discovery takes care of below configuration.**
When composer installs Laravel Paytm Wallet library successfully, register the `Anand\LaravelPaytmWallet\PaytmWalletServiceProvider` in your `config/app.php` configuration file.
```php
'providers' => [
// Other service providers...
Anand\LaravelPaytmWallet\PaytmWalletServiceProvider::class,
],
```
Also, add the `PaytmWallet` facade to the `aliases` array in your `app` configuration file:
```php
'aliases' => [
// Other aliases
'PaytmWallet' => Anand\LaravelPaytmWallet\Facades\PaytmWallet::class,
],
```
#### Add the paytm credentials to the `.env` file
```bash
PAYTM_ENVIRONMENT=local
PAYTM_MERCHANT_ID=YOUR_MERCHANT_ID_HERE
PAYTM_MERCHANT_KEY=YOUR_SECRET_KEY_HERE
PAYTM_MERCHANT_WEBSITE=YOUR_MERCHANT_WEBSITE
PAYTM_CHANNEL=YOUR_CHANNEL_HERE
PAYTM_INDUSTRY_TYPE=YOUR_INDUSTRY_TYPE_HERE
```
#### One more step to go....
On your `config/services.php` add the following configuration
```php
'paytm-wallet' => [
'env' => env('PAYTM_ENVIRONMENT'), // values : (local | production)
'merchant_id' => env('PAYTM_MERCHANT_ID'),
'merchant_key' => env('PAYTM_MERCHANT_KEY'),
'merchant_website' => env('PAYTM_MERCHANT_WEBSITE'),
'channel' => env('PAYTM_CHANNEL'),
'industry_type' => env('PAYTM_INDUSTRY_TYPE'),
],
```
Note : All the credentials mentioned are provided by Paytm after signing up as merchant.
#### Laravel 7 Changes
Our package is comptible with Laravel 7 but same_site setting is changed in default Laravel installation, make sure you change `same_site` to `null` in `config/session.php` or callback won't include cookies and you will be logged out when a payment is completed
```php
<?php
use Illuminate\Support\Str;
return [
/...
'same_site' => null,
];
```
## Usage
### Making a transaction
```php
<?php
namespace App\Http\Controllers;
use PaytmWallet;
class OrderController extends Controller
{
/**
* Redirect the user to the Payment Gateway.
*
* @return Response
*/
public function order()
{
$payment = PaytmWallet::with('receive');
$payment->prepare([
'order' => $order->id,
'user' => $user->id,
'mobile_number' => $user->phonenumber,
'email' => $user->email,
'amount' => $order->amount,
'callback_url' => 'http://example.com/payment/status'
]);
return $payment->receive();
}
/**
* Obtain the payment information.
*
* @return Object
*/
public function paymentCallback()
{
$transaction = PaytmWallet::with('receive');
$response = $transaction->response(); // To get raw response as array
//Check out response parameters sent by paytm here -> http://paywithpaytm.com/developer/paytm_api_doc?target=interpreting-response-sent-by-paytm
if($transaction->isSuccessful()){
//Transaction Successful
}else if($transaction->isFailed()){
//Transaction Failed
}else if($transaction->isOpen()){
//Transaction Open/Processing
}
$transaction->getResponseMessage(); //Get Response Message If Available
//get important parameters via public methods
$transaction->getOrderId(); // Get order id
$transaction->getTransactionId(); // Get transaction id
}
}
```
Make sure the `callback_url` you have mentioned while receiving payment is `post` on your `routes.php` file, Example see below:
```php
Route::post('/payment/status', [App\Http\Controllers\PaytmController::class,'paymentCallback'])->name('status');
```
Important: The `callback_url` must not be csrf protected [Check out here to how to do that](https://laracasts.com/discuss/channels/general-discussion/l5-disable-csrf-middleware-on-certain-routes)
### Get transaction status/information using order id
```php
<?php
namespace App\Http\Controllers;
use PaytmWallet;
class OrderController extends Controller
{
/**
* Obtain the transaction status/information.
*
* @return Object
*/
public function statusCheck(){
$status = PaytmWallet::with('status');
$status->prepare(['order' => $order->id]);
$status->check();
$response = $status->response(); // To get raw response as array
//Check out response parameters sent by paytm here -> http://paywithpaytm.com/developer/paytm_api_doc?target=txn-status-api-description
if($status->isSuccessful()){
//Transaction Successful
}else if($status->isFailed()){
//Transaction Failed
}else if($status->isOpen()){
//Transaction Open/Processing
}
$status->getResponseMessage(); //Get Response Message If Available
//get important parameters via public methods
$status->getOrderId(); // Get order id
$status->getTransactionId(); // Get transaction id
}
}
```
### Initiating Refunds
```php
<?php
namespace App\Http\Controllers;
use PaytmWallet;
class OrderController extends Controller
{
/**
* Initiate refund.
*
* @return Object
*/
public function refund(){
$refund = PaytmWallet::with('refund');
$refund->prepare([
'order' => $order->id,
'reference' => "refund-order-4", // provide refund reference for your future reference (should be unique for each order)
'amount' => 300, // refund amount
'transaction' => $order->transaction_id // provide paytm transaction id referring to this order
]);
$refund->initiate();
$response = $refund->response(); // To get raw response as array
if($refund->isSuccessful()){
//Refund Successful
}else if($refund->isFailed()){
//Refund Failed
}else if($refund->isOpen()){
//Refund Open/Processing
}else if($refund->isPending()){
//Refund Pending
}
}
}
```
### Check Refund Status
```php
<?php
namespace App\Http\Controllers;
use PaytmWallet;
class OrderController extends Controller
{
/**
* Initiate refund.
*
* @return Object
*/
public function refund(){
$refundStatus = PaytmWallet::with('refund_status');
$refundStatus->prepare([
'order' => $order->id,
'reference' => "refund-order-4", // provide reference number (the same which you have entered for initiating refund)
]);
$refundStatus->check();
$response = $refundStatus->response(); // To get raw response as array
if($refundStatus->isSuccessful()){
//Refund Successful
}else if($refundStatus->isFailed()){
//Refund Failed
}else if($refundStatus->isOpen()){
//Refund Open/Processing
}else if($refundStatus->isPending()){
//Refund Pending
}
}
}
```
### Customizing transaction being processed page
Considering the modern app user interfaces, default "transaction being processed page" is too dull which comes with this package. If you would like to modify this, you have the option to do so. Here's how:
You just need to change 1 line in you `OrderController`'s code.
```php
<?php
namespace App\Http\Controllers;
use PaytmWallet;
class OrderController extends Controller
{
/**
* Redirect the user to the Payment Gateway.
*
* @return Response
*/
public function order()
{
$payment = PaytmWallet::with('receive');
$payment->prepare([
'order' => $order->id,
'user' => $user->id,
'mobile_number' => $user->phonenumber,
'email' => $user->email,
'amount' => $order->amount,
'callback_url' => 'http://example.com/payment/status'
]);
return $payment->view('your_custom_view')->receive();
}
```
Here `$payment->receive()` is replaced with `$payment->view('your_custom_view')->receive()`. Replace `your_custom_view` with your view name which resides in your `resources/views/your_custom_view.blade.php`.
And in your view file make sure you have added this line of code before `</body>` (i.e. before closing body tag), which redirects to payment gateway.
`@yield('payment_redirect')`
Here's a sample custom view:
```html
<html>
<head>
</head>
<body>
<h1>Custom payment message</h1>
@yield('payment_redirect')
</body>
</html>
```
That's all folks!
## Support on Beerpay
[![Beerpay](https://beerpay.io/anandsiddharth/laravel-paytm-wallet/badge.svg?style=beer-square)](https://beerpay.io/anandsiddharth/laravel-paytm-wallet) [![Beerpay](https://beerpay.io/anandsiddharth/laravel-paytm-wallet/make-wish.svg?style=flat-square)](https://beerpay.io/anandsiddharth/laravel-paytm-wallet?focus=wish)

View File

@@ -0,0 +1,33 @@
{
"name": "anandsiddharth/laravel-paytm-wallet",
"description": "Integrate paytm wallet easily with this package. This package uses official Paytm PHP SDK's",
"license": "MIT",
"keywords": ["paytm wallet", "laravel"],
"authors": [
{
"name": "Anand Siddharth",
"email": "anandsiddharth21@gmail.com"
}
],
"minimum-stability": "dev",
"require": {
"php": ">=7.3.0",
"illuminate/support": ">=8.0",
"illuminate/contracts": ">=8.0"
},
"autoload": {
"psr-4": {
"Anand\\LaravelPaytmWallet\\": "src/"
}
},
"extra": {
"laravel": {
"providers": [
"Anand\\LaravelPaytmWallet\\PaytmWalletServiceProvider"
],
"aliases": {
"PaytmWallet": "Anand\\LaravelPaytmWallet\\Facades\\PaytmWallet"
}
}
}
}

View File

@@ -0,0 +1,154 @@
<?php
function encrypt_e_openssl($input, $ky){
$iv = "@@@@&&&&####$$$$";
$data = openssl_encrypt ( $input , "AES-128-CBC" , $ky, 0, $iv );
return $data;
}
function decrypt_e_openssl($crypt, $ky){
$iv = "@@@@&&&&####$$$$";
$data = openssl_decrypt ( $crypt , "AES-128-CBC" , $ky, 0, $iv );
return $data;
}
function generateSalt_e($length) {
$random = "";
srand((double) microtime() * 1000000);
$data = "AbcDE123IJKLMN67QRSTUVWXYZ";
$data .= "aBCdefghijklmn123opq45rs67tuv89wxyz";
$data .= "0FGH45OP89";
for ($i = 0; $i < $length; $i++) {
$random .= substr($data, (rand() % (strlen($data))), 1);
}
return $random;
}
function checkString_e($value) {
$myvalue = ltrim($value);
$myvalue = rtrim($myvalue);
if (in_array($myvalue, ['null', 'NULL'])) {
$myvalue = '';
}
return $myvalue;
}
function getChecksumFromArray($arrayList, $key, $sort=1) {
if ($sort != 0) {
ksort($arrayList);
}
$str = getArray2Str($arrayList);
$salt = generateSalt_e(4);
$finalString = $str . "|" . $salt;
$hash = hash("sha256", $finalString);
$hashString = $hash . $salt;
$checksum = encrypt_e_openssl($hashString, $key);
return $checksum;
}
function getChecksumFromString($str, $key) {
$salt = generateSalt_e(4);
$finalString = $str . "|" . $salt;
$hash = hash("sha256", $finalString);
$hashString = $hash . $salt;
$checksum = encrypt_e_openssl($hashString, $key);
return $checksum;
}
function verifychecksum_e($arrayList, $key, $checksumvalue) {
$arrayList = removeCheckSumParam($arrayList);
ksort($arrayList);
$str = getArray2Str($arrayList);
$paytm_hash = decrypt_e_openssl($checksumvalue, $key);
$salt = substr($paytm_hash, -4);
$finalString = $str . "|" . $salt;
$website_hash = hash("sha256", $finalString);
$website_hash .= $salt;
$validFlag = "FALSE";
if ($website_hash == $paytm_hash) {
$validFlag = "TRUE";
} else {
$validFlag = "FALSE";
}
return $validFlag;
}
function verifychecksum_eFromStr($str, $key, $checksumvalue) {
$paytm_hash = decrypt_e_openssl($checksumvalue, $key);
$salt = substr($paytm_hash, -4);
$finalString = $str . "|" . $salt;
$website_hash = hash("sha256", $finalString);
$website_hash .= $salt;
$validFlag = "FALSE";
if ($website_hash == $paytm_hash) {
$validFlag = "TRUE";
} else {
$validFlag = "FALSE";
}
return $validFlag;
}
function getArray2Str($arrayList) {
$paramStr = "";
$flag = 1;
foreach ($arrayList as $key => $value) {
if ($flag) {
$paramStr .= checkString_e($value);
$flag = 0;
} else {
$paramStr .= "|" . checkString_e($value);
}
}
return $paramStr;
}
function redirect2PG($paramList, $key) {
$hashString = getchecksumFromArray($paramList);
$checksum = encrypt_e_openssl($hashString, $key);
}
function removeCheckSumParam($arrayList) {
if (isset($arrayList["CHECKSUMHASH"])) {
unset($arrayList["CHECKSUMHASH"]);
}
return $arrayList;
}
function getTxnStatus($requestParamList) {
return callAPI(PAYTM_STATUS_QUERY_URL, $requestParamList);
}
function initiateTxnRefund($requestParamList) {
$CHECKSUM = getChecksumFromArray($requestParamList,PAYTM_MERCHANT_KEY,0);
$requestParamList["CHECKSUM"] = $CHECKSUM;
return callAPI(PAYTM_REFUND_URL, $requestParamList);
}
function callAPI($apiURL, $requestParamList) {
$jsonResponse = "";
$responseParamList = array();
$JsonData =json_encode($requestParamList);
$postData = 'JsonData='.urlencode($JsonData);
$ch = curl_init($apiURL);
curl_setopt($ch, CURLOPT_CUSTOMREQUEST, "POST");
curl_setopt($ch, CURLOPT_POSTFIELDS, $postData);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt ($ch, CURLOPT_SSL_VERIFYHOST, 0);
curl_setopt ($ch, CURLOPT_SSL_VERIFYPEER, 0);
curl_setopt($ch, CURLOPT_HTTPHEADER, array(
'Content-Type: application/json',
'Content-Length: ' . strlen($postData))
);
$jsonResponse = curl_exec($ch);
$responseParamList = json_decode($jsonResponse,true);
return $responseParamList;
}

View File

@@ -0,0 +1,15 @@
<?php
namespace Anand\LaravelPaytmWallet\Contracts;
interface Factory
{
/**
* Get Paytm Wallet Provider
*
* @param string $driver
* @return \Anand\LaravelPaytmWallet\Contracts\Provider
*/
public function driver($do = null);
}

View File

@@ -0,0 +1,14 @@
<?php
namespace Anand\LaravelPaytmWallet\Contracts;
interface Provider
{
/**
* Return raw response.
*
* @return object
*/
public function response();
}

View File

@@ -0,0 +1,34 @@
<?php
namespace Anand\LaravelPaytmWallet\Facades;
use Illuminate\Support\Facades\Facade;
/**
* @see \Laravel\Socialite\SocialiteManager
*/
class PaytmWallet extends Facade
{
/**
* Get the registered name of the component.
*
* @return string
*/
const STATUS_SUCCESSFUL = 'TXN_SUCCESS';
const STATUS_FAILURE = 'TXN_FAILURE';
const STATUS_OPEN = 'OPEN';
const STATUS_PENDING = 'PENDING';
const RESPONSE_SUCCESSFUL="01";
const RESPONSE_CANCELLED = "141";
const RESPONSE_FAILED = "227";
const RESPONSE_PAGE_CLOSED = "810";
const REPSONSE_REFUND_ALREADY_RAISED = "617";
const RESPONSE_CANCELLED_CUSTOMER = "8102";
const RESPONSE_CANCELLED_CUSTOMER_INSUFFICIENT_BALANCE = "8103";
protected static function getFacadeAccessor()
{
return 'Anand\LaravelPaytmWallet\Contracts\Factory';
}
}

View File

@@ -0,0 +1,76 @@
<?php
namespace Anand\LaravelPaytmWallet;
use Illuminate\Support\Manager;
use Illuminate\Http\Request;
class PaytmWalletManager extends Manager implements Contracts\Factory{
protected $config;
public function with($driver){
return $this->driver($driver);
}
protected function createReceiveDriver(){
$this->config = $this->container['config']['services.paytm-wallet'];
return $this->buildProvider(
'Anand\LaravelPaytmWallet\Providers\ReceivePaymentProvider',
$this->config
);
}
protected function createStatusDriver(){
$this->config = $this->container['config']['services.paytm-wallet'];
return $this->buildProvider(
'Anand\LaravelPaytmWallet\Providers\StatusCheckProvider',
$this->config
);
}
protected function createBalanceDriver(){
$this->config = $this->container['config']['services.paytm-wallet'];
return $this->buildProvider(
'Anand\LaravelPaytmWallet\Providers\BalanceCheckProvider',
$this->config
);
}
protected function createAppDriver(){
$this->config = $this->container['config']['services.paytm-wallet'];
return $this->buildProvider(
'Anand\LaravelPaytmWallet\Providers\PaytmAppProvider',
$this->config
);
}
protected function createRefundDriver() {
$this->config = $this->container['config']['services.paytm-wallet'];
return $this->buildProvider(
'Anand\LaravelPaytmWallet\Providers\RefundPaymentProvider',
$this->config
);
}
protected function createRefundStatusDriver(){
$this->config = $this->container['config']['services.paytm-wallet'];
return $this->buildProvider(
'Anand\LaravelPaytmWallet\Providers\RefundStatusCheckProvider',
$this->config
);
}
public function getDefaultDriver(){
throw new \Exception('No driver was specified. - Laravel Paytm Wallet');
}
public function buildProvider($provider, $config){
return new $provider(
$this->container['request'],
$config
);
}
}

View File

@@ -0,0 +1,42 @@
<?php
namespace Anand\LaravelPaytmWallet;
use Illuminate\Support\ServiceProvider;
class PaytmWalletServiceProvider extends ServiceProvider
{
/**
* Indicates if loading of the provider is deferred.
*
* @var bool
*/
protected $defer = false;
/**
* Register bindings in the container.
*
* @return void
*/
public function register()
{
$this->app->singleton('Anand\LaravelPaytmWallet\Contracts\Factory', function ($app) {
// $this->app->singleton('PaytmWallet', function ($app) {
return new PaytmWalletManager($app);
});
}
public function boot(){
$this->loadViewsFrom(__DIR__.'/resources/views', 'paytmwallet');
}
public function provides(){
return ['Anand\LaravelPaytmWallet\Contracts\Factory'];
}
}

View File

@@ -0,0 +1,49 @@
<?php
namespace Anand\LaravelPaytmWallet\Providers;
use Illuminate\Http\Request;
// require __DIR__.'/../../lib/encdec_paytm.php';
class BalanceCheckProvider extends PaytmWalletProvider{
private $parameters = null;
public function prepare($params = array()){
$defaults = [
'token' => NULL,
];
$_p = array_merge($defaults, $params);
foreach ($_p as $key => $value) {
if ($value == NULL) {
throw new \Exception(' \''.$key.'\' parameter not specified in array passed in prepare() method');
return false;
}
}
$this->parameters = $_p;
return $this;
}
public function check(){
if ($this->parameters == null) {
throw new \Exception("prepare() method not called");
}
return $this->beginTransaction();
}
private function beginTransaction(){
$params = [
'MID' => $this->merchant_id,
'TOKEN' => $this->parameters['token']
];
return $this->api_call($this->paytm_balance_check_url, $params);
}
}

View File

@@ -0,0 +1,38 @@
<?php
namespace Anand\LaravelPaytmWallet\Providers;
use Illuminate\Http\Request;
class PaytmAppProvider extends PaytmWalletProvider{
public function generate(Request $request){
$checksum = getChecksumFromArray($request->all(), $this->merchant_key);
return response()->json([ 'CHECKSUMHASH' => $checksum, 'ORDER_ID' => $request->get('ORDER_ID'), 'payt_STATUS' => '1' ]);
}
public function verify(Request $request, $success = null, $error = null){
$paramList = $request->all();
$return_array = $request->all();
$paytmChecksum = $request->get('CHECKSUMHASH');
$isValidChecksum = verifychecksum_e($paramList, $this->merchant_key, $paytmChecksum);
if ($isValidChecksum) {
if ($success != null && is_callable($success)) {
$success();
}
}else{
if ($error != null && is_callable($error)) {
$error();
}
}
$return_array["IS_CHECKSUM_VALID"] = $isValidChecksum ? "Y" : "N";
unset($return_array["CHECKSUMHASH"]);
$encoded_json = htmlentities(json_encode($return_array));
return view('paytmwallet::app_redirect')->with('json', $encoded_json);
}
}

View File

@@ -0,0 +1,65 @@
<?php
namespace Anand\LaravelPaytmWallet\Providers;
use Anand\LaravelPaytmWallet\Contracts\Provider as ProviderContract;
use Illuminate\Http\Request;
require __DIR__.'/../../lib/encdec_paytm.php';
class PaytmWalletProvider implements ProviderContract {
protected $request;
protected $response;
protected $paytm_txn_url;
protected $paytm_txn_status_url;
protected $paytm_refund_url;
protected $paytm_refund_status_url;
protected $paytm_balance_check_url;
protected $merchant_key;
protected $merchant_id;
protected $merchant_website;
protected $industry_type;
protected $channel;
public function __construct(Request $request, $config){
$this->request = $request;
if ($config['env'] == 'production') {
$domain = 'securegw.paytm.in';
}else{
$domain = 'securegw-stage.paytm.in';
}
$this->paytm_txn_url = 'https://'.$domain.'/theia/processTransaction';
$this->paytm_txn_status_url = 'https://'.$domain.'/merchant-status/getTxnStatus';
$this->paytm_refund_url = 'https://'.$domain.'/refund/HANDLER_INTERNAL/REFUND';
$this->paytm_refund_status_url = 'https://'.$domain.'/refund/HANDLER_INTERNAL/getRefundStatus';
$this->paytm_balance_check_url = 'https://'.$domain.'/refund/HANDLER_INTERNAL/getRefundStatus';
$this->merchant_key = $config['merchant_key'];
$this->merchant_id = $config['merchant_id'];
$this->merchant_website = $config['merchant_website'];
$this->industry_type = $config['industry_type'];
$this->channel = $config['channel'];
}
public function response(){
$checksum = $this->request->get('CHECKSUMHASH');
if(verifychecksum_e($this->request->post(), $this->merchant_key, $checksum) == "TRUE"){
return $this->response = $this->request->post();
}
throw new \Exception('Invalid checksum');
}
public function getResponseMessage() {
return $this->response()['RESPMSG'];
}
public function api_call($url, $params){
return callAPI($url, $params);
}
public function api_call_new($url, $params){
return callAPI($url, $params);
}
}

View File

@@ -0,0 +1,76 @@
<?php
namespace Anand\LaravelPaytmWallet\Providers;
use Anand\LaravelPaytmWallet\Facades\PaytmWallet;
use Anand\LaravelPaytmWallet\Traits\HasTransactionStatus;
use Illuminate\Http\Request;
class ReceivePaymentProvider extends PaytmWalletProvider{
use HasTransactionStatus;
private $parameters = null;
private $view = 'paytmwallet::transact';
public function prepare($params = array()){
$defaults = [
'order' => NULL,
'user' => NULL,
'amount' => NULL,
'callback_url' => NULL,
'email' => NULL,
'mobile_number' => NULL,
];
$_p = array_merge($defaults, $params);
foreach ($_p as $key => $value) {
if ($value == NULL) {
throw new \Exception(' \''.$key.'\' parameter not specified in array passed in prepare() method');
return false;
}
}
$this->parameters = $_p;
return $this;
}
public function receive(){
if ($this->parameters == null) {
throw new \Exception("prepare() method not called");
}
return $this->beginTransaction();
}
public function view($view) {
if($view) {
$this->view = $view;
}
return $this;
}
private function beginTransaction(){
$params = [
'REQUEST_TYPE' => 'DEFAULT',
'MID' => $this->merchant_id,
'ORDER_ID' => $this->parameters['order'],
'CUST_ID' => $this->parameters['user'],
'INDUSTRY_TYPE_ID' => $this->industry_type,
'CHANNEL_ID' => $this->channel,
'TXN_AMOUNT' => $this->parameters['amount'],
'WEBSITE' => $this->merchant_website,
'CALLBACK_URL' => $this->parameters['callback_url'],
'MOBILE_NO' => $this->parameters['mobile_number'],
'EMAIL' => $this->parameters['email'],
];
return view('paytmwallet::form')->with('view', $this->view)->with('params', $params)->with('txn_url', $this->paytm_txn_url)->with('checkSum', getChecksumFromArray($params, $this->merchant_key));
}
public function getOrderId(){
return $this->response()['ORDERID'];
}
public function getTransactionId(){
return $this->response()['TXNID'];
}
}

View File

@@ -0,0 +1,70 @@
<?php
namespace Anand\LaravelPaytmWallet\Providers;
use Anand\LaravelPaytmWallet\Facades\PaytmWallet;
use Anand\LaravelPaytmWallet\Traits\HasTransactionStatus;
use Illuminate\Http\Request;
class RefundPaymentProvider extends PaytmWalletProvider{
use HasTransactionStatus;
private $parameters = null;
protected $response;
public function prepare($params = array()){
$defaults = [
'order' => NULL,
'reference' => NULL,
'amount' => NULL,
'transaction' => NULL
];
$_p = array_merge($defaults, $params);
foreach ($_p as $key => $value) {
if ($value == NULL) {
throw new \Exception(' \''.$key.'\' parameter not specified in array passed in prepare() method');
return false;
}
}
$this->parameters = $_p;
return $this;
}
private function beginTransaction(){
$params = array();
$params["MID"] = $this->merchant_id;
$params["ORDERID"] = $this->parameters['order'];
$params["REFID"] = $this->parameters['reference'];
$params["TXNTYPE"] = 'REFUND';
$params["REFUNDAMOUNT"] = $this->parameters['amount'];
$params["TXNID"] = $this->parameters['transaction'];
$chk = getChecksumFromArray($params, $this->merchant_key);
$params['CHECKSUM'] = $chk;
$this->response = $this->api_call_new($this->paytm_refund_url, $params);
return $this;
}
public function initiate(){
if ($this->parameters == null) {
throw new \Exception("prepare() method not called");
}
$this->beginTransaction();
return $this;
}
public function response(){
return $this->response;
}
public function isRefundAlreadyRaised() {
if ($this->isFailed() && $this->response()['RESPCODE'] == PaytmWallet::REPSONSE_REFUND_ALREADY_RAISED) {
return true;
}
return false;
}
}

View File

@@ -0,0 +1,66 @@
<?php
namespace Anand\LaravelPaytmWallet\Providers;
use Anand\LaravelPaytmWallet\Traits\HasTransactionStatus;
use Illuminate\Http\Request;
class RefundStatusCheckProvider extends PaytmWalletProvider{
use HasTransactionStatus;
private $parameters = null;
protected $response;
public function prepare($params = array()){
$defaults = [
'order' => NULL,
'reference' => NULL,
];
$_p = array_merge($defaults, $params);
foreach ($_p as $key => $value) {
if ($value == NULL) {
throw new \Exception(' \''.$key.'\' parameter not specified in array passed in prepare() method');
return false;
}
}
$this->parameters = $_p;
return $this;
}
public function check(){
if ($this->parameters == null) {
throw new \Exception("prepare() method not called");
}
return $this->beginTransaction();
}
private function beginTransaction(){
$params = array(
'MID' => $this->merchant_id,
'ORDERID' => $this->parameters['order'],
'REFID' => $this->parameters['reference']
);
$chk = getChecksumFromArray($params, $this->merchant_key);
$params['CHECKSUM'] = $chk;
$this->response = $this->api_call_new($this->paytm_txn_status_url, $params);
return $this;
}
public function response(){
return $this->response;
}
public function getOrderId(){
return $this->response()['ORDERID'];
}
public function getTransactionId(){
return $this->response()['TXNID'];
}
}

View File

@@ -0,0 +1,63 @@
<?php
namespace Anand\LaravelPaytmWallet\Providers;
use Anand\LaravelPaytmWallet\Traits\HasTransactionStatus;
use Illuminate\Http\Request;
class StatusCheckProvider extends PaytmWalletProvider{
use HasTransactionStatus;
private $parameters = null;
protected $response;
public function prepare($params = array()){
$defaults = [
'order' => NULL,
];
$_p = array_merge($defaults, $params);
foreach ($_p as $key => $value) {
if ($value == NULL) {
throw new \Exception(' \''.$key.'\' parameter not specified in array passed in prepare() method');
return false;
}
}
$this->parameters = $_p;
return $this;
}
public function check(){
if ($this->parameters == null) {
throw new \Exception("prepare() method not called");
}
return $this->beginTransaction();
}
private function beginTransaction(){
$params = array(
'MID' => $this->merchant_id,
'ORDERID' => $this->parameters['order']
);
$chk = getChecksumFromArray($params, $this->merchant_key);
$params['CHECKSUMHASH'] = $chk;
$this->response = $this->api_call_new($this->paytm_txn_status_url, $params);
return $this;
}
public function response(){
return $this->response;
}
public function getOrderId(){
return $this->response()['ORDERID'];
}
public function getTransactionId(){
return $this->response()['TXNID'];
}
}

View File

@@ -0,0 +1,35 @@
<?php
namespace Anand\LaravelPaytmWallet\Traits;
use Anand\LaravelPaytmWallet\Facades\PaytmWallet;
trait HasTransactionStatus {
public function isOpen(){
if ($this->response['STATUS'] == PaytmWallet::STATUS_OPEN){
return true;
}
return false;
}
public function isFailed(){
if ($this->response['STATUS'] == PaytmWallet::STATUS_FAILURE) {
return true;
}
return false;
}
public function isSuccessful(){
if($this->response['STATUS'] == PaytmWallet::STATUS_SUCCESSFUL){
return true;
}
return false;
}
public function isPending(){
if($this->response['STATUS'] == PaytmWallet::STATUS_PENDING){
return true;
}
return false;
}
}

View File

@@ -0,0 +1,18 @@
<html>
<head>
<meta http-equiv="Content-Type" content="text/html;charset=ISO-8859-I">
<title>Paytm</title>
<script type="text/javascript">
function response(){
return document.getElementById('response').value;
}
</script>
</head>
<body>
Redirect back to the app<br>
<form name="frm" method="post">
<input type="hidden" id="response" name="responseField" value='{{$json}}'>
</form>
</body>
</html>

View File

@@ -0,0 +1,16 @@
@extends($view)
@section('payment_redirect')
<form method="post" action="{{$txn_url}}" name="f1" style="visibility: hidden;">
<table border="1">
<tbody>
@foreach ($params as $key => $value)
<input type="hidden" name="{{$key}}" value="{{$value}}" />
@endforeach
<input type="hidden" name="CHECKSUMHASH" value="{{$checkSum}}">
</tbody>
</table>
<script type="text/javascript">
document.f1.submit();
</script>
</form>
@stop

View File

@@ -0,0 +1,12 @@
<html>
<head>
<title>Merchant Check Out Page</title>
</head>
<body>
<br>
<br>
<center><h1>Your transaction is being processed!!!</h1></center>
<center><h2>Please do not refresh this page...</h2></center>
@yield('payment_redirect')
</body>
</html>

22
vendor/autoload.php vendored Normal file
View File

@@ -0,0 +1,22 @@
<?php
// autoload.php @generated by Composer
if (PHP_VERSION_ID < 50600) {
if (!headers_sent()) {
header('HTTP/1.1 500 Internal Server Error');
}
$err = 'Composer 2.3.0 dropped support for autoloading on PHP <5.6 and you are running '.PHP_VERSION.', please upgrade PHP or use Composer 2.2 LTS via "composer self-update --2.2". Aborting.'.PHP_EOL;
if (!ini_get('display_errors')) {
if (PHP_SAPI === 'cli' || PHP_SAPI === 'phpdbg') {
fwrite(STDERR, $err);
} elseif (!headers_sent()) {
echo $err;
}
}
throw new RuntimeException($err);
}
require_once __DIR__ . '/composer/autoload_real.php';
return ComposerAutoloaderInite18b3d3bc6afaf5dd5c2b53c80a29450::getLoader();

1
vendor/autoload1.php vendored Normal file
View File

@@ -0,0 +1 @@
{"date":"2026-02-05T02:39:19.104838Z"}

View File

@@ -0,0 +1,4 @@
## Code of Conduct
This project has adopted the [Amazon Open Source Code of Conduct](https://aws.github.io/code-of-conduct).
For more information see the [Code of Conduct FAQ](https://aws.github.io/code-of-conduct-faq) or contact
opensource-codeofconduct@amazon.com with any additional questions or comments.

175
vendor/aws/aws-crt-php/LICENSE vendored Normal file
View File

@@ -0,0 +1,175 @@
Apache License
Version 2.0, January 2004
http://www.apache.org/licenses/
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
1. Definitions.
"License" shall mean the terms and conditions for use, reproduction,
and distribution as defined by Sections 1 through 9 of this document.
"Licensor" shall mean the copyright owner or entity authorized by
the copyright owner that is granting the License.
"Legal Entity" shall mean the union of the acting entity and all
other entities that control, are controlled by, or are under common
control with that entity. For the purposes of this definition,
"control" means (i) the power, direct or indirect, to cause the
direction or management of such entity, whether by contract or
otherwise, or (ii) ownership of fifty percent (50%) or more of the
outstanding shares, or (iii) beneficial ownership of such entity.
"You" (or "Your") shall mean an individual or Legal Entity
exercising permissions granted by this License.
"Source" form shall mean the preferred form for making modifications,
including but not limited to software source code, documentation
source, and configuration files.
"Object" form shall mean any form resulting from mechanical
transformation or translation of a Source form, including but
not limited to compiled object code, generated documentation,
and conversions to other media types.
"Work" shall mean the work of authorship, whether in Source or
Object form, made available under the License, as indicated by a
copyright notice that is included in or attached to the work
(an example is provided in the Appendix below).
"Derivative Works" shall mean any work, whether in Source or Object
form, that is based on (or derived from) the Work and for which the
editorial revisions, annotations, elaborations, or other modifications
represent, as a whole, an original work of authorship. For the purposes
of this License, Derivative Works shall not include works that remain
separable from, or merely link (or bind by name) to the interfaces of,
the Work and Derivative Works thereof.
"Contribution" shall mean any work of authorship, including
the original version of the Work and any modifications or additions
to that Work or Derivative Works thereof, that is intentionally
submitted to Licensor for inclusion in the Work by the copyright owner
or by an individual or Legal Entity authorized to submit on behalf of
the copyright owner. For the purposes of this definition, "submitted"
means any form of electronic, verbal, or written communication sent
to the Licensor or its representatives, including but not limited to
communication on electronic mailing lists, source code control systems,
and issue tracking systems that are managed by, or on behalf of, the
Licensor for the purpose of discussing and improving the Work, but
excluding communication that is conspicuously marked or otherwise
designated in writing by the copyright owner as "Not a Contribution."
"Contributor" shall mean Licensor and any individual or Legal Entity
on behalf of whom a Contribution has been received by Licensor and
subsequently incorporated within the Work.
2. Grant of Copyright License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
copyright license to reproduce, prepare Derivative Works of,
publicly display, publicly perform, sublicense, and distribute the
Work and such Derivative Works in Source or Object form.
3. Grant of Patent License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
(except as stated in this section) patent license to make, have made,
use, offer to sell, sell, import, and otherwise transfer the Work,
where such license applies only to those patent claims licensable
by such Contributor that are necessarily infringed by their
Contribution(s) alone or by combination of their Contribution(s)
with the Work to which such Contribution(s) was submitted. If You
institute patent litigation against any entity (including a
cross-claim or counterclaim in a lawsuit) alleging that the Work
or a Contribution incorporated within the Work constitutes direct
or contributory patent infringement, then any patent licenses
granted to You under this License for that Work shall terminate
as of the date such litigation is filed.
4. Redistribution. You may reproduce and distribute copies of the
Work or Derivative Works thereof in any medium, with or without
modifications, and in Source or Object form, provided that You
meet the following conditions:
(a) You must give any other recipients of the Work or
Derivative Works a copy of this License; and
(b) You must cause any modified files to carry prominent notices
stating that You changed the files; and
(c) You must retain, in the Source form of any Derivative Works
that You distribute, all copyright, patent, trademark, and
attribution notices from the Source form of the Work,
excluding those notices that do not pertain to any part of
the Derivative Works; and
(d) If the Work includes a "NOTICE" text file as part of its
distribution, then any Derivative Works that You distribute must
include a readable copy of the attribution notices contained
within such NOTICE file, excluding those notices that do not
pertain to any part of the Derivative Works, in at least one
of the following places: within a NOTICE text file distributed
as part of the Derivative Works; within the Source form or
documentation, if provided along with the Derivative Works; or,
within a display generated by the Derivative Works, if and
wherever such third-party notices normally appear. The contents
of the NOTICE file are for informational purposes only and
do not modify the License. You may add Your own attribution
notices within Derivative Works that You distribute, alongside
or as an addendum to the NOTICE text from the Work, provided
that such additional attribution notices cannot be construed
as modifying the License.
You may add Your own copyright statement to Your modifications and
may provide additional or different license terms and conditions
for use, reproduction, or distribution of Your modifications, or
for any such Derivative Works as a whole, provided Your use,
reproduction, and distribution of the Work otherwise complies with
the conditions stated in this License.
5. Submission of Contributions. Unless You explicitly state otherwise,
any Contribution intentionally submitted for inclusion in the Work
by You to the Licensor shall be under the terms and conditions of
this License, without any additional terms or conditions.
Notwithstanding the above, nothing herein shall supersede or modify
the terms of any separate license agreement you may have executed
with Licensor regarding such Contributions.
6. Trademarks. This License does not grant permission to use the trade
names, trademarks, service marks, or product names of the Licensor,
except as required for reasonable and customary use in describing the
origin of the Work and reproducing the content of the NOTICE file.
7. Disclaimer of Warranty. Unless required by applicable law or
agreed to in writing, Licensor provides the Work (and each
Contributor provides its Contributions) on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
implied, including, without limitation, any warranties or conditions
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
PARTICULAR PURPOSE. You are solely responsible for determining the
appropriateness of using or redistributing the Work and assume any
risks associated with Your exercise of permissions under this License.
8. Limitation of Liability. In no event and under no legal theory,
whether in tort (including negligence), contract, or otherwise,
unless required by applicable law (such as deliberate and grossly
negligent acts) or agreed to in writing, shall any Contributor be
liable to You for damages, including any direct, indirect, special,
incidental, or consequential damages of any character arising as a
result of this License or out of the use or inability to use the
Work (including but not limited to damages for loss of goodwill,
work stoppage, computer failure or malfunction, or any and all
other commercial damages or losses), even if such Contributor
has been advised of the possibility of such damages.
9. Accepting Warranty or Additional Liability. While redistributing
the Work or Derivative Works thereof, You may choose to offer,
and charge a fee for, acceptance of support, warranty, indemnity,
or other liability obligations and/or rights consistent with this
License. However, in accepting such obligations, You may act only
on Your own behalf and on Your sole responsibility, not on behalf
of any other Contributor, and only if You agree to indemnify,
defend, and hold each Contributor harmless for any liability
incurred by, or claims asserted against, such Contributor by reason
of your accepting any such warranty or additional liability.

1
vendor/aws/aws-crt-php/NOTICE vendored Normal file
View File

@@ -0,0 +1 @@
Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.

117
vendor/aws/aws-crt-php/README.md vendored Normal file
View File

@@ -0,0 +1,117 @@
# AWS Common Runtime PHP bindings
## Requirements
* PHP 5.5+ on UNIX platforms, 7.2+ on Windows
* CMake 3.x
* GCC 4.4+, clang 3.8+ on UNIX, Visual Studio build tools on Windows
* Tests require [Composer](https://getcomposer.org)
## Installing with Composer and PECL
The package has two different package published to [composer](https://packagist.org/packages/aws/aws-crt-php) and [PECL](https://pecl.php.net/package/awscrt).
On UNIX, you can get the package from package manager or build from source:
```
pecl install awscrt
composer require aws/aws-crt-php
```
On Windows, you need to build from source as instruction written below for the native extension `php_awscrt.dll` . And, follow https://www.php.net/manual/en/install.pecl.windows.php#install.pecl.windows.loading to load extension. After that:
```
composer require aws/aws-crt-php
```
## Building from Github source
```sh
$ git clone --recursive https://github.com/awslabs/aws-crt-php.git
$ cd aws-crt-php
$ phpize
$ ./configure
$ make
$ ./dev-scripts/run_tests.sh
```
## Building on Windows
### Requirements for Windows
* Ensure you have the [windows PHP SDK](https://github.com/microsoft/php-sdk-binary-tools) (this example assumes installation of the SDK to C:\php-sdk and that you've checked out the PHP source to php-src within the build directory) and it works well on your machine.
* Ensure you have "Development package (SDK to develop PHP extensions)" and PHP available from your system path. You can download them from https://windows.php.net/download/. You can check if they are available by running `phpize -v` and `php -v`
### Instructions
From Command Prompt (not powershell). The instruction is based on Visual Studio 2019 on 64bit Windows.
```bat
> git clone --recursive https://github.com/awslabs/aws-crt-php.git
> git clone https://github.com/microsoft/php-sdk-binary-tools.git C:\php-sdk
> C:\php-sdk\phpsdk-vs16-x64.bat
C:\php-sdk\
$ cd <your-path-to-aws-crt-php>
<your-path-to-aws-crt-php>\
$ phpize
# --with-prefix only required when your php runtime in system path is different than the runtime you wish to use.
<your-path-to-aws-crt-php>\
$ configure --enable-awscrt=shared --with-prefix=<your-path-to-php-prefix>
<your-path-to-aws-crt-php>\
$ nmake
<your-path-to-aws-crt-php>\
$ nmake generate-php-ini
# check .\php-win.ini, it now has the full path to php_awscrt.dll that you can manually load to your php runtime, or you can run the following command to run tests and load the required native extension for awscrt.
<your-path-to-aws-crt-php>\
$ .\dev-scripts\run_tests.bat <your-path-to-php-binary>
```
Note: for VS2017, Cmake will default to build for Win32, refer to [here](https://cmake.org/cmake/help/latest/generator/Visual%20Studio%2015%202017.html). If you are building for x64 php, you can set environment variable as follow to let cmake pick x64 compiler.
```bat
set CMAKE_GENERATOR=Visual Studio 15 2017
set CMAKE_GENERATOR_PLATFORM=x64
```
## Debugging
Using [PHPBrew](https://github.com/phpbrew/phpbrew) to build/manage multiple versions of PHP is helpful.
Note: You must use a debug build of PHP to debug native extensions.
See the [PHP Internals Book](https://www.phpinternalsbook.com/php7/build_system/building_php.html) for more info
```shell
# PHP 8 example
$ phpbrew install --stdout -j 8 8.0 +default -- CFLAGS=-Wno-error --disable-cgi --enable-debug
# PHP 5.5 example
$ phpbrew install --stdout -j 8 5.5 +default -openssl -mbstring -- CFLAGS="-w -Wno-error" --enable-debug --with-zlib=/usr/local/opt/zlib
$ phpbrew switch php-8.0.6 # or whatever version is current, it'll be at the end of the build output
$ phpize
$ ./configure
$ make CMAKE_BUILD_TYPE=Debug
```
Ensure that the php you launch from your debugger is the result of `which php` , not just
the system default php.
## Security
See [CONTRIBUTING](CONTRIBUTING.md#security-issue-notifications) for more information.
## Known OpenSSL related issue (Unix only)
* When your php loads a different version of openssl than your system openssl version, awscrt may fail to load or weirdly crash. You can find the openssl version php linked via: `php -i | grep 'OpenSSL'`, and awscrt linked from the build log, which will be `Found OpenSSL: * (found version *)`
The easiest workaround to those issue is to build from source and get aws-lc for awscrt to depend on instead.
TO do that, same instructions as [here](#building-from-github-source), but use `USE_OPENSSL=OFF make` instead of `make`
## License
This project is licensed under the Apache-2.0 License.

35
vendor/aws/aws-crt-php/composer.json vendored Normal file
View File

@@ -0,0 +1,35 @@
{
"name": "aws/aws-crt-php",
"homepage": "https://github.com/awslabs/aws-crt-php",
"description": "AWS Common Runtime for PHP",
"keywords": ["aws","amazon","sdk","crt"],
"type": "library",
"authors": [
{
"name": "AWS SDK Common Runtime Team",
"email": "aws-sdk-common-runtime@amazon.com"
}
],
"minimum-stability": "alpha",
"require": {
"php": ">=5.5"
},
"require-dev": {
"phpunit/phpunit":"^4.8.35||^5.6.3||^9.5",
"yoast/phpunit-polyfills": "^1.0"
},
"autoload": {
"classmap": [
"src/"
]
},
"suggest": {
"ext-awscrt": "Make sure you install awscrt native extension to use any of the functionality."
},
"scripts": {
"test": "./dev-scripts/run_tests.sh",
"test-extension": "@test",
"test-win": ".\\dev-scripts\\run_tests.bat"
},
"license": "Apache-2.0"
}

46
vendor/aws/aws-crt-php/format-check.py vendored Normal file
View File

@@ -0,0 +1,46 @@
#!/usr/bin/env python3
import argparse
import os
from pathlib import Path
import re
from subprocess import list2cmdline, run
from tempfile import NamedTemporaryFile
CLANG_FORMAT_VERSION = '18.1.6'
INCLUDE_REGEX = re.compile(r'^ext/.*\.(c|h|inl)$')
EXCLUDE_REGEX = re.compile(r'^$')
arg_parser = argparse.ArgumentParser(description="Check with clang-format")
arg_parser.add_argument('-i', '--inplace-edit', action='store_true',
help="Edit files inplace")
args = arg_parser.parse_args()
os.chdir(Path(__file__).parent)
# create file containing list of all files to format
filepaths_file = NamedTemporaryFile(delete=False)
for dirpath, dirnames, filenames in os.walk('.'):
for filename in filenames:
# our regexes expect filepath to use forward slash
filepath = Path(dirpath, filename).as_posix()
if not INCLUDE_REGEX.match(filepath):
continue
if EXCLUDE_REGEX.match(filepath):
continue
filepaths_file.write(f"{filepath}\n".encode())
filepaths_file.close()
# use pipx to run clang-format from PyPI
# this is a simple way to run the same clang-format version regardless of OS
cmd = ['pipx', 'run', f'clang-format=={CLANG_FORMAT_VERSION}',
f'--files={filepaths_file.name}']
if args.inplace_edit:
cmd += ['-i']
else:
cmd += ['--Werror', '--dry-run']
print(f"{Path.cwd()}$ {list2cmdline(cmd)}")
if run(cmd).returncode:
exit(1)

View File

@@ -0,0 +1,69 @@
<?php
/**
* Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
* SPDX-License-Identifier: Apache-2.0.
*/
namespace AWS\CRT\Auth;
use AWS\CRT\NativeResource as NativeResource;
use AWS\CRT\Options as Options;
/**
* Represents a set of AWS credentials
*
* @param array options:
* - string access_key_id - AWS Access Key Id
* - string secret_access_key - AWS Secret Access Key
* - string session_token - Optional STS session token
* - int expiration_timepoint_seconds - Optional time to expire these credentials
*/
final class AwsCredentials extends NativeResource {
static function defaults() {
return [
'access_key_id' => '',
'secret_access_key' => '',
'session_token' => '',
'expiration_timepoint_seconds' => 0,
];
}
private $access_key_id;
private $secret_access_key;
private $session_token;
private $expiration_timepoint_seconds = 0;
public function __get($name) {
return $this->$name;
}
function __construct(array $options = []) {
parent::__construct();
$options = new Options($options, self::defaults());
$this->access_key_id = $options->access_key_id->asString();
$this->secret_access_key = $options->secret_access_key->asString();
$this->session_token = $options->session_token ? $options->session_token->asString() : null;
$this->expiration_timepoint_seconds = $options->expiration_timepoint_seconds->asInt();
if (strlen($this->access_key_id) == 0) {
throw new \InvalidArgumentException("access_key_id must be provided");
}
if (strlen($this->secret_access_key) == 0) {
throw new \InvalidArgumentException("secret_access_key must be provided");
}
$creds_options = self::$crt->aws_credentials_options_new();
self::$crt->aws_credentials_options_set_access_key_id($creds_options, $this->access_key_id);
self::$crt->aws_credentials_options_set_secret_access_key($creds_options, $this->secret_access_key);
self::$crt->aws_credentials_options_set_session_token($creds_options, $this->session_token);
self::$crt->aws_credentials_options_set_expiration_timepoint_seconds($creds_options, $this->expiration_timepoint_seconds);
$this->acquire(self::$crt->aws_credentials_new($creds_options));
self::$crt->aws_credentials_options_release($creds_options);
}
function __destruct() {
self::$crt->aws_credentials_release($this->release());
parent::__destruct();
}
}

View File

@@ -0,0 +1,23 @@
<?php
/**
* Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
* SPDX-License-Identifier: Apache-2.0.
*/
namespace AWS\CRT\Auth;
use AWS\CRT\NativeResource as NativeResource;
/**
* Base class for credentials providers
*/
abstract class CredentialsProvider extends NativeResource {
function __construct(array $options = []) {
parent::__construct();
}
function __destruct() {
self::$crt->credentials_provider_release($this->release());
parent::__destruct();
}
}

View File

@@ -0,0 +1,43 @@
<?php
/**
* Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
* SPDX-License-Identifier: Apache-2.0.
*/
namespace AWS\CRT\Auth;
use AWS\CRT\IO\InputStream;
use AWS\CRT\NativeResource as NativeResource;
class Signable extends NativeResource {
public static function fromHttpRequest($http_message) {
return new Signable(function() use ($http_message) {
return self::$crt->signable_new_from_http_request($http_message->native);
});
}
public static function fromChunk($chunk_stream, $previous_signature="") {
if (!($chunk_stream instanceof InputStream)) {
$chunk_stream = new InputStream($chunk_stream);
}
return new Signable(function() use($chunk_stream, $previous_signature) {
return self::$crt->signable_new_from_chunk($chunk_stream->native, $previous_signature);
});
}
public static function fromCanonicalRequest($canonical_request) {
return new Signable(function() use($canonical_request) {
return self::$crt->signable_new_from_canonical_request($canonical_request);
});
}
protected function __construct($ctor) {
parent::__construct();
$this->acquire($ctor());
}
function __destruct() {
self::$crt->signable_release($this->release());
parent::__destruct();
}
}

View File

@@ -0,0 +1,15 @@
<?php
/**
* Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
* SPDX-License-Identifier: Apache-2.0.
*/
namespace AWS\CRT\Auth;
class SignatureType {
const HTTP_REQUEST_HEADERS = 0;
const HTTP_REQUEST_QUERY_PARAMS = 1;
const HTTP_REQUEST_CHUNK = 2;
const HTTP_REQUEST_EVENT = 3;
const CANONICAL_REQUEST_HEADERS = 4;
const CANONICAL_REQUEST_QUERY_PARAMS = 5;
}

View File

@@ -0,0 +1,11 @@
<?php
/**
* Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
* SPDX-License-Identifier: Apache-2.0.
*/
namespace AWS\CRT\Auth;
class SignedBodyHeaderType {
const NONE = 0;
const X_AMZ_CONTENT_SHA256 = 1;
}

View File

@@ -0,0 +1,22 @@
<?php
/**
* Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
* SPDX-License-Identifier: Apache-2.0.
*/
namespace AWS\CRT\Auth;
use AWS\CRT\NativeResource;
abstract class Signing extends NativeResource {
static function signRequestAws($signable, $signing_config, $on_complete) {
return self::$crt->sign_request_aws($signable->native, $signing_config->native,
function($result, $error_code) use ($on_complete) {
$signing_result = SigningResult::fromNative($result);
$on_complete($signing_result, $error_code);
}, null);
}
static function testVerifySigV4ASigning($signable, $signing_config, $expected_canonical_request, $signature, $ecc_key_pub_x, $ecc_key_pub_y) {
return self::$crt->test_verify_sigv4a_signing($signable, $signing_config, $expected_canonical_request, $signature, $ecc_key_pub_x, $ecc_key_pub_y);
}
}

View File

@@ -0,0 +1,11 @@
<?php
/**
* Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
* SPDX-License-Identifier: Apache-2.0.
*/
namespace AWS\CRT\Auth;
class SigningAlgorithm {
const SIGv4 = 0;
const SIGv4_ASYMMETRIC = 1;
}

View File

@@ -0,0 +1,75 @@
<?php
/**
* Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
* SPDX-License-Identifier: Apache-2.0.
*/
namespace AWS\CRT\Auth;
use AWS\CRT\NativeResource as NativeResource;
use AWS\CRT\Options as Options;
class SigningConfigAWS extends NativeResource {
public static function defaults() {
return [
'algorithm' => SigningAlgorithm::SIGv4,
'signature_type' => SignatureType::HTTP_REQUEST_HEADERS,
'credentials_provider' => null,
'region' => null,
'service' => null,
'use_double_uri_encode' => false,
'should_normalize_uri_path' => false,
'omit_session_token' => false,
'signed_body_value' => null,
'signed_body_header_type' => SignedBodyHeaderType::NONE,
'expiration_in_seconds' => 0,
'date' => time(),
'should_sign_header' => null,
];
}
private $options;
public function __construct(array $options = []) {
parent::__construct();
$this->options = $options = new Options($options, self::defaults());
$sc = $this->acquire(self::$crt->signing_config_aws_new());
self::$crt->signing_config_aws_set_algorithm($sc, $options->algorithm->asInt());
self::$crt->signing_config_aws_set_signature_type($sc, $options->signature_type->asInt());
if ($credentials_provider = $options->credentials_provider->asObject()) {
self::$crt->signing_config_aws_set_credentials_provider(
$sc,
$credentials_provider->native);
}
self::$crt->signing_config_aws_set_region(
$sc, $options->region->asString());
self::$crt->signing_config_aws_set_service(
$sc, $options->service->asString());
self::$crt->signing_config_aws_set_use_double_uri_encode(
$sc, $options->use_double_uri_encode->asBool());
self::$crt->signing_config_aws_set_should_normalize_uri_path(
$sc, $options->should_normalize_uri_path->asBool());
self::$crt->signing_config_aws_set_omit_session_token(
$sc, $options->omit_session_token->asBool());
self::$crt->signing_config_aws_set_signed_body_value(
$sc, $options->signed_body_value->asString());
self::$crt->signing_config_aws_set_signed_body_header_type(
$sc, $options->signed_body_header_type->asInt());
self::$crt->signing_config_aws_set_expiration_in_seconds(
$sc, $options->expiration_in_seconds->asInt());
self::$crt->signing_config_aws_set_date($sc, $options->date->asInt());
if ($should_sign_header = $options->should_sign_header->asCallable()) {
self::$crt->signing_config_aws_set_should_sign_header_fn($sc, $should_sign_header);
}
}
function __destruct()
{
self::$crt->signing_config_aws_release($this->release());
parent::__destruct();
}
public function __get($name) {
return $this->options->get($name);
}
}

View File

@@ -0,0 +1,33 @@
<?php
/**
* Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
* SPDX-License-Identifier: Apache-2.0.
*/
namespace AWS\CRT\Auth;
use AWS\CRT\NativeResource;
use AWS\CRT\HTTP\Request;
class SigningResult extends NativeResource {
protected function __construct($native) {
parent::__construct();
$this->acquire($native);
}
function __destruct() {
// No destruction necessary, SigningResults are transient, just release
$this->release();
parent::__destruct();
}
public static function fromNative($ptr) {
return new SigningResult($ptr);
}
public function applyToHttpRequest(&$http_request) {
self::$crt->signing_result_apply_to_http_request($this->native, $http_request->native);
// Update http_request from native
$http_request = Request::unmarshall($http_request->toBlob());
}
}

View File

@@ -0,0 +1,35 @@
<?php
/**
* Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
* SPDX-License-Identifier: Apache-2.0.
*/
namespace AWS\CRT\Auth;
/**
* Provides a static set of AWS credentials
*
* @param array options:
* - string access_key_id - AWS Access Key Id
* - string secret_access_key - AWS Secret Access Key
* - string session_token - Optional STS session token
*/
final class StaticCredentialsProvider extends CredentialsProvider {
private $credentials;
public function __get($name) {
return $this->$name;
}
function __construct(array $options = []) {
parent::__construct();
$this->credentials = new AwsCredentials($options);
$provider_options = self::$crt->credentials_provider_static_options_new();
self::$crt->credentials_provider_static_options_set_access_key_id($provider_options, $this->credentials->access_key_id);
self::$crt->credentials_provider_static_options_set_secret_access_key($provider_options, $this->credentials->secret_access_key);
self::$crt->credentials_provider_static_options_set_session_token($provider_options, $this->credentials->session_token);
$this->acquire(self::$crt->credentials_provider_static_new($provider_options));
self::$crt->credentials_provider_static_options_release($provider_options);
}
}

Some files were not shown because too many files have changed in this diff Show More