@@ -0,0 +1,42 @@ | |||
composer.phar | |||
/old/ | |||
# Compiled source # | |||
################### | |||
*.com | |||
*.class | |||
*.dll | |||
*.exe | |||
*.o | |||
*.so | |||
# Packages # | |||
############ | |||
# it's better to unpack these files and commit the raw source | |||
# git has its own built in compression methods | |||
*.7z | |||
*.dmg | |||
*.gz | |||
*.iso | |||
*.jar | |||
*.rar | |||
*.tar | |||
*.zip | |||
# Logs and databases # | |||
###################### | |||
*.log | |||
*.sql | |||
*.sqlite | |||
# OS generated files # | |||
###################### | |||
.DS_Store | |||
.DS_Store? | |||
._* | |||
.Spotlight-V100 | |||
.Trashes | |||
ehthumbs.db | |||
Thumbs.db | |||
@@ -0,0 +1,21 @@ | |||
################################################## | |||
# Gustavo Arnosti Neves - 2016 Jul 11 | |||
# Simple makefile for system install / uninstall | |||
# PHP cli-barcode-generator | |||
# Change INSTDIR if you want to install somewhere else | |||
INSTDIR=/usr/local/bin | |||
BC_BASH=barcode | |||
all: | |||
install: | |||
cp ${BC_BASH} ${INSTDIR}/${BC_BASH} | |||
chmod 755 ${INSTDIR}/${BC_BASH} | |||
permissions: | |||
find . -type d -exec chmod 0755 {} \; | |||
find . -type f -exec chmod 0644 {} \; | |||
uninstall: | |||
rm ${INSTDIR}/${BC_BASH} |
@@ -0,0 +1,15 @@ | |||
#!/usr/bin/env bash | |||
################################################## | |||
# Gustavo Arnosti Neves - 2016 Jul 11 | |||
# Simple bash script for global barcode executable | |||
# PHP cli-barcode-generator | |||
# | |||
# Please run "./barcode.php --create-bash" to update this script | |||
# You can then use sudo make install to copy it to /usr/local/bin | |||
# | |||
# This won't work on windows | |||
# | |||
BARCODE_LOCATION="./barcode.php" # enter full path here | |||
/usr/bin/env php "$BARCODE_LOCATION" "$@" |
@@ -0,0 +1,298 @@ | |||
#!/usr/bin/env php | |||
<?php | |||
########################################################################## | |||
# Gustavo Arnosti Neves - 2016 Jul 11 | |||
# guneves < a t > gmail < d o t > com | |||
# | |||
# PHP cli-barcode-generator | |||
# | |||
# Most of the work here is for option / argument parsing. | |||
# Picqer's barcode framework makes it east on the bar coding generation. | |||
# While ulrichsg's getopt-php helps with the cli part. | |||
# | |||
########################################################################## | |||
require_once 'vendor/autoload.php'; | |||
define("_BC_VERSION", "1.0.2"); | |||
# permission to set to barcode files | |||
define("_BC_PERMISSION", 0644); | |||
# group to set to barcode files (disabled at bot) | |||
define("_BC_SYSGROUP", "yourGrpHere"); | |||
# default padding for barcode | |||
define("_BC_PADDING", 30); | |||
$verbose = false; | |||
$quiet = false; | |||
$encoding = null; | |||
$format = null; | |||
$bc_string = null; | |||
$bc_file = null; | |||
$width = 2; | |||
$height = 30; | |||
$color = '#000000'; | |||
$encodings_list = array( | |||
'CODE_39', | |||
'CODE_39_CHECKSUM', | |||
'CODE_39E', | |||
'CODE_39E_CHECKSUM', | |||
'CODE_93', | |||
'STANDARD_2_5', | |||
'STANDARD_2_5_CHECKSUM', | |||
'INTERLEAVED_2_5', | |||
'INTERLEAVED_2_5_CHECKSUM', | |||
'CODE_128', | |||
'CODE_128_A', | |||
'CODE_128_B', | |||
'CODE_128_C', | |||
'EAN_2', | |||
'EAN_5', | |||
'EAN_8', | |||
'EAN_13', | |||
'UPC_A', | |||
'UPC_E', | |||
'MSI', | |||
'MSI_CHECKSUM', | |||
'POSTNET', | |||
'PLANET', | |||
'RMS4CC', | |||
'KIX', | |||
'IMB', | |||
'CODABAR', | |||
'CODE_11', | |||
'PHARMA_CODE', | |||
'PHARMA_CODE_TWO_TRACKS' | |||
); | |||
sort($encodings_list); | |||
$formats_list = array( | |||
'SVG', | |||
'PNG', | |||
'JPG', | |||
'HTML' | |||
); | |||
sort($formats_list); | |||
/////////////////// GETOPT STARTS | |||
use Ulrichsg\Getopt\Getopt; | |||
use Ulrichsg\Getopt\Option; | |||
use Ulrichsg\Getopt\Argument; | |||
// define and configure options | |||
$getopt = new Getopt(array( | |||
(new Option('e', 'encoding', Getopt::REQUIRED_ARGUMENT)) | |||
->setDescription('Barcode encoding type selection') | |||
->setValidation(function($value) { | |||
global $encodings_list; | |||
return in_array(strtoupper($value), $encodings_list); | |||
}) | |||
->setArgument(new Argument(null, null, 'bar-type')), | |||
(new Option('f', 'format', Getopt::REQUIRED_ARGUMENT)) | |||
->setDescription('Output format for the barcode') | |||
->setValidation(function($value, $formats_list) { | |||
global $formats_list; | |||
return in_array(strtoupper($value), $formats_list); | |||
}) | |||
->setArgument(new Argument(null, null, 'file-type')), | |||
(new Option('w', 'width', Getopt::REQUIRED_ARGUMENT)) | |||
->setDescription('Width factor for bars to make wider, defaults to 2') | |||
->setArgument(new Argument(2, 'is_numeric', 'points')), | |||
(new Option('h', 'height', Getopt::REQUIRED_ARGUMENT)) | |||
->setDescription('Total height of the barcode, defaults to 30') | |||
->setArgument(new Argument(30, 'is_numeric', 'points')), | |||
(new Option('c', 'color', Getopt::REQUIRED_ARGUMENT)) | |||
->setDescription('Hex code of the foreground color, defaults to black') | |||
->setArgument(new Argument('#000000', 'not_empty', 'hex-color')), | |||
(new Option('v', 'verbose')) | |||
->setDescription('Display extra information') | |||
->setDefaultValue(false), | |||
(new Option('q', 'quiet')) | |||
->setDescription('Supress all messages') | |||
->setDefaultValue(false), | |||
(new Option(null, 'help')) | |||
->setDescription('Help Information, including encodings and formats'), | |||
(new Option(null, 'version')) | |||
->setDescription('Display version information and exits'), | |||
(new Option(null, 'create-bash')) | |||
->setDescription('Creates a bash script named barcode that can call this script') | |||
)); | |||
$getopt->setBanner("Usage: barcode -e <encoding> -f <output_format> [options] <barcode string> <output file>\n"); | |||
try { | |||
$getopt->parse(); | |||
if ($getopt['version']) { | |||
echo "PHP-CLI Barcode v"._BC_VERSION."\n"; | |||
exit(0); | |||
} | |||
if ($getopt['help']) { | |||
print_help($getopt); | |||
exit(0); | |||
} | |||
if ($getopt['create-bash']) { | |||
create_bash_script(); | |||
exit(1); | |||
} | |||
$verbose = $getopt['verbose']; | |||
$quiet = $getopt['quiet']; | |||
$encoding = $getopt['encoding']; | |||
$format = $getopt['format']; | |||
$width = $getopt['width']; | |||
$height = $getopt['height']; | |||
$color = $getopt['color']; | |||
$bc_string = $getopt->getOperand(0); | |||
$bc_file = $getopt->getOperand(1); | |||
} catch (UnexpectedValueException $e) { | |||
echo "Error: ".$e->getMessage()."\n"; | |||
echo $getopt->getHelpText(_BC_PADDING); | |||
exit(1); | |||
} | |||
// check if we can proceed | |||
if (empty($encoding) || empty($format) || empty($bc_string) || empty($bc_file)) { | |||
echo "Error: Invalid parameters or options.\n"; | |||
echo $getopt->getHelpText(_BC_PADDING); | |||
exit(1); | |||
} | |||
// Match case | |||
$encoding = strtoupper($encoding); | |||
$format = strtoupper($format); | |||
/////////////////// GETOPT ENDS | |||
/////////////////// CREATE BARCODE | |||
// creates a bash script named barcode that will run this script | |||
// from anywhere on the system. Assumes barcode.php is running | |||
// on its final installation location | |||
function create_bash_script() { | |||
$error = true; | |||
$bc_path = __FILE__; | |||
$bash_path = dirname($bc_path) . DIRECTORY_SEPARATOR . "barcode"; | |||
$bash_script = <<<EOF | |||
#!/usr/bin/env bash | |||
################################################## | |||
# Gustavo Arnosti Neves - 2016 Jul 11 | |||
# Simple bash script for global barcode executable | |||
# PHP cli-barcode-generator | |||
# | |||
# Please run "./barcode.php --create-bash" to update this script | |||
# You can then use sudo make install to copy it to /usr/local/bin | |||
# | |||
# This won't work on windows | |||
# | |||
BARCODE_LOCATION="$bc_path" # enter full path here | |||
/usr/bin/env php "\$BARCODE_LOCATION" "\$@" | |||
EOF; | |||
if (file_exists($bash_path)) { | |||
unlink($bash_path) or die("Could not remove old barcode script, are you running from it?"); | |||
} | |||
$error = file_put_contents($bash_path, $bash_script) === true ? false : true; | |||
$error = chmod($bash_path, 0755) === true ? false : true; | |||
if ($error) { | |||
echo "\nAn error was detected during the process.\n"; | |||
echo "Please check for permissions and try again.\n\n"; | |||
exit(2); | |||
} | |||
echo "\nThe file \"$bash_path\" was successfully created.\n"; | |||
echo "You may perform a system install to /usr/local/bin by issuing\n"; | |||
echo "the command \"sudo make install\"\n\n"; | |||
exit(0); | |||
} | |||
// get actual barcode type string | |||
$bc_type = constant('Picqer\Barcode\BarcodeGenerator::TYPE_'.$encoding); | |||
// add trailling zero if odd digits on Code128C | |||
$bc_string = strlen($bc_string) % 2 == 0 && $encoding === 'CODE_128_C'? | |||
$bc_string : '0'.$bc_string; | |||
// create appropriate generator | |||
$generator = null; | |||
if ($format === 'SVG') { | |||
$generator = new Picqer\Barcode\BarcodeGeneratorSVG(); | |||
} else if ($format === 'PNG') { | |||
$generator = new Picqer\Barcode\BarcodeGeneratorPNG(); | |||
} else if ($format === 'JPG') { | |||
$generator = new Picqer\Barcode\BarcodeGeneratorJPG(); | |||
} else if ($format === 'HTML') { | |||
$generator = new Picqer\Barcode\BarcodeGeneratorHTML(); | |||
} else { | |||
exit(1); | |||
} | |||
// generate de barcode | |||
$bc_data = $generator->getBarcode($bc_string, $bc_type, $width, $height, $color); | |||
// save to file | |||
if (file_put_contents($bc_file, $bc_data) === false) { | |||
echo "Error: could not save file $bc_file!\n"; | |||
exit(1); | |||
} | |||
// set permissions and group | |||
chmod($bc_file, _BC_PERMISSION); | |||
#chgrp($bc_file, _BC_SYSGROUP); | |||
// prints help information | |||
function print_help($getopt) { | |||
global $encodings_list; | |||
global $formats_list; | |||
echo $getopt->getHelpText(_BC_PADDING); | |||
echo "\nRequired Options and Parameters:\n"; | |||
echo " -e <encoding>\n"; | |||
echo " -f <output format>\n"; | |||
echo " <input string>\n"; | |||
echo " <output file>\n"; | |||
echo "\nOutput Formats:\n"; | |||
foreach($formats_list as $for) { | |||
echo " $for\n"; | |||
} | |||
echo "\nEncodings:\n"; | |||
foreach($encodings_list as $enc) { | |||
echo " $enc\n"; | |||
} | |||
echo "\nExamples:\n"; | |||
echo " barcode -f HTML -e CODE_39 \"1234567890\" \"/tmp/1234567890.html\"\n"; | |||
echo " barcode -e CODE_128 -f PNG -c \"#888\" -w 3 -h 50 \"AGREATBAR\" \"/tmp/AGREATBAR.png\"\n"; | |||
echo " barcode \"1234567890\" \"/tmp/mybar.svg\" --encoding EAN_13 --format SVG\n"; | |||
} | |||
// check if empty (callback) | |||
function not_empty($str) { | |||
return (!empty($str)); | |||
} | |||
// done | |||
exit(0); | |||
?> |
@@ -0,0 +1,6 @@ | |||
{ | |||
"require": { | |||
"picqer/php-barcode-generator": "^0.1.0", | |||
"ulrichsg/getopt-php": "^2.3" | |||
} | |||
} |
@@ -0,0 +1,120 @@ | |||
{ | |||
"_readme": [ | |||
"This file locks the dependencies of your project to a known state", | |||
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#composer-lock-the-lock-file", | |||
"This file is @generated automatically" | |||
], | |||
"hash": "a723e9e5630e78d2303e845440a976b2", | |||
"content-hash": "8180bfe7b58f0f40617b074b3efc026a", | |||
"packages": [ | |||
{ | |||
"name": "picqer/php-barcode-generator", | |||
"version": "v0.1", | |||
"source": { | |||
"type": "git", | |||
"url": "https://github.com/picqer/php-barcode-generator.git", | |||
"reference": "bd486cfb311989a506c62827fdee463b8a698002" | |||
}, | |||
"dist": { | |||
"type": "zip", | |||
"url": "https://api.github.com/repos/picqer/php-barcode-generator/zipball/bd486cfb311989a506c62827fdee463b8a698002", | |||
"reference": "bd486cfb311989a506c62827fdee463b8a698002", | |||
"shasum": "" | |||
}, | |||
"require": { | |||
"php": ">=5.4.0" | |||
}, | |||
"type": "library", | |||
"autoload": { | |||
"psr-4": { | |||
"Picqer\\Barcode\\": "src" | |||
} | |||
}, | |||
"notification-url": "https://packagist.org/downloads/", | |||
"license": [ | |||
"MIT" | |||
], | |||
"authors": [ | |||
{ | |||
"name": "Casper Bakker", | |||
"email": "info@picqer.com" | |||
} | |||
], | |||
"description": "An easy to use, non-bloated, barcode generator in PHP. Creates SVG, PNG, JPG and HTML images from the most used 1D barcode standards.", | |||
"homepage": "http://github.com/picqer/exact-php-client", | |||
"keywords": [ | |||
"CODABAR", | |||
"Code11", | |||
"Code93", | |||
"EAN13", | |||
"KIX", | |||
"KIXCODE", | |||
"MSI", | |||
"POSTNET", | |||
"Pharma", | |||
"Standard 2 of 5", | |||
"barcode", | |||
"barcode generator", | |||
"code128", | |||
"code39", | |||
"ean", | |||
"html", | |||
"jpeg", | |||
"jpg", | |||
"php", | |||
"png", | |||
"svg", | |||
"upc" | |||
], | |||
"time": "2015-08-13 07:59:44" | |||
}, | |||
{ | |||
"name": "ulrichsg/getopt-php", | |||
"version": "2.3.0", | |||
"source": { | |||
"type": "git", | |||
"url": "https://github.com/ulrichsg/getopt-php.git", | |||
"reference": "a51554a16e206a6642bf1a0d7d1e4378ec2ba980" | |||
}, | |||
"dist": { | |||
"type": "zip", | |||
"url": "https://api.github.com/repos/ulrichsg/getopt-php/zipball/a51554a16e206a6642bf1a0d7d1e4378ec2ba980", | |||
"reference": "a51554a16e206a6642bf1a0d7d1e4378ec2ba980", | |||
"shasum": "" | |||
}, | |||
"require": { | |||
"php": ">=5.3.0" | |||
}, | |||
"require-dev": { | |||
"phpunit/phpunit": "3.7.*" | |||
}, | |||
"type": "library", | |||
"autoload": { | |||
"psr-0": { | |||
"Ulrichsg\\": "src" | |||
} | |||
}, | |||
"notification-url": "https://packagist.org/downloads/", | |||
"license": [ | |||
"MIT" | |||
], | |||
"authors": [ | |||
{ | |||
"name": "Ulrich Schmidt-Goertz", | |||
"email": "ulrich@schmidt-goertz.de" | |||
} | |||
], | |||
"description": "Command line arguments parser for PHP 5.3", | |||
"homepage": "http://ulrichsg.github.io/getopt-php", | |||
"time": "2015-03-28 14:09:20" | |||
} | |||
], | |||
"packages-dev": [], | |||
"aliases": [], | |||
"minimum-stability": "stable", | |||
"stability-flags": [], | |||
"prefer-stable": false, | |||
"prefer-lowest": false, | |||
"platform": [], | |||
"platform-dev": [] | |||
} |
@@ -0,0 +1,7 @@ | |||
<?php | |||
// autoload.php @generated by Composer | |||
require_once __DIR__ . '/composer' . '/autoload_real.php'; | |||
return ComposerAutoloaderInitf17787d2ecff231b84857fe0d96cbca5::getLoader(); |
@@ -0,0 +1,413 @@ | |||
<?php | |||
/* | |||
* This file is part of Composer. | |||
* | |||
* (c) Nils Adermann <naderman@naderman.de> | |||
* Jordi Boggiano <j.boggiano@seld.be> | |||
* | |||
* For the full copyright and license information, please view the LICENSE | |||
* file that was distributed with this source code. | |||
*/ | |||
namespace Composer\Autoload; | |||
/** | |||
* ClassLoader implements a PSR-0, PSR-4 and classmap class loader. | |||
* | |||
* $loader = new \Composer\Autoload\ClassLoader(); | |||
* | |||
* // register classes with namespaces | |||
* $loader->add('Symfony\Component', __DIR__.'/component'); | |||
* $loader->add('Symfony', __DIR__.'/framework'); | |||
* | |||
* // activate the autoloader | |||
* $loader->register(); | |||
* | |||
* // to enable searching the include path (eg. for PEAR packages) | |||
* $loader->setUseIncludePath(true); | |||
* | |||
* In this example, if you try to use a class in the Symfony\Component | |||
* namespace or one of its children (Symfony\Component\Console for instance), | |||
* the autoloader will first look for the class under the component/ | |||
* directory, and it will then fallback to the framework/ directory if not | |||
* found before giving up. | |||
* | |||
* This class is loosely based on the Symfony UniversalClassLoader. | |||
* | |||
* @author Fabien Potencier <fabien@symfony.com> | |||
* @author Jordi Boggiano <j.boggiano@seld.be> | |||
* @see http://www.php-fig.org/psr/psr-0/ | |||
* @see http://www.php-fig.org/psr/psr-4/ | |||
*/ | |||
class ClassLoader | |||
{ | |||
// PSR-4 | |||
private $prefixLengthsPsr4 = array(); | |||
private $prefixDirsPsr4 = array(); | |||
private $fallbackDirsPsr4 = array(); | |||
// PSR-0 | |||
private $prefixesPsr0 = array(); | |||
private $fallbackDirsPsr0 = array(); | |||
private $useIncludePath = false; | |||
private $classMap = array(); | |||
private $classMapAuthoritative = false; | |||
public function getPrefixes() | |||
{ | |||
if (!empty($this->prefixesPsr0)) { | |||
return call_user_func_array('array_merge', $this->prefixesPsr0); | |||
} | |||
return array(); | |||
} | |||
public function getPrefixesPsr4() | |||
{ | |||
return $this->prefixDirsPsr4; | |||
} | |||
public function getFallbackDirs() | |||
{ | |||
return $this->fallbackDirsPsr0; | |||
} | |||
public function getFallbackDirsPsr4() | |||
{ | |||
return $this->fallbackDirsPsr4; | |||
} | |||
public function getClassMap() | |||
{ | |||
return $this->classMap; | |||
} | |||
/** | |||
* @param array $classMap Class to filename map | |||
*/ | |||
public function addClassMap(array $classMap) | |||
{ | |||
if ($this->classMap) { | |||
$this->classMap = array_merge($this->classMap, $classMap); | |||
} else { | |||
$this->classMap = $classMap; | |||
} | |||
} | |||
/** | |||
* Registers a set of PSR-0 directories for a given prefix, either | |||
* appending or prepending to the ones previously set for this prefix. | |||
* | |||
* @param string $prefix The prefix | |||
* @param array|string $paths The PSR-0 root directories | |||
* @param bool $prepend Whether to prepend the directories | |||
*/ | |||
public function add($prefix, $paths, $prepend = false) | |||
{ | |||
if (!$prefix) { | |||
if ($prepend) { | |||
$this->fallbackDirsPsr0 = array_merge( | |||
(array) $paths, | |||
$this->fallbackDirsPsr0 | |||
); | |||
} else { | |||
$this->fallbackDirsPsr0 = array_merge( | |||
$this->fallbackDirsPsr0, | |||
(array) $paths | |||
); | |||
} | |||
return; | |||
} | |||
$first = $prefix[0]; | |||
if (!isset($this->prefixesPsr0[$first][$prefix])) { | |||
$this->prefixesPsr0[$first][$prefix] = (array) $paths; | |||
return; | |||
} | |||
if ($prepend) { | |||
$this->prefixesPsr0[$first][$prefix] = array_merge( | |||
(array) $paths, | |||
$this->prefixesPsr0[$first][$prefix] | |||
); | |||
} else { | |||
$this->prefixesPsr0[$first][$prefix] = array_merge( | |||
$this->prefixesPsr0[$first][$prefix], | |||
(array) $paths | |||
); | |||
} | |||
} | |||
/** | |||
* Registers a set of PSR-4 directories for a given namespace, either | |||
* appending or prepending to the ones previously set for this namespace. | |||
* | |||
* @param string $prefix The prefix/namespace, with trailing '\\' | |||
* @param array|string $paths The PSR-4 base directories | |||
* @param bool $prepend Whether to prepend the directories | |||
* | |||
* @throws \InvalidArgumentException | |||
*/ | |||
public function addPsr4($prefix, $paths, $prepend = false) | |||
{ | |||
if (!$prefix) { | |||
// Register directories for the root namespace. | |||
if ($prepend) { | |||
$this->fallbackDirsPsr4 = array_merge( | |||
(array) $paths, | |||
$this->fallbackDirsPsr4 | |||
); | |||
} else { | |||
$this->fallbackDirsPsr4 = array_merge( | |||
$this->fallbackDirsPsr4, | |||
(array) $paths | |||
); | |||
} | |||
} elseif (!isset($this->prefixDirsPsr4[$prefix])) { | |||
// Register directories for a new namespace. | |||
$length = strlen($prefix); | |||
if ('\\' !== $prefix[$length - 1]) { | |||
throw new \InvalidArgumentException("A non-empty PSR-4 prefix must end with a namespace separator."); | |||
} | |||
$this->prefixLengthsPsr4[$prefix[0]][$prefix] = $length; | |||
$this->prefixDirsPsr4[$prefix] = (array) $paths; | |||
} elseif ($prepend) { | |||
// Prepend directories for an already registered namespace. | |||
$this->prefixDirsPsr4[$prefix] = array_merge( | |||
(array) $paths, | |||
$this->prefixDirsPsr4[$prefix] | |||
); | |||
} else { | |||
// Append directories for an already registered namespace. | |||
$this->prefixDirsPsr4[$prefix] = array_merge( | |||
$this->prefixDirsPsr4[$prefix], | |||
(array) $paths | |||
); | |||
} | |||
} | |||
/** | |||
* Registers a set of PSR-0 directories for a given prefix, | |||
* replacing any others previously set for this prefix. | |||
* | |||
* @param string $prefix The prefix | |||
* @param array|string $paths The PSR-0 base directories | |||
*/ | |||
public function set($prefix, $paths) | |||
{ | |||
if (!$prefix) { | |||
$this->fallbackDirsPsr0 = (array) $paths; | |||
} else { | |||
$this->prefixesPsr0[$prefix[0]][$prefix] = (array) $paths; | |||
} | |||
} | |||
/** | |||
* Registers a set of PSR-4 directories for a given namespace, | |||
* replacing any others previously set for this namespace. | |||
* | |||
* @param string $prefix The prefix/namespace, with trailing '\\' | |||
* @param array|string $paths The PSR-4 base directories | |||
* | |||
* @throws \InvalidArgumentException | |||
*/ | |||
public function setPsr4($prefix, $paths) | |||
{ | |||
if (!$prefix) { | |||
$this->fallbackDirsPsr4 = (array) $paths; | |||
} else { | |||
$length = strlen($prefix); | |||
if ('\\' !== $prefix[$length - 1]) { | |||
throw new \InvalidArgumentException("A non-empty PSR-4 prefix must end with a namespace separator."); | |||
} | |||
$this->prefixLengthsPsr4[$prefix[0]][$prefix] = $length; | |||
$this->prefixDirsPsr4[$prefix] = (array) $paths; | |||
} | |||
} | |||
/** | |||
* Turns on searching the include path for class files. | |||
* | |||
* @param bool $useIncludePath | |||
*/ | |||
public function setUseIncludePath($useIncludePath) | |||
{ | |||
$this->useIncludePath = $useIncludePath; | |||
} | |||
/** | |||
* Can be used to check if the autoloader uses the include path to check | |||
* for classes. | |||
* | |||
* @return bool | |||
*/ | |||
public function getUseIncludePath() | |||
{ | |||
return $this->useIncludePath; | |||
} | |||
/** | |||
* Turns off searching the prefix and fallback directories for classes | |||
* that have not been registered with the class map. | |||
* | |||
* @param bool $classMapAuthoritative | |||
*/ | |||
public function setClassMapAuthoritative($classMapAuthoritative) | |||
{ | |||
$this->classMapAuthoritative = $classMapAuthoritative; | |||
} | |||
/** | |||
* Should class lookup fail if not found in the current class map? | |||
* | |||
* @return bool | |||
*/ | |||
public function isClassMapAuthoritative() | |||
{ | |||
return $this->classMapAuthoritative; | |||
} | |||
/** | |||
* Registers this instance as an autoloader. | |||
* | |||
* @param bool $prepend Whether to prepend the autoloader or not | |||
*/ | |||
public function register($prepend = false) | |||
{ | |||
spl_autoload_register(array($this, 'loadClass'), true, $prepend); | |||
} | |||
/** | |||
* Unregisters this instance as an autoloader. | |||
*/ | |||
public function unregister() | |||
{ | |||
spl_autoload_unregister(array($this, 'loadClass')); | |||
} | |||
/** | |||
* Loads the given class or interface. | |||
* | |||
* @param string $class The name of the class | |||
* @return bool|null True if loaded, null otherwise | |||
*/ | |||
public function loadClass($class) | |||
{ | |||
if ($file = $this->findFile($class)) { | |||
includeFile($file); | |||
return true; | |||
} | |||
} | |||
/** | |||
* Finds the path to the file where the class is defined. | |||
* | |||
* @param string $class The name of the class | |||
* | |||
* @return string|false The path if found, false otherwise | |||
*/ | |||
public function findFile($class) | |||
{ | |||
// work around for PHP 5.3.0 - 5.3.2 https://bugs.php.net/50731 | |||
if ('\\' == $class[0]) { | |||
$class = substr($class, 1); | |||
} | |||
// class map lookup | |||
if (isset($this->classMap[$class])) { | |||
return $this->classMap[$class]; | |||
} | |||
if ($this->classMapAuthoritative) { | |||
return false; | |||
} | |||
$file = $this->findFileWithExtension($class, '.php'); | |||
// Search for Hack files if we are running on HHVM | |||
if ($file === null && defined('HHVM_VERSION')) { | |||
$file = $this->findFileWithExtension($class, '.hh'); | |||
} | |||
if ($file === null) { | |||
// Remember that this class does not exist. | |||
return $this->classMap[$class] = false; | |||
} | |||
return $file; | |||
} | |||
private function findFileWithExtension($class, $ext) | |||
{ | |||
// PSR-4 lookup | |||
$logicalPathPsr4 = strtr($class, '\\', DIRECTORY_SEPARATOR) . $ext; | |||
$first = $class[0]; | |||
if (isset($this->prefixLengthsPsr4[$first])) { | |||
foreach ($this->prefixLengthsPsr4[$first] as $prefix => $length) { | |||
if (0 === strpos($class, $prefix)) { | |||
foreach ($this->prefixDirsPsr4[$prefix] as $dir) { | |||
if (file_exists($file = $dir . DIRECTORY_SEPARATOR . substr($logicalPathPsr4, $length))) { | |||
return $file; | |||
} | |||
} | |||
} | |||
} | |||
} | |||
// PSR-4 fallback dirs | |||
foreach ($this->fallbackDirsPsr4 as $dir) { | |||
if (file_exists($file = $dir . DIRECTORY_SEPARATOR . $logicalPathPsr4)) { | |||
return $file; | |||
} | |||
} | |||
// PSR-0 lookup | |||
if (false !== $pos = strrpos($class, '\\')) { | |||
// namespaced class name | |||
$logicalPathPsr0 = substr($logicalPathPsr4, 0, $pos + 1) | |||
. strtr(substr($logicalPathPsr4, $pos + 1), '_', DIRECTORY_SEPARATOR); | |||
} else { | |||
// PEAR-like class name | |||
$logicalPathPsr0 = strtr($class, '_', DIRECTORY_SEPARATOR) . $ext; | |||
} | |||
if (isset($this->prefixesPsr0[$first])) { | |||
foreach ($this->prefixesPsr0[$first] as $prefix => $dirs) { | |||
if (0 === strpos($class, $prefix)) { | |||
foreach ($dirs as $dir) { | |||
if (file_exists($file = $dir . DIRECTORY_SEPARATOR . $logicalPathPsr0)) { | |||
return $file; | |||
} | |||
} | |||
} | |||
} | |||
} | |||
// PSR-0 fallback dirs | |||
foreach ($this->fallbackDirsPsr0 as $dir) { | |||
if (file_exists($file = $dir . DIRECTORY_SEPARATOR . $logicalPathPsr0)) { | |||
return $file; | |||
} | |||
} | |||
// PSR-0 include paths. | |||
if ($this->useIncludePath && $file = stream_resolve_include_path($logicalPathPsr0)) { | |||
return $file; | |||
} | |||
} | |||
} | |||
/** | |||
* Scope isolated include. | |||
* | |||
* Prevents access to $this/self from included files. | |||
*/ | |||
function includeFile($file) | |||
{ | |||
include $file; | |||
} |
@@ -0,0 +1,21 @@ | |||
Copyright (c) 2016 Nils Adermann, Jordi Boggiano | |||
Permission is hereby granted, free of charge, to any person obtaining a copy | |||
of this software and associated documentation files (the "Software"), to deal | |||
in the Software without restriction, including without limitation the rights | |||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | |||
copies of the Software, and to permit persons to whom the Software is furnished | |||
to do so, subject to the following conditions: | |||
The above copyright notice and this permission notice shall be included in all | |||
copies or substantial portions of the Software. | |||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | |||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | |||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | |||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | |||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | |||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN | |||
THE SOFTWARE. | |||
@@ -0,0 +1,9 @@ | |||
<?php | |||
// autoload_classmap.php @generated by Composer | |||
$vendorDir = dirname(dirname(__FILE__)); | |||
$baseDir = dirname($vendorDir); | |||
return array( | |||
); |
@@ -0,0 +1,10 @@ | |||
<?php | |||
// autoload_namespaces.php @generated by Composer | |||
$vendorDir = dirname(dirname(__FILE__)); | |||
$baseDir = dirname($vendorDir); | |||
return array( | |||
'Ulrichsg\\' => array($vendorDir . '/ulrichsg/getopt-php/src'), | |||
); |
@@ -0,0 +1,10 @@ | |||
<?php | |||
// autoload_psr4.php @generated by Composer | |||
$vendorDir = dirname(dirname(__FILE__)); | |||
$baseDir = dirname($vendorDir); | |||
return array( | |||
'Picqer\\Barcode\\' => array($vendorDir . '/picqer/php-barcode-generator/src'), | |||
); |
@@ -0,0 +1,45 @@ | |||
<?php | |||
// autoload_real.php @generated by Composer | |||
class ComposerAutoloaderInitf17787d2ecff231b84857fe0d96cbca5 | |||
{ | |||
private static $loader; | |||
public static function loadClassLoader($class) | |||
{ | |||
if ('Composer\Autoload\ClassLoader' === $class) { | |||
require __DIR__ . '/ClassLoader.php'; | |||
} | |||
} | |||
public static function getLoader() | |||
{ | |||
if (null !== self::$loader) { | |||
return self::$loader; | |||
} | |||
spl_autoload_register(array('ComposerAutoloaderInitf17787d2ecff231b84857fe0d96cbca5', 'loadClassLoader'), true, true); | |||
self::$loader = $loader = new \Composer\Autoload\ClassLoader(); | |||
spl_autoload_unregister(array('ComposerAutoloaderInitf17787d2ecff231b84857fe0d96cbca5', 'loadClassLoader')); | |||
$map = require __DIR__ . '/autoload_namespaces.php'; | |||
foreach ($map as $namespace => $path) { | |||
$loader->set($namespace, $path); | |||
} | |||
$map = require __DIR__ . '/autoload_psr4.php'; | |||
foreach ($map as $namespace => $path) { | |||
$loader->setPsr4($namespace, $path); | |||
} | |||
$classMap = require __DIR__ . '/autoload_classmap.php'; | |||
if ($classMap) { | |||
$loader->addClassMap($classMap); | |||
} | |||
$loader->register(true); | |||
return $loader; | |||
} | |||
} |
@@ -0,0 +1,107 @@ | |||
[ | |||
{ | |||
"name": "picqer/php-barcode-generator", | |||
"version": "v0.1", | |||
"version_normalized": "0.1.0.0", | |||
"source": { | |||
"type": "git", | |||
"url": "https://github.com/picqer/php-barcode-generator.git", | |||
"reference": "bd486cfb311989a506c62827fdee463b8a698002" | |||
}, | |||
"dist": { | |||
"type": "zip", | |||
"url": "https://api.github.com/repos/picqer/php-barcode-generator/zipball/bd486cfb311989a506c62827fdee463b8a698002", | |||
"reference": "bd486cfb311989a506c62827fdee463b8a698002", | |||
"shasum": "" | |||
}, | |||
"require": { | |||
"php": ">=5.4.0" | |||
}, | |||
"time": "2015-08-13 07:59:44", | |||
"type": "library", | |||
"installation-source": "dist", | |||
"autoload": { | |||
"psr-4": { | |||
"Picqer\\Barcode\\": "src" | |||
} | |||
}, | |||
"notification-url": "https://packagist.org/downloads/", | |||
"license": [ | |||
"MIT" | |||
], | |||
"authors": [ | |||
{ | |||
"name": "Casper Bakker", | |||
"email": "info@picqer.com" | |||
} | |||
], | |||
"description": "An easy to use, non-bloated, barcode generator in PHP. Creates SVG, PNG, JPG and HTML images from the most used 1D barcode standards.", | |||
"homepage": "http://github.com/picqer/exact-php-client", | |||
"keywords": [ | |||
"CODABAR", | |||
"Code11", | |||
"Code93", | |||
"EAN13", | |||
"KIX", | |||
"KIXCODE", | |||
"MSI", | |||
"POSTNET", | |||
"Pharma", | |||
"Standard 2 of 5", | |||
"barcode", | |||
"barcode generator", | |||
"code128", | |||
"code39", | |||
"ean", | |||
"html", | |||
"jpeg", | |||
"jpg", | |||
"php", | |||
"png", | |||
"svg", | |||
"upc" | |||
] | |||
}, | |||
{ | |||
"name": "ulrichsg/getopt-php", | |||
"version": "2.3.0", | |||
"version_normalized": "2.3.0.0", | |||
"source": { | |||
"type": "git", | |||
"url": "https://github.com/ulrichsg/getopt-php.git", | |||
"reference": "a51554a16e206a6642bf1a0d7d1e4378ec2ba980" | |||
}, | |||
"dist": { | |||
"type": "zip", | |||
"url": "https://api.github.com/repos/ulrichsg/getopt-php/zipball/a51554a16e206a6642bf1a0d7d1e4378ec2ba980", | |||
"reference": "a51554a16e206a6642bf1a0d7d1e4378ec2ba980", | |||
"shasum": "" | |||
}, | |||
"require": { | |||
"php": ">=5.3.0" | |||
}, | |||
"require-dev": { | |||
"phpunit/phpunit": "3.7.*" | |||
}, | |||
"time": "2015-03-28 14:09:20", | |||
"type": "library", | |||
"installation-source": "dist", | |||
"autoload": { | |||
"psr-0": { | |||
"Ulrichsg\\": "src" | |||
} | |||
}, | |||
"notification-url": "https://packagist.org/downloads/", | |||
"license": [ | |||
"MIT" | |||
], | |||
"authors": [ | |||
{ | |||
"name": "Ulrich Schmidt-Goertz", | |||
"email": "ulrich@schmidt-goertz.de" | |||
} | |||
], | |||
"description": "Command line arguments parser for PHP 5.3", | |||
"homepage": "http://ulrichsg.github.io/getopt-php" | |||
} | |||
] |
@@ -0,0 +1,2 @@ | |||
.idea | |||
.DS_Store |
@@ -0,0 +1,76 @@ | |||
# PHP Barcode Generator | |||
This is an easy to use, non-bloated, framework independent, barcode generator in PHP. | |||
It creates SVG, PNG, JPG and HTML images, from the most used 1D barcode standards. | |||
*The codebase is largely from the TCPDF barcode generator. It is still a bit of a mess, bit I will clean it in the future. I do not expect the interface of this class will change during the clean ups.* | |||
## Installation | |||
Install through [composer](https://getcomposer.org/doc/00-intro.md): | |||
``` | |||
composer require picqer/php-barcode-generator | |||
``` | |||
## Usage | |||
Initiate the barcode generator for the output you want, then call the ->getBarcode() routine as many times as you want. | |||
```php | |||
$generator = new Picqer\Barcode\BarcodeGeneratorHTML(); | |||
echo $generator->getBarcode('081231723897', $generator::TYPE_CODE_128); | |||
``` | |||
The ->getBarcode() routine accepts the following: | |||
- $code Data for the barcode | |||
- $type Type of barcode, use the constants defined in the class | |||
- $widthFactor Width is based on the length of the data, with this factor you can make the barcode bars wider then default | |||
- $totalHeight The total height of the barcode | |||
- $color Hex code of the foreground color | |||
## Image types | |||
```php | |||
$generatorSVG = new Picqer\Barcode\BarcodeGeneratorSVG(); | |||
$generatorPNG = new Picqer\Barcode\BarcodeGeneratorPNG(); | |||
$generatorJPG = new Picqer\Barcode\BarcodeGeneratorJPG(); | |||
$generatorHTML = new Picqer\Barcode\BarcodeGeneratorHTML(); | |||
``` | |||
## Accepted types | |||
- 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 | |||
## Examples | |||
Embedded PNG image in HTML: | |||
```php | |||
$generator = new Picqer\Barcode\BarcodeGeneratorPNG(); | |||
echo '<img src="data:image/png;base64,' . base64_encode($generator->getBarcode('081231723897', $generator::TYPE_CODE_128)) . '">'; | |||
``` |
@@ -0,0 +1,22 @@ | |||
{ | |||
"name": "picqer/php-barcode-generator", | |||
"type": "library", | |||
"description": "An easy to use, non-bloated, barcode generator in PHP. Creates SVG, PNG, JPG and HTML images from the most used 1D barcode standards.", | |||
"keywords": [ "php", "barcode", "barcode generator", "EAN", "EAN13", "UPC", "Code39", "Code128", "Code93", "Standard 2 of 5", "MSI", "POSTNET", "KIX", "KIXCODE", "CODABAR", "PHARMA", "Code11", "SVG", "PNG", "HTML", "JPG", "JPEG" ], | |||
"homepage": "http://github.com/picqer/exact-php-client", | |||
"license": "MIT", | |||
"authors": [ | |||
{ | |||
"name": "Casper Bakker", | |||
"email": "info@picqer.com" | |||
} | |||
], | |||
"require": { | |||
"php": ">=5.4.0" | |||
}, | |||
"autoload": { | |||
"psr-4": { | |||
"Picqer\\Barcode\\": "src" | |||
} | |||
} | |||
} |
@@ -0,0 +1,14 @@ | |||
<?php | |||
include('src/BarcodeGenerator.php'); | |||
include('src/BarcodeGeneratorPNG.php'); | |||
include('src/BarcodeGeneratorSVG.php'); | |||
include('src/BarcodeGeneratorHTML.php'); | |||
$generatorPNG = new Picqer\Barcode\BarcodeGeneratorPNG(); | |||
$generatorSVG = new Picqer\Barcode\BarcodeGeneratorSVG(); | |||
$generatorHTML = new Picqer\Barcode\BarcodeGeneratorHTML(); | |||
echo $generatorHTML->getBarcode('081231723897', $generatorPNG::TYPE_CODE_128); | |||
echo $generatorSVG->getBarcode('081231723897', $generatorPNG::TYPE_EAN_13); | |||
echo '<img src="data:image/png;base64,' . base64_encode($generatorPNG->getBarcode('081231723897', $generatorPNG::TYPE_CODE_128)) . '">'; |
@@ -0,0 +1,44 @@ | |||
<?php | |||
namespace Picqer\Barcode; | |||
class BarcodeGeneratorHTML extends BarcodeGenerator | |||
{ | |||
/** | |||
* Return an HTML representation of barcode. | |||
* | |||
* @param string $code code to print | |||
* @param string $type type of barcode | |||
* @param int $widthFactor Width of a single bar element in pixels. | |||
* @param int $totalHeight Height of a single bar element in pixels. | |||
* @param int $color Foreground color for bar elements (background is transparent). | |||
* @return string HTML code. | |||
* @public | |||
*/ | |||
public function getBarcode($code, $type, $widthFactor = 2, $totalHeight = 30, $color = 'black') | |||
{ | |||
$barcodeData = $this->getBarcodeData($code, $type); | |||
$html = '<div style="font-size:0;position:relative;width:' . ($barcodeData['maxWidth'] * $widthFactor) . 'px;height:' . ($totalHeight) . 'px;">' . "\n"; | |||
$positionHorizontal = 0; | |||
foreach ($barcodeData['bars'] as $bar) { | |||
$barWidth = round(($bar['width'] * $widthFactor), 3); | |||
$barHeight = round(($bar['height'] * $totalHeight / $barcodeData['maxHeight']), 3); | |||
if ($bar['drawBar']) { | |||
$positionVertical = round(($bar['positionVertical'] * $totalHeight / $barcodeData['maxHeight']), 3); | |||
// draw a vertical bar | |||
$html .= '<div style="background-color:' . $color . ';width:' . $barWidth . 'px;height:' . $barHeight . 'px;position:absolute;left:' . $positionHorizontal . 'px;top:' . $positionVertical . 'px;"> </div>' . "\n"; | |||
} | |||
$positionHorizontal += $barWidth; | |||
} | |||
$html .= '</div>' . "\n"; | |||
return $html; | |||
} | |||
} |
@@ -0,0 +1,74 @@ | |||
<?php | |||
namespace Picqer\Barcode; | |||
class BarcodeGeneratorJPG extends BarcodeGenerator | |||
{ | |||
/** | |||
* Return a JPG image representation of barcode (requires GD or Imagick library). | |||
* | |||
* @param string $code code to print | |||
* @param string $type type of barcode: | |||
* @param int $widthFactor Width of a single bar element in pixels. | |||
* @param int $totalHeight Height of a single bar element in pixels. | |||
* @param array $color RGB (0-255) foreground color for bar elements (background is transparent). | |||
* @return string image data or false in case of error. | |||
* @public | |||
*/ | |||
public function getBarcode($code, $type, $widthFactor = 2, $totalHeight = 30, $color = array(0, 0, 0)) | |||
{ | |||
$barcodeData = $this->getBarcodeData($code, $type); | |||
// calculate image size | |||
$width = ($barcodeData['maxWidth'] * $widthFactor); | |||
$height = $totalHeight; | |||
if (function_exists('imagecreate')) { | |||
// GD library | |||
$imagick = false; | |||
$jpg = imagecreate($width, $height); | |||
$colorBackground = imagecolorallocate($jpg, 255, 255, 255); | |||
imagecolortransparent($jpg, $colorBackground); | |||
$colorForeground = imagecolorallocate($jpg, $color[0], $color[1], $color[2]); | |||
} elseif (extension_loaded('imagick')) { | |||
$imagick = true; | |||
$colorForeground = new \imagickpixel('rgb(' . $color[0] . ',' . $color[1] . ',' . $color[2] . ')'); | |||
$jpg = new \Imagick(); | |||
$jpg->newImage($width, $height, 'none', 'jpg'); | |||
$imageMagickObject = new \imagickdraw(); | |||
$imageMagickObject->setfillcolor($colorForeground); | |||
} else { | |||
return false; | |||
} | |||
// print bars | |||
$positionHorizontal = 0; | |||
foreach ($barcodeData['bars'] as $bar) { | |||
$bw = round(($bar['width'] * $widthFactor), 3); | |||
$bh = round(($bar['height'] * $totalHeight / $barcodeData['maxHeight']), 3); | |||
if ($bar['drawBar']) { | |||
$y = round(($bar['positionVertical'] * $totalHeight / $barcodeData['maxHeight']), 3); | |||
// draw a vertical bar | |||
if ($imagick) { | |||
$imageMagickObject->rectangle($positionHorizontal, $y, ($positionHorizontal + $bw), ($y + $bh)); | |||
} else { | |||
imagefilledrectangle($jpg, $positionHorizontal, $y, ($positionHorizontal + $bw) - 1, ($y + $bh), | |||
$colorForeground); | |||
} | |||
} | |||
$positionHorizontal += $bw; | |||
} | |||
ob_start(); | |||
if ($imagick) { | |||
$jpg->drawimage($imageMagickObject); | |||
echo $jpg; | |||
} else { | |||
imagejpeg($jpg); | |||
imagedestroy($jpg); | |||
} | |||
$image = ob_get_clean(); | |||
return $image; | |||
} | |||
} |
@@ -0,0 +1,74 @@ | |||
<?php | |||
namespace Picqer\Barcode; | |||
class BarcodeGeneratorPNG extends BarcodeGenerator | |||
{ | |||
/** | |||
* Return a PNG image representation of barcode (requires GD or Imagick library). | |||
* | |||
* @param string $code code to print | |||
* @param string $type type of barcode: | |||
* @param int $widthFactor Width of a single bar element in pixels. | |||
* @param int $totalHeight Height of a single bar element in pixels. | |||
* @param array $color RGB (0-255) foreground color for bar elements (background is transparent). | |||
* @return string image data or false in case of error. | |||
* @public | |||
*/ | |||
public function getBarcode($code, $type, $widthFactor = 2, $totalHeight = 30, $color = array(0, 0, 0)) | |||
{ | |||
$barcodeData = $this->getBarcodeData($code, $type); | |||
// calculate image size | |||
$width = ($barcodeData['maxWidth'] * $widthFactor); | |||
$height = $totalHeight; | |||
if (function_exists('imagecreate')) { | |||
// GD library | |||
$imagick = false; | |||
$png = imagecreate($width, $height); | |||
$colorBackground = imagecolorallocate($png, 255, 255, 255); | |||
imagecolortransparent($png, $colorBackground); | |||
$colorForeground = imagecolorallocate($png, $color[0], $color[1], $color[2]); | |||
} elseif (extension_loaded('imagick')) { | |||
$imagick = true; | |||
$colorForeground = new \imagickpixel('rgb(' . $color[0] . ',' . $color[1] . ',' . $color[2] . ')'); | |||
$png = new \Imagick(); | |||
$png->newImage($width, $height, 'none', 'png'); | |||
$imageMagickObject = new \imagickdraw(); | |||
$imageMagickObject->setfillcolor($colorForeground); | |||
} else { | |||
return false; | |||
} | |||
// print bars | |||
$positionHorizontal = 0; | |||
foreach ($barcodeData['bars'] as $bar) { | |||
$bw = round(($bar['width'] * $widthFactor), 3); | |||
$bh = round(($bar['height'] * $totalHeight / $barcodeData['maxHeight']), 3); | |||
if ($bar['drawBar']) { | |||
$y = round(($bar['positionVertical'] * $totalHeight / $barcodeData['maxHeight']), 3); | |||
// draw a vertical bar | |||
if ($imagick) { | |||
$imageMagickObject->rectangle($positionHorizontal, $y, ($positionHorizontal + $bw), ($y + $bh)); | |||
} else { | |||
imagefilledrectangle($png, $positionHorizontal, $y, ($positionHorizontal + $bw) - 1, ($y + $bh), | |||
$colorForeground); | |||
} | |||
} | |||
$positionHorizontal += $bw; | |||
} | |||
ob_start(); | |||
if ($imagick) { | |||
$png->drawimage($imageMagickObject); | |||
echo $png; | |||
} else { | |||
imagepng($png); | |||
imagedestroy($png); | |||
} | |||
$image = ob_get_clean(); | |||
return $image; | |||
} | |||
} |
@@ -0,0 +1,49 @@ | |||
<?php | |||
namespace Picqer\Barcode; | |||
class BarcodeGeneratorSVG extends BarcodeGenerator | |||
{ | |||
/** | |||
* Return a SVG string representation of barcode. | |||
* | |||
* @param $code (string) code to print | |||
* @param $type (const) type of barcode | |||
* @param $widthFactor (int) Minimum width of a single bar in user units. | |||
* @param $totalHeight (int) Height of barcode in user units. | |||
* @param $color (string) Foreground color (in SVG format) for bar elements (background is transparent). | |||
* @return string SVG code. | |||
* @public | |||
*/ | |||
public function getBarcode($code, $type, $widthFactor = 2, $totalHeight = 30, $color = 'black') | |||
{ | |||
$barcodeData = $this->getBarcodeData($code, $type); | |||
// replace table for special characters | |||
$repstr = array("\0" => '', '&' => '&', '<' => '<', '>' => '>'); | |||
$svg = '<?xml version="1.0" standalone="no" ?>' . "\n"; | |||
$svg .= '<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">' . "\n"; | |||
$svg .= '<svg width="' . round(($barcodeData['maxWidth'] * $widthFactor), | |||
3) . '" height="' . $totalHeight . '" version="1.1" xmlns="http://www.w3.org/2000/svg">' . "\n"; | |||
$svg .= "\t" . '<desc>' . strtr($barcodeData['code'], $repstr) . '</desc>' . "\n"; | |||
$svg .= "\t" . '<g id="bars" fill="' . $color . '" stroke="none">' . "\n"; | |||
// print bars | |||
$positionHorizontal = 0; | |||
foreach ($barcodeData['bars'] as $bar) { | |||
$barWidth = round(($bar['width'] * $widthFactor), 3); | |||
$barHeight = round(($bar['height'] * $totalHeight / $barcodeData['maxHeight']), 3); | |||
if ($bar['drawBar']) { | |||
$positionVertical = round(($bar['positionVertical'] * $totalHeight / $barcodeData['maxHeight']), 3); | |||
// draw a vertical bar | |||
$svg .= "\t\t" . '<rect x="' . $positionHorizontal . '" y="' . $positionVertical . '" width="' . $barWidth . '" height="' . $barHeight . '" />' . "\n"; | |||
} | |||
$positionHorizontal += $barWidth; | |||
} | |||
$svg .= "\t" . '</g>' . "\n"; | |||
$svg .= '</svg>' . "\n"; | |||
return $svg; | |||
} | |||
} |
@@ -0,0 +1,6 @@ | |||
bin | |||
build | |||
composer.lock | |||
vendor | |||
nbproject | |||
_site |
@@ -0,0 +1,10 @@ | |||
language: php | |||
php: | |||
- 5.6 | |||
- 5.5 | |||
- 5.4 | |||
- 5.3 | |||
- hhvm | |||
before_script: | |||
- composer install |
@@ -0,0 +1,77 @@ | |||
## 2.3.0 (2015-03-28) | |||
Features: | |||
* Optional argument descriptions (courtesy of @sabl0r) | |||
Bugfixes: | |||
* Passing a single hyphen as an option value works now (courtesy of @tistre) | |||
## 2.2.0 (2014-09-13) | |||
Features: | |||
* Added method to customize the help message (courtesy of @mfn) | |||
* Option now has a static create method for call chaining in PHP 5.3 (courtesy of @kamermans) | |||
## 2.1.0 (2014-02-28) | |||
Features: | |||
* Added setters for default values and validation to Option | |||
## 2.0.0 (2014-01-30) | |||
Features: | |||
* Argument validation (courtesy of @jochenvdv) | |||
## 2.0.0-RC.1 (2014-01-17) | |||
Changes: | |||
* Namespace is now Ulrichsg\Getopt | |||
* Public API has been cleaned up, please refer to the documentation | |||
## 1.4.1 (2013-12-13) | |||
Bugfixes: | |||
* Long options are required to be longer than 1 character | |||
* Passing duplicate option names to the constructor is forbidden by default | |||
## 1.4.0 (2013-12-13) | |||
Features: | |||
* Options can be numeric (courtesy of @patinthehat) | |||
* Additional convenience methods for working with operands (ditto) | |||
## 1.3.0 (2013-12-07) | |||
Features: | |||
* Default values for options | |||
* ArrayAccess, Countable and Traversable support | |||
* Can set program name to enhance help message (courtesy of @misterion) | |||
## 1.2.0 (2013-11-14) | |||
Features: | |||
* Allow passing incomplete option arrays | |||
## 1.1.0 (2013-06-19) | |||
Features: | |||
* Added help text printing functionality | |||
Bugfixes: | |||
* Fixed passing a mandatory argument to the last in a sequence of collapsed short options | |||
## 1.0.1 (2012-05-20) | |||
Bugfixes: | |||
* Fixed bug where '0' could not be passed as an option value | |||
@@ -0,0 +1,17 @@ | |||
Copyright (c) 2011-2014 Ulrich Schmidt-Goertz <ulrich at schmidt-goertz.de> | |||
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. |
@@ -0,0 +1,35 @@ | |||
# vim: tabstop=4:softtabstop=4:shiftwidth=4:noexpandtab | |||
help: | |||
@echo "Usual targets:" | |||
@echo " test - run test suites" | |||
@echo "" | |||
@echo "Other targets:" | |||
@echo " install-composer - install composer" | |||
@echo " install-dependencies - install/update all vendor libraries using composer" | |||
@echo " install-dev-dependencies - install/update all vendor libraries necessary for development" | |||
@echo "" | |||
@exit 0 | |||
test: | |||
@vendor/bin/phpunit | |||
install-composer: | |||
@if [ ! -d ./bin ]; then mkdir bin; fi | |||
@if [ ! -f ./bin/composer.phar ]; then curl -s http://getcomposer.org/installer | php -n -d allow_url_fopen=1 -d date.timezone="Europe/Berlin" -- --install-dir=./bin/; fi | |||
install-dependencies: | |||
@make install-composer | |||
@php -n -d allow_url_fopen=1 -d date.timezone="Europe/Berlin" ./bin/composer.phar -- update | |||
install-dev-dependencies: | |||
@make install-composer | |||
@php -n -d allow_url_fopen=1 -d date.timezone="Europe/Berlin" ./bin/composer.phar update --dev | |||
.PHONY: test help | |||
@@ -0,0 +1,28 @@ | |||
Getopt.PHP | |||
========== | |||
Getopt.PHP is a library for command-line argument processing. It supports PHP version 5.3 and above. | |||
Features | |||
-------- | |||
* Supports both short (eg. `-v`) and long (eg. `--version`) options | |||
* Option aliasing, ie. an option can have both a long and a short version | |||
* Collapsed short options (eg. `-abc` instead of `-a -b -c`) | |||
* Cumulative options (eg. `-vvv`) | |||
* Options may take optional or mandatory arguments | |||
* Two alternative notations for long options with arguments: `--option value` and `--option=value` | |||
* Collapsed short options with mandatory argument at the end (eg. `-ab 1` instead of `-a -b 1`) | |||
Documentation | |||
------------- | |||
* [Documentation for the current version (2.0+)](http://ulrichsg.github.io/getopt-php/) | |||
* [Legacy documentation (1.4)](https://github.com/ulrichsg/getopt-php/blob/2aa8ab1be57200af4cc51447d2a6c244b75ca70b/README.markdown) | |||
License | |||
------- | |||
Getopt.PHP is published under the [MIT License](http://www.opensource.org/licenses/mit-license.php). | |||
[](https://travis-ci.org/ulrichsg/getopt-php) |
@@ -0,0 +1,24 @@ | |||
{ | |||
"name": "ulrichsg/getopt-php", | |||
"type": "library", | |||
"description": "Command line arguments parser for PHP 5.3", | |||
"homepage": "http://ulrichsg.github.io/getopt-php", | |||
"license": "MIT", | |||
"authors": [ | |||
{ | |||
"name": "Ulrich Schmidt-Goertz", | |||
"email": "ulrich@schmidt-goertz.de" | |||
} | |||
], | |||
"require": { | |||
"php": ">=5.3.0" | |||
}, | |||
"require-dev": { | |||
"phpunit/phpunit": "3.7.*" | |||
}, | |||
"autoload": { | |||
"psr-0": { | |||
"Ulrichsg\\": "src" | |||
} | |||
} | |||
} |
@@ -0,0 +1,35 @@ | |||
<?xml version="1.0" encoding="UTF-8"?> | |||
<phpunit | |||
bootstrap="vendor/autoload.php" | |||
colors="true" | |||
convertErrorsToExceptions="true" | |||
convertNoticesToExceptions="true" | |||
convertWarningsToExceptions="true" | |||
stopOnFailure="true" | |||
syntaxCheck="true" | |||
> | |||
<testsuites> | |||
<testsuite name="basic"> | |||
<directory>test</directory> | |||
</testsuite> | |||
</testsuites> | |||
<filter> | |||
<whitelist> | |||
<directory suffix=".php">src</directory> | |||
</whitelist> | |||
</filter> | |||
<logging> | |||
<log type="coverage-html" | |||
target="build/coverage" | |||
charset="UTF-8" | |||
yui="true" | |||
highlight="true" | |||
lowUpperBound="40" | |||
highLowerBound="70" | |||
/> | |||
</logging> | |||
</phpunit> |
@@ -0,0 +1,115 @@ | |||
<?php | |||
namespace Ulrichsg\Getopt; | |||
class Argument | |||
{ | |||
/** @var string */ | |||
private $default; | |||
/** @var callable */ | |||
private $validation; | |||
/** @var string */ | |||
private $name; | |||
/** | |||
* Creates a new argument. | |||
* | |||
* @param scalar|null $default Default value or NULL | |||
* @param callable|null $validation a validation function (optional) | |||
* @throws \InvalidArgumentException | |||
*/ | |||
public function __construct($default = null, $validation = null, $name = "arg") | |||
{ | |||
if (!is_null($default)) { | |||
$this->setDefaultValue($default); | |||
} | |||
if (!is_null($validation)) { | |||
$this->setValidation($validation); | |||
} | |||
$this->name = $name; | |||
} | |||
/** | |||
* Set the default value | |||
* | |||
* @param scalar $value | |||
* @return Argument this object (for chaining calls) | |||
* @throws \InvalidArgumentException | |||
*/ | |||
public function setDefaultValue($value) | |||
{ | |||
if (!is_scalar($value)) { | |||
throw new \InvalidArgumentException("Default value must be scalar"); | |||
} | |||
$this->default = $value; | |||
return $this; | |||
} | |||
/** | |||
* Set a validation function. | |||
* The function must take a string and return true if it is valid, false otherwise. | |||
* | |||
* @param callable $callable | |||
* @return Argument this object (for chaining calls) | |||
* @throws \InvalidArgumentException | |||
*/ | |||
public function setValidation($callable) | |||
{ | |||
if (!is_callable($callable)) { | |||
throw new \InvalidArgumentException("Validation must be a callable"); | |||
} | |||
$this->validation = $callable; | |||
return $this; | |||
} | |||
/** | |||
* Check if an argument validates according to the specification. | |||
* | |||
* @param string $arg | |||
* @return bool | |||
*/ | |||
public function validates($arg) | |||
{ | |||
return (bool)call_user_func($this->validation, $arg); | |||
} | |||
/** | |||
* Check if the argument has a validation function | |||
* | |||
* @return bool | |||
*/ | |||
public function hasValidation() | |||
{ | |||
return isset($this->validation); | |||
} | |||
/** | |||
* Check whether the argument has a default value | |||
* | |||
* @return boolean | |||
*/ | |||
public function hasDefaultValue() | |||
{ | |||
return !empty($this->default); | |||
} | |||
/** | |||
* Retrieve the default value | |||
* | |||
* @return scalar|null | |||
*/ | |||
public function getDefaultValue() | |||
{ | |||
return $this->default; | |||
} | |||
/** | |||
* Retrieve the argument name | |||
* | |||
* @return string | |||
*/ | |||
public function getName() | |||
{ | |||
return $this->name; | |||
} | |||
} |
@@ -0,0 +1,233 @@ | |||
<?php | |||
namespace Ulrichsg\Getopt; | |||
/** | |||
* Parses command line arguments according to a list of allowed options. | |||
*/ | |||
class CommandLineParser | |||
{ | |||
/** @var Option[] */ | |||
private $optionList; | |||
private $options = array(); | |||
private $operands = array(); | |||
/** | |||
* Creates a new instance. | |||
* | |||
* @param Option[] $optionList the list of allowed options | |||
*/ | |||
public function __construct(array $optionList) | |||
{ | |||
$this->optionList = $optionList; | |||
} | |||
/** | |||
* Parses the given arguments and converts them into options and operands. | |||
* | |||
* @param mixed $arguments a string or an array with one argument per element | |||
*/ | |||
public function parse($arguments) | |||
{ | |||
if (!is_array($arguments)) { | |||
$arguments = explode(' ', $arguments); | |||
} | |||
$operands = array(); | |||
$numArgs = count($arguments); | |||
for ($i = 0; $i < $numArgs; ++$i) { | |||
$arg = trim($arguments[$i]); | |||
if (empty($arg)) { | |||
continue; | |||
} | |||
if (($arg === '--') || ($arg === '-') || (mb_substr($arg, 0, 1) !== '-')){ | |||
// no more options, treat the remaining arguments as operands | |||
$firstOperandIndex = ($arg == '--') ? $i + 1 : $i; | |||
$operands = array_slice($arguments, $firstOperandIndex); | |||
break; | |||
} | |||
if (mb_substr($arg, 0, 2) == '--') { | |||
$this->addLongOption($arguments, $i); | |||
} else { | |||
$this->addShortOption($arguments, $i); | |||
} | |||
} // endfor | |||
$this->addDefaultValues(); | |||
// remove '--' from operands array | |||
foreach ($operands as $operand) { | |||
if ($operand !== '--') { | |||
$this->operands[] = $operand; | |||
} | |||
} | |||
} | |||
/** | |||
* Returns the options created by a previous invocation of parse(). | |||
* | |||
* @return array | |||
*/ | |||
public function getOptions() | |||
{ | |||
return $this->options; | |||
} | |||
/** | |||
* Returns the operands created by a previous invocation of parse(), | |||
* | |||
* @return array | |||
*/ | |||
public function getOperands() | |||
{ | |||
return $this->operands; | |||
} | |||
private function addShortOption($arguments, &$i) | |||
{ | |||
$numArgs = count($arguments); | |||
$option = mb_substr($arguments[$i], 1); | |||
if (mb_strlen($option) > 1) { | |||
// multiple options strung together | |||
$options = $this->splitString($option, 1); | |||
foreach ($options as $j => $ch) { | |||
if ($j < count($options) - 1 | |||
|| !( | |||
$i < $numArgs - 1 | |||
&& ((mb_substr($arguments[$i + 1], 0, 1) !== '-') || ($arguments[$i + 1] === '-')) | |||
&& $this->optionHasArgument($ch) | |||
) | |||
) { | |||
$this->addOption($ch, null); | |||
} else { // e.g. `ls -sw 100` | |||
$value = $arguments[$i + 1]; | |||
++$i; | |||
$this->addOption($ch, $value); | |||
} | |||
} | |||
} else { | |||
if ($i < $numArgs - 1 | |||
&& ((mb_substr($arguments[$i + 1], 0, 1) !== '-') || ($arguments[$i + 1] === '-')) | |||
&& $this->optionHasArgument($option) | |||
) { | |||
$value = $arguments[$i + 1]; | |||
++$i; | |||
} else { | |||
$value = null; | |||
} | |||
$this->addOption($option, $value); | |||
} | |||
} | |||
private function addLongOption($arguments, &$i) | |||
{ | |||
$option = mb_substr($arguments[$i], 2); | |||
if (strpos($option, '=') === false) { | |||
if ($i < count($arguments) - 1 | |||
&& ((mb_substr($arguments[$i + 1], 0, 1) !== '-') || ($arguments[$i + 1] === '-')) | |||
&& $this->optionHasArgument($option) | |||
) { | |||
$value = $arguments[$i + 1]; | |||
++$i; | |||
} else { | |||
$value = null; | |||
} | |||
} else { | |||
list($option, $value) = explode('=', $option, 2); | |||
} | |||
$this->addOption($option, $value); | |||
} | |||
/** | |||
* Add an option to the list of known options. | |||
* | |||
* @param string $string the option's name | |||
* @param string $value the option's value (or null) | |||
* @throws \UnexpectedValueException | |||
* @return void | |||
*/ | |||
private function addOption($string, $value) | |||
{ | |||
foreach ($this->optionList as $option) { | |||
if ($option->matches($string)) { | |||
if ($option->mode() == Getopt::REQUIRED_ARGUMENT && !mb_strlen($value)) { | |||
throw new \UnexpectedValueException("Option '$string' must have a value"); | |||
} | |||
if ($option->getArgument()->hasValidation()) { | |||
if ((mb_strlen($value) > 0) && !$option->getArgument()->validates($value)) { | |||
throw new \UnexpectedValueException("Option '$string' has an invalid value"); | |||
} | |||
} | |||
// for no-argument options, check if they are duplicate | |||
if ($option->mode() == Getopt::NO_ARGUMENT) { | |||
$oldValue = isset($this->options[$string]) ? $this->options[$string] : null; | |||
$value = is_null($oldValue) ? 1 : $oldValue + 1; | |||
} | |||
// for optional-argument options, set value to 1 if none was given | |||
$value = (mb_strlen($value) > 0) ? $value : 1; | |||
// add both long and short names (if they exist) to the option array to facilitate lookup | |||
if ($option->short()) { | |||
$this->options[$option->short()] = $value; | |||
} | |||
if ($option->long()) { | |||
$this->options[$option->long()] = $value; | |||
} | |||
return; | |||
} | |||
} | |||
throw new \UnexpectedValueException("Option '$string' is unknown"); | |||
} | |||
/** | |||
* If there are options with default values that were not overridden by the parsed option string, | |||
* add them to the list of known options. | |||
*/ | |||
private function addDefaultValues() | |||
{ | |||
foreach ($this->optionList as $option) { | |||
if ($option->getArgument()->hasDefaultValue() | |||
&& !isset($this->options[$option->short()]) | |||
&& !isset($this->options[$option->long()]) | |||
) { | |||
if ($option->short()) { | |||
$this->addOption($option->short(), $option->getArgument()->getDefaultValue()); | |||
} | |||
if ($option->long()) { | |||
$this->addOption($option->long(), $option->getArgument()->getDefaultValue()); | |||
} | |||
} | |||
} | |||
} | |||
/** | |||
* Return true if the given option can take an argument, false if it can't or is unknown. | |||
* | |||
* @param string $name the option's name | |||
* @return boolean | |||
*/ | |||
private function optionHasArgument($name) | |||
{ | |||
foreach ($this->optionList as $option) { | |||
if ($option->matches($name)) { | |||
return $option->mode() != Getopt::NO_ARGUMENT; | |||
} | |||
} | |||
return false; | |||
} | |||
/** | |||
* Split the string into individual characters, | |||
* | |||
* @param string $string string to split | |||
* @return array | |||
*/ | |||
private function splitString($string) | |||
{ | |||
$result = array(); | |||
for ($i = 0; $i < mb_strlen($string, "UTF-8"); ++$i) { | |||
$result[] = mb_substr($string, $i, 1, "UTF-8"); | |||
} | |||
return $result; | |||
} | |||
} |
@@ -0,0 +1,295 @@ | |||
<?php | |||
namespace Ulrichsg\Getopt; | |||
/** | |||
* Getopt.PHP allows for easy processing of command-line arguments. | |||
* It is a more powerful, object-oriented alternative to PHP's built-in getopt() function. | |||
* | |||
* @version 2.1.0 | |||
* @license MIT | |||
* @link http://ulrichsg.github.io/getopt-php | |||
*/ | |||
class Getopt implements \Countable, \ArrayAccess, \IteratorAggregate | |||
{ | |||
const NO_ARGUMENT = 0; | |||
const REQUIRED_ARGUMENT = 1; | |||
const OPTIONAL_ARGUMENT = 2; | |||
/** @var OptionParser */ | |||
private $optionParser; | |||
/** @var string */ | |||
private $scriptName; | |||
/** @var Option[] */ | |||
private $optionList = array(); | |||
/** @var array */ | |||
private $options = array(); | |||
/** @var array */ | |||
private $operands = array(); | |||
/** @var string */ | |||
private $banner = "Usage: %s [options] [operands]\n"; | |||
/** | |||
* Creates a new Getopt object. | |||
* | |||
* The argument $options can be either a string in the format accepted by the PHP library | |||
* function getopt() or an array. | |||
* | |||
* @param mixed $options Array of options, a String, or null (see documentation for details) | |||
* @param int $defaultType The default option type to use when omitted (optional) | |||
* @throws \InvalidArgumentException | |||
* | |||
* @link https://www.gnu.org/s/hello/manual/libc/Getopt.html GNU Getopt manual | |||
*/ | |||
public function __construct($options = null, $defaultType = Getopt::NO_ARGUMENT) | |||
{ | |||
$this->optionParser = new OptionParser($defaultType); | |||
if ($options !== null) { | |||
$this->addOptions($options); | |||
} | |||
} | |||
/** | |||
* Extends the list of known options. Takes the same argument types as the constructor. | |||
* | |||
* @param mixed $options | |||
* @throws \InvalidArgumentException | |||
*/ | |||
public function addOptions($options) | |||
{ | |||
if (is_string($options)) { | |||
$this->mergeOptions($this->optionParser->parseString($options)); | |||
} elseif (is_array($options)) { | |||
$this->mergeOptions($this->optionParser->parseArray($options)); | |||
} else { | |||
throw new \InvalidArgumentException("Getopt(): argument must be string or array"); | |||
} | |||
} | |||
/** | |||
* Merges new options with the ones already in the Getopt optionList, making sure the resulting list is free of | |||
* conflicts. | |||
* | |||
* @param Option[] $options The list of new options | |||
* @throws \InvalidArgumentException | |||
*/ | |||
private function mergeOptions(array $options) | |||
{ | |||
/** @var Option[] $mergedList */ | |||
$mergedList = array_merge($this->optionList, $options); | |||
$duplicates = array(); | |||
foreach ($mergedList as $option) { | |||
foreach ($mergedList as $otherOption) { | |||
if (($option === $otherOption) || in_array($otherOption, $duplicates)) { | |||
continue; | |||
} | |||
if ($this->optionsConflict($option, $otherOption)) { | |||
throw new \InvalidArgumentException('Failed to add options due to conflict'); | |||
} | |||
if (($option->short() === $otherOption->short()) && ($option->long() === $otherOption->long())) { | |||
$duplicates[] = $option; | |||
} | |||
} | |||
} | |||
foreach ($mergedList as $index => $option) { | |||
if (in_array($option, $duplicates)) { | |||
unset($mergedList[$index]); | |||
} | |||
} | |||
$this->optionList = array_values($mergedList); | |||
} | |||
private function optionsConflict(Option $option1, Option $option2) { | |||
if ((is_null($option1->short()) && is_null($option2->short())) | |||
|| (is_null($option1->long()) && is_null($option2->long()))) { | |||
return false; | |||
} | |||
return ((($option1->short() === $option2->short()) && ($option1->long() !== $option2->long())) | |||
|| (($option1->short() !== $option2->short()) && ($option1->long() === $option2->long()))); | |||
} | |||
/** | |||
* Evaluate the given arguments. These can be passed either as a string or as an array. | |||
* If nothing is passed, the running script's command line arguments are used. | |||
* | |||
* An {@link \UnexpectedValueException} or {@link \InvalidArgumentException} is thrown | |||
* when the arguments are not well-formed or do not conform to the options passed by the user. | |||
* | |||
* @param mixed $arguments optional ARGV array or space separated string | |||
*/ | |||
public function parse($arguments = null) | |||
{ | |||
$this->options = array(); | |||
if (!isset($arguments)) { | |||
global $argv; | |||
$arguments = $argv; | |||
$this->scriptName = array_shift($arguments); // $argv[0] is the script's name | |||
} elseif (is_string($arguments)) { | |||
$this->scriptName = $_SERVER['PHP_SELF']; | |||
$arguments = explode(' ', $arguments); | |||
} | |||
$parser = new CommandLineParser($this->optionList); | |||
$parser->parse($arguments); | |||
$this->options = $parser->getOptions(); | |||
$this->operands = $parser->getOperands(); | |||
} | |||
/** | |||
* Returns the value of the given option. Must be invoked after parse(). | |||
* | |||
* The return value can be any of the following: | |||
* <ul> | |||
* <li><b>null</b> if the option is not given and does not have a default value</li> | |||
* <li><b>the default value</b> if it has been defined and the option is not given</li> | |||
* <li><b>an integer</b> if the option is given without argument. The | |||
* returned value is the number of occurrences of the option.</li> | |||
* <li><b>a string</b> if the option is given with an argument. The returned value is that argument.</li> | |||
* </ul> | |||
* | |||
* @param string $name The (short or long) option name. | |||
* @return mixed | |||
*/ | |||
public function getOption($name) | |||
{ | |||
return isset($this->options[$name]) ? $this->options[$name] : null; | |||
} | |||
/** | |||
* Returns the list of options. Must be invoked after parse() (otherwise it returns an empty array). | |||
* | |||
* @return array | |||
*/ | |||
public function getOptions() | |||
{ | |||
return $this->options; | |||
} | |||
/** | |||
* Returns the list of operands. Must be invoked after parse(). | |||
* | |||
* @return array | |||
*/ | |||
public function getOperands() | |||
{ | |||
return $this->operands; | |||
} | |||
/** | |||
* Returns the i-th operand (starting with 0), or null if it does not exist. Must be invoked after parse(). | |||
* | |||
* @param int $i | |||
* @return string | |||
*/ | |||
public function getOperand($i) | |||
{ | |||
return ($i < count($this->operands)) ? $this->operands[$i] : null; | |||
} | |||
/** | |||
* Returns the banner string | |||
* | |||
* @return string | |||
*/ | |||
public function getBanner() | |||
{ | |||
return $this->banner; | |||
} | |||
/** | |||
* Set the banner string | |||
* | |||
* @param string $banner The banner string; will be passed to sprintf(), can include %s for current scripts name. | |||
* Be sure to include a trailing line feed. | |||
* @return Getopt | |||
*/ | |||
public function setBanner($banner) | |||
{ | |||
$this->banner = $banner; | |||
return $this; | |||
} | |||
/** | |||
* Returns an usage information text generated from the given options. | |||
* @param int $padding Number of characters to pad output of options to | |||
* @return string | |||
*/ | |||
public function getHelpText($padding = 25) | |||
{ | |||
$helpText = sprintf($this->getBanner(), $this->scriptName); | |||
$helpText .= "Options:\n"; | |||
foreach ($this->optionList as $option) { | |||
$mode = ''; | |||
switch ($option->mode()) { | |||
case self::NO_ARGUMENT: | |||
$mode = ''; | |||
break; | |||
case self::REQUIRED_ARGUMENT: | |||
$mode = "<".$option->getArgument()->getName().">"; | |||
break; | |||
case self::OPTIONAL_ARGUMENT: | |||
$mode = "[<".$option->getArgument()->getName().">]"; | |||
break; | |||
} | |||
$short = ($option->short()) ? '-'.$option->short() : ''; | |||
$long = ($option->long()) ? '--'.$option->long() : ''; | |||
if ($short && $long) { | |||
$options = $short.', '.$long; | |||
} else { | |||
$options = $short ? : $long; | |||
} | |||
$padded = str_pad(sprintf(" %s %s", $options, $mode), $padding); | |||
$helpText .= sprintf("%s %s\n", $padded, $option->getDescription()); | |||
} | |||
return $helpText; | |||
} | |||
/* | |||
* Interface support functions | |||
*/ | |||
public function count() | |||
{ | |||
return count($this->options); | |||
} | |||
public function offsetExists($offset) | |||
{ | |||
return isset($this->options[$offset]); | |||
} | |||
public function offsetGet($offset) | |||
{ | |||
return $this->getOption($offset); | |||
} | |||
public function offsetSet($offset, $value) | |||
{ | |||
throw new \LogicException('Getopt is read-only'); | |||
} | |||
public function offsetUnset($offset) | |||
{ | |||
throw new \LogicException('Getopt is read-only'); | |||
} | |||
public function getIterator() | |||
{ | |||
// For options that have both short and long names, $this->options has two entries. | |||
// We don't want this when iterating, so we have to filter the duplicates out. | |||
$filteredOptions = array(); | |||
foreach ($this->options as $name => $value) { | |||
$keep = true; | |||
foreach ($this->optionList as $option) { | |||
if ($option->long() == $name && !is_null($option->short())) { | |||
$keep = false; | |||
} | |||
} | |||
if ($keep) { | |||
$filteredOptions[$name] = $value; | |||
} | |||
} | |||
return new \ArrayIterator($filteredOptions); | |||
} | |||
} |
@@ -0,0 +1,162 @@ | |||
<?php | |||
namespace Ulrichsg\Getopt; | |||
/** | |||
* Represents an option that Getopt accepts. | |||
*/ | |||
class Option | |||
{ | |||
private $short; | |||
private $long; | |||
private $mode; | |||
private $description = ''; | |||
private $argument; | |||
/** | |||
* Creates a new option. | |||
* | |||
* @param string $short the option's short name (a single letter or digit) or null for long-only options | |||
* @param string $long the option's long name (a string of 2+ letter/digit/_/- characters, starting with a letter | |||
* or digit) or null for short-only options | |||
* @param int $mode whether the option can/must have an argument (one of the constants defined in the Getopt class) | |||
* (optional, defaults to no argument) | |||
* @throws \InvalidArgumentException if both short and long name are null | |||
*/ | |||
public function __construct($short, $long, $mode = Getopt::NO_ARGUMENT) | |||
{ | |||
if (!$short && !$long) { | |||
throw new \InvalidArgumentException("The short and long name may not both be empty"); | |||
} | |||
$this->setShort($short); | |||
$this->setLong($long); | |||
$this->setMode($mode); | |||
$this->argument = new Argument(); | |||
} | |||
/** | |||
* Defines a description for the option. This is only used for generating usage information. | |||
* | |||
* @param string $description | |||
* @return Option this object (for chaining calls) | |||
*/ | |||
public function setDescription($description) | |||
{ | |||
$this->description = $description; | |||
return $this; | |||
} | |||
/** | |||
* Defines a default value for the option. | |||
* | |||
* @param mixed $value | |||
* @return Option this object (for chaining calls) | |||
*/ | |||
public function setDefaultValue($value) | |||
{ | |||
$this->argument->setDefaultValue($value); | |||
return $this; | |||
} | |||
/** | |||
* Defines a validation function for the option. | |||
* | |||
* @param callable $function | |||
* @return Option this object (for chaining calls) | |||
*/ | |||
public function setValidation($function) | |||
{ | |||
$this->argument->setValidation($function); | |||
return $this; | |||
} | |||
/** | |||
* Sets the argument object directly. | |||
* | |||
* @param Argument $arg | |||
* @return Option this object (for chaining calls) | |||
*/ | |||
public function setArgument(Argument $arg) | |||
{ | |||
if ($this->mode == Getopt::NO_ARGUMENT) { | |||
throw new \InvalidArgumentException("Option should not have any argument"); | |||
} | |||
$this->argument = $arg; | |||
return $this; | |||
} | |||
/** | |||
* Returns true if the given string is equal to either the short or the long name. | |||
* | |||
* @param string $string | |||
* @return bool | |||
*/ | |||
public function matches($string) | |||
{ | |||
return ($string === $this->short) || ($string === $this->long); | |||
} | |||
public function short() | |||
{ | |||
return $this->short; | |||
} | |||
public function long() | |||
{ | |||
return $this->long; | |||
} | |||
public function mode() | |||
{ | |||
return $this->mode; | |||
} | |||
public function getDescription() | |||
{ | |||
return $this->description; | |||
} | |||
/** | |||
* Retrieve the argument object | |||
* | |||
* @return Argument | |||
*/ | |||
public function getArgument() | |||
{ | |||
return $this->argument; | |||
} | |||
/** | |||
* Fluent interface for constructor so options can be added during construction | |||
* @see Options::__construct() | |||
*/ | |||
public static function create($short, $long, $mode = Getopt::NO_ARGUMENT) | |||
{ | |||
return new self($short, $long, $mode); | |||
} | |||
private function setShort($short) | |||
{ | |||
if (!(is_null($short) || preg_match("/^[a-zA-Z0-9]$/", $short))) { | |||
throw new \InvalidArgumentException("Short option must be null or a letter/digit, found '$short'"); | |||
} | |||
$this->short = $short; | |||
} | |||
private function setLong($long) | |||
{ | |||
if (!(is_null($long) || preg_match("/^[a-zA-Z0-9][a-zA-Z0-9_-]{1,}$/", $long))) { | |||
throw new \InvalidArgumentException("Long option must be null or an alphanumeric string, found '$long'"); | |||
} | |||
$this->long = $long; | |||
} | |||
private function setMode($mode) | |||
{ | |||
if (!in_array($mode, array(Getopt::NO_ARGUMENT, Getopt::OPTIONAL_ARGUMENT, Getopt::REQUIRED_ARGUMENT), true)) { | |||
throw new \InvalidArgumentException("Option mode must be one of " | |||
."Getopt::NO_ARGUMENT, Getopt::OPTIONAL_ARGUMENT and Getopt::REQUIRED_ARGUMENT"); | |||
} | |||
$this->mode = $mode; | |||
} | |||
} |
@@ -0,0 +1,137 @@ | |||
<?php | |||
namespace Ulrichsg\Getopt; | |||
/** | |||
* Converts user-given option specifications into Option objects. | |||
*/ | |||
class OptionParser | |||
{ | |||
private $defaultMode; | |||
/** | |||
* Creates a new instance. | |||
* | |||
* @param int $defaultMode will be assigned to options when no mode is given for them. | |||
*/ | |||
public function __construct($defaultMode) { | |||
$this->defaultMode = $defaultMode; | |||
} | |||
/** | |||
* Parse a GNU-style option string. | |||
* | |||
* @param string $string the option string | |||
* @return Option[] | |||
* @throws \InvalidArgumentException | |||
*/ | |||
public function parseString($string) | |||
{ | |||
if (!mb_strlen($string)) { | |||
throw new \InvalidArgumentException('Option string must not be empty'); | |||
} | |||
$options = array(); | |||
$eol = mb_strlen($string) - 1; | |||
$nextCanBeColon = false; | |||
for ($i = 0; $i <= $eol; ++$i) { | |||
$ch = $string[$i]; | |||
if (!preg_match('/^[A-Za-z0-9]$/', $ch)) { | |||
$colon = $nextCanBeColon ? " or ':'" : ''; | |||
throw new \InvalidArgumentException("Option string is not well formed: " | |||
."expected a letter$colon, found '$ch' at position ".($i + 1)); | |||
} | |||
if ($i == $eol || $string[$i + 1] != ':') { | |||
$options[] = new Option($ch, null, Getopt::NO_ARGUMENT); | |||
$nextCanBeColon = true; | |||
} elseif ($i < $eol - 1 && $string[$i + 2] == ':') { | |||
$options[] = new Option($ch, null, Getopt::OPTIONAL_ARGUMENT); | |||
$i += 2; | |||
$nextCanBeColon = false; | |||
} else { | |||
$options[] = new Option($ch, null, Getopt::REQUIRED_ARGUMENT); | |||
++$i; | |||
$nextCanBeColon = true; | |||
} | |||
} | |||
return $options; | |||
} | |||
/** | |||
* Processes an option array. The array elements can either be Option objects or arrays conforming to the format | |||
* (short, long, mode [, description [, default]]). See documentation for details. | |||
* | |||
* Developer note: Please don't add any further elements to the array. Future features should be configured only | |||
* through the Option class's methods. | |||
* | |||
* @param array $array | |||
* @return Option[] | |||
* @throws \InvalidArgumentException | |||
*/ | |||
public function parseArray(array $array) | |||
{ | |||
if (empty($array)) { | |||
throw new \InvalidArgumentException('No options given'); | |||
} | |||
$options = array(); | |||
foreach ($array as $row) { | |||
if ($row instanceof Option) { | |||
$options[] = $row; | |||
} elseif (is_array($row)) { | |||
$options[] = $this->createOption($row); | |||
} else { | |||
throw new \InvalidArgumentException("Invalid option type, must be Option or array"); | |||
} | |||
} | |||
return $options; | |||
} | |||
/** | |||
* @param array $row | |||
* @return Option | |||
*/ | |||
private function createOption(array $row) | |||
{ | |||
$rowSize = count($row); | |||
if ($rowSize < 3) { | |||
$row = $this->completeOptionArray($row); | |||
} | |||
$option = new Option($row[0], $row[1], $row[2]); | |||
if ($rowSize >= 4) { | |||
$option->setDescription($row[3]); | |||
} | |||
if ($rowSize >= 5 && $row[2] != Getopt::NO_ARGUMENT) { | |||
$option->setArgument(new Argument($row[4])); | |||
} | |||
return $option; | |||
} | |||
/** | |||
* When using arrays, instead of a full option spec ([short, long, type]) users can leave out one or more of | |||
* these parts and have Getopt fill them in intelligently: | |||
* - If either the short or the long option string is left out, the first element of the given array is interpreted | |||
* as either short (if it has length 1) or long, and the other one is set to null. | |||
* - If the type is left out, it is set to NO_ARGUMENT. | |||
* | |||
* @param array $row | |||
* @return array | |||
*/ | |||
private function completeOptionArray(array $row) | |||
{ | |||
$short = (strlen($row[0]) == 1) ? $row[0] : null; | |||
$long = null; | |||
if (is_null($short)) { | |||
$long = $row[0]; | |||
} elseif (count($row) > 1 && !is_int($row[1])) { | |||
$long = $row[1]; | |||
} | |||
$mode = $this->defaultMode; | |||
if (count($row) == 2 && is_int($row[1])) { | |||
$mode = $row[1]; | |||
} | |||
return array($short, $long, $mode); | |||
} | |||
} |
@@ -0,0 +1,40 @@ | |||
<?php | |||
namespace Ulrichsg\Getopt; | |||
class ArgumentTest extends \PHPUnit_Framework_TestCase | |||
{ | |||
public function testConstructor() | |||
{ | |||
$argument1 = new Argument(); | |||
$argument2 = new Argument(10); | |||
$this->assertFalse($argument1->hasDefaultValue()); | |||
$this->assertEquals(10, $argument2->getDefaultValue()); | |||
} | |||
public function testSetDefaultValueNotScalar() | |||
{ | |||
$this->setExpectedException('InvalidArgumentException'); | |||
$argument = new Argument(); | |||
$argument->setDefaultValue(array()); | |||
} | |||
public function testValidates() | |||
{ | |||
$test = $this; | |||
$argument = new Argument(); | |||
$argument->setValidation(function($arg) use ($test, $argument) { | |||
$test->assertEquals('test', $arg); | |||
return true; | |||
}); | |||
$this->assertTrue($argument->hasValidation()); | |||
$this->assertTrue($argument->validates('test')); | |||
} | |||
public function testSetValidationUncallable() | |||
{ | |||
$this->setExpectedException('InvalidArgumentException'); | |||
$argument = new Argument(); | |||
$argument->setValidation(''); | |||
} | |||
} |
@@ -0,0 +1,341 @@ | |||
<?php | |||
namespace Ulrichsg\Getopt; | |||
class CommandLineParserTest extends \PHPUnit_Framework_TestCase | |||
{ | |||
public function testParseNoOptions() | |||
{ | |||
$parser = new CommandLineParser(array( | |||
new Option('a', null) | |||
)); | |||
$parser->parse('something'); | |||
$this->assertCount(0, $parser->getOptions()); | |||
$operands = $parser->getOperands(); | |||
$this->assertCount(1, $operands); | |||
$this->assertEquals('something', $operands[0]); | |||
} | |||
public function testParseUnknownOption() | |||
{ | |||
$this->setExpectedException('UnexpectedValueException'); | |||
$parser = new CommandLineParser(array( | |||
new Option('a', null) | |||
)); | |||
$parser->parse('-b'); | |||
} | |||
public function testParseRequiredArgumentMissing() | |||
{ | |||
$this->setExpectedException('UnexpectedValueException'); | |||
$parser = new CommandLineParser(array( | |||
new Option('a', null, Getopt::REQUIRED_ARGUMENT) | |||
)); | |||
$parser->parse('-a'); | |||
} | |||
public function testParseMultipleOptionsWithOneHyphen() | |||
{ | |||
$parser = new CommandLineParser(array( | |||
new Option('a', null), | |||
new Option('b', null) | |||
)); | |||
$parser->parse('-ab'); | |||
$options = $parser->getOptions(); | |||
$this->assertEquals(1, $options['a']); | |||
$this->assertEquals(1, $options['b']); | |||
} | |||
public function testParseCumulativeOption() | |||
{ | |||
$parser = new CommandLineParser(array( | |||
new Option('a', null), | |||
new Option('b', null) | |||
)); | |||
$parser->parse('-a -b -a -a'); | |||
$options = $parser->getOptions(); | |||
$this->assertEquals(3, $options['a']); | |||
$this->assertEquals(1, $options['b']); | |||
} | |||
public function testParseCumulativeOptionShort() | |||
{ | |||
$parser = new CommandLineParser(array( | |||
new Option('a', null), | |||
new Option('b', null) | |||
)); | |||
$parser->parse('-abaa'); | |||
$options = $parser->getOptions(); | |||
$this->assertEquals(3, $options['a']); | |||
$this->assertEquals(1, $options['b']); | |||
} | |||
public function testParseShortOptionWithArgument() | |||
{ | |||
$parser = new CommandLineParser(array( | |||
new Option('a', null, Getopt::REQUIRED_ARGUMENT) | |||
)); | |||
$parser->parse('-a value'); | |||
$options = $parser->getOptions(); | |||
$this->assertEquals('value', $options['a']); | |||
} | |||
public function testParseZeroArgument() | |||
{ | |||
$parser = new CommandLineParser(array( | |||
new Option('a', null, Getopt::REQUIRED_ARGUMENT) | |||
)); | |||
$parser->parse('-a 0'); | |||
$options = $parser->getOptions(); | |||
$this->assertEquals('0', $options['a']); | |||
} | |||
public function testParseNumericOption() | |||
{ | |||
$parser = new CommandLineParser(array( | |||
new Option('a', null, Getopt::REQUIRED_ARGUMENT), | |||
new Option('2', null) | |||
)); | |||
$parser->parse('-a 2 -2'); | |||
$options = $parser->getOptions(); | |||
$this->assertEquals('2', $options['a']); | |||
$this->assertEquals(1, $options['2']); | |||
} | |||
public function testParseCollapsedShortOptionsRequiredArgumentMissing() | |||
{ | |||
$this->setExpectedException('UnexpectedValueException'); | |||
$parser = new CommandLineParser(array( | |||
new Option('a', null), | |||
new Option('b', null, Getopt::REQUIRED_ARGUMENT) | |||
)); | |||
$parser->parse('-ab'); | |||
} | |||
public function testParseCollapsedShortOptionsWithArgument() | |||
{ | |||
$parser = new CommandLineParser(array( | |||
new Option('a', null), | |||
new Option('b', null, Getopt::REQUIRED_ARGUMENT) | |||
)); | |||
$parser->parse('-ab value'); | |||
$options = $parser->getOptions(); | |||
$this->assertEquals(1, $options['a']); | |||
$this->assertEquals('value', $options['b']); | |||
} | |||
public function testParseNoArgumentOptionAndOperand() | |||
{ | |||
$parser = new CommandLineParser(array( | |||
new Option('a', null), | |||
)); | |||
$parser->parse('-a b'); | |||
$options = $parser->getOptions(); | |||
$this->assertEquals(1, $options['a']); | |||
$operands = $parser->getOperands(); | |||
$this->assertCount(1, $operands); | |||
$this->assertEquals('b', $operands[0]); | |||
} | |||
public function testParseOperandsOnly() | |||
{ | |||
$parser = new CommandLineParser(array( | |||
new Option('a', null, Getopt::REQUIRED_ARGUMENT), | |||
new Option('b', null) | |||
)); | |||
$parser->parse('-- -a -b'); | |||
$this->assertCount(0, $parser->getOptions()); | |||
$operands = $parser->getOperands(); | |||
$this->assertCount(2, $operands); | |||
$this->assertEquals('-a', $operands[0]); | |||
$this->assertEquals('-b', $operands[1]); | |||
} | |||
public function testParseLongOptionWithoutArgument() | |||
{ | |||
$parser = new CommandLineParser(array( | |||
new Option('o', 'option', Getopt::OPTIONAL_ARGUMENT) | |||
)); | |||
$parser->parse('--option'); | |||
$options = $parser->getOptions(); | |||
$this->assertEquals(1, $options['option']); | |||
} | |||
public function testParseLongOptionWithoutArgumentAndOperand() | |||
{ | |||
$parser = new CommandLineParser(array( | |||
new Option('o', 'option', Getopt::NO_ARGUMENT) | |||
)); | |||
$parser->parse('--option something'); | |||
$options = $parser->getOptions(); | |||
$this->assertEquals(1, $options['option']); | |||
$operands = $parser->getOperands(); | |||
$this->assertCount(1, $operands); | |||
$this->assertEquals('something', $operands[0]); | |||
} | |||
public function testParseLongOptionWithArgument() | |||
{ | |||
$parser = new CommandLineParser(array( | |||
new Option('o', 'option', Getopt::OPTIONAL_ARGUMENT) | |||
)); | |||
$parser->parse('--option value'); | |||
$options = $parser->getOptions(); | |||
$this->assertEquals('value', $options['option']); | |||
$this->assertEquals('value', $options['o']); | |||
} | |||
public function testParseLongOptionWithEqualsSignAndArgument() | |||
{ | |||
$parser = new CommandLineParser(array( | |||
new Option('o', 'option', Getopt::OPTIONAL_ARGUMENT) | |||
)); | |||
$parser->parse('--option=value something'); | |||
$options = $parser->getOptions(); | |||
$this->assertEquals('value', $options['option']); | |||
$operands = $parser->getOperands(); | |||
$this->assertCount(1, $operands); | |||
$this->assertEquals('something', $operands[0]); | |||
} | |||
public function testParseLongOptionWithValueStartingWithHyphen() | |||
{ | |||
$parser = new CommandLineParser(array( | |||
new Option('o', 'option', Getopt::REQUIRED_ARGUMENT) | |||
)); | |||
$parser->parse('--option=-value'); | |||
$options = $parser->getOptions(); | |||
$this->assertEquals('-value', $options['option']); | |||
} | |||
public function testParseNoValueStartingWithHyphenRequired() | |||
{ | |||
$this->setExpectedException('UnexpectedValueException'); | |||
$parser = new CommandLineParser(array( | |||
new Option('a', null, Getopt::REQUIRED_ARGUMENT), | |||
new Option('b', null) | |||
)); | |||
$parser->parse('-a -b'); | |||
} | |||
public function testParseNoValueStartingWithHyphenOptional() | |||
{ | |||
$parser = new CommandLineParser(array( | |||
new Option('a', null, Getopt::OPTIONAL_ARGUMENT), | |||
new Option('b', null) | |||
)); | |||
$parser->parse('-a -b'); | |||
$options = $parser->getOptions(); | |||
$this->assertEquals(1, $options['a']); | |||
$this->assertEquals(1, $options['b']); | |||
} | |||
public function testParseOptionWithDefaultValue() | |||
{ | |||
$optionA = new Option('a', null, Getopt::REQUIRED_ARGUMENT); | |||
$optionA->setArgument(new Argument(10)); | |||
$optionB = new Option('b', 'beta', Getopt::REQUIRED_ARGUMENT); | |||
$optionB->setArgument(new Argument(20)); | |||
$parser = new CommandLineParser(array($optionA, $optionB)); | |||
$parser->parse('-a 12'); | |||
$options = $parser->getOptions(); | |||
$this->assertEquals(12, $options['a']); | |||
$this->assertEquals(20, $options['b']); | |||
$this->assertEquals(20, $options['beta']); | |||
} | |||
public function testDoubleHyphenNotInOperands() | |||
{ | |||
$parser = new CommandLineParser(array( | |||
new Option('a', null, Getopt::REQUIRED_ARGUMENT) | |||
)); | |||
$parser->parse('-a 0 foo -- bar baz'); | |||
$options = $parser->getOptions(); | |||
$this->assertEquals('0', $options['a']); | |||
$operands = $parser->getOperands(); | |||
$this->assertCount(3, $operands); | |||
$this->assertEquals('foo', $operands[0]); | |||
$this->assertEquals('bar', $operands[1]); | |||
$this->assertEquals('baz', $operands[2]); | |||
} | |||
public function testSingleHyphenValue() | |||
{ | |||
$parser = new CommandLineParser(array( | |||
new Option('a', 'alpha', Getopt::REQUIRED_ARGUMENT) | |||
)); | |||
$parser->parse('-a -'); | |||
$options = $parser->getOptions(); | |||
$this->assertEquals('-', $options['a']); | |||
$operands = $parser->getOperands(); | |||
$this->assertCount(0, $operands); | |||
$parser->parse('--alpha -'); | |||
$options = $parser->getOptions(); | |||
$this->assertEquals('-', $options['a']); | |||
$operands = $parser->getOperands(); | |||
$this->assertCount(0, $operands); | |||
} | |||
public function testSingleHyphenOperand() | |||
{ | |||
$parser = new CommandLineParser(array( | |||
new Option('a', null, Getopt::REQUIRED_ARGUMENT) | |||
)); | |||
$parser->parse('-a 0 -'); | |||
$options = $parser->getOptions(); | |||
$this->assertEquals('0', $options['a']); | |||
$operands = $parser->getOperands(); | |||
$this->assertCount(1, $operands); | |||
$this->assertEquals('-', $operands[0]); | |||
} | |||
public function testParseWithArgumentValidation() | |||
{ | |||
$validation = 'is_numeric'; | |||
$optionA = new Option('a', null, Getopt::OPTIONAL_ARGUMENT); | |||
$optionA->setArgument(new Argument(null, $validation)); | |||
$optionB = new Option('b', null, Getopt::REQUIRED_ARGUMENT); | |||
$optionB->setArgument(new Argument(null, $validation)); | |||
$optionC = new Option('c', null, Getopt::OPTIONAL_ARGUMENT); | |||
$optionC->setArgument(new Argument(null, $validation)); | |||
$parser = new CommandLineParser(array($optionA, $optionB, $optionC)); | |||
$parser->parse('-a 1 -b 2 -c'); | |||
$options = $parser->getOptions(); | |||
$this->assertSame('1', $options['a']); | |||
$this->assertSame('2', $options['b']); | |||
$this->assertSame(1, $options['c']); | |||
} | |||
public function testParseInvalidArgument() | |||
{ | |||
$this->setExpectedException('UnexpectedValueException'); | |||
$validation = 'is_numeric'; | |||
$option = new Option('a', null, Getopt::OPTIONAL_ARGUMENT); | |||
$option->setArgument(new Argument(null, $validation)); | |||
$parser = new CommandLineParser(array($option)); | |||
$parser->parse('-a nonnumeric'); | |||
} | |||
} |
@@ -0,0 +1,199 @@ | |||
<?php | |||
namespace Ulrichsg\Getopt; | |||
class GetoptTest extends \PHPUnit_Framework_TestCase | |||
{ | |||
public function testAddOptions() | |||
{ | |||
$getopt = new Getopt(); | |||
$getopt->addOptions('a:'); | |||
$getopt->addOptions( | |||
array( | |||
array('s', null, Getopt::OPTIONAL_ARGUMENT), | |||
array(null, 'long', Getopt::OPTIONAL_ARGUMENT), | |||
array('n', 'name', Getopt::OPTIONAL_ARGUMENT) | |||
) | |||
); | |||
$getopt->parse('-a aparam -s sparam --long longparam'); | |||
$this->assertEquals('aparam', $getopt->getOption('a')); | |||
$this->assertEquals('longparam', $getopt->getOption('long')); | |||
$this->assertEquals('sparam', $getopt->getOption('s')); | |||
} | |||
public function testAddOptionsChooseShortOrLongAutomatically() | |||
{ | |||
$getopt = new Getopt(); | |||
$getopt->addOptions( | |||
array( | |||
array('s'), | |||
array('long', Getopt::OPTIONAL_ARGUMENT) | |||
) | |||
); | |||
$getopt->parse('-s --long longparam'); | |||
$this->assertEquals('longparam', $getopt->getOption('long')); | |||
$this->assertEquals('1', $getopt->getOption('s')); | |||
} | |||
public function testAddOptionsUseDefaultArgumentType() | |||
{ | |||
$getopt = new Getopt(null, Getopt::REQUIRED_ARGUMENT); | |||
$getopt->addOptions( | |||
array( | |||
array('l', 'long') | |||
) | |||
); | |||
$getopt->parse('-l something'); | |||
$this->assertEquals('something', $getopt->getOption('l')); | |||
$getopt->parse('--long someOtherThing'); | |||
$this->assertEquals('someOtherThing', $getopt->getOption('long')); | |||
} | |||
public function testAddOptionsFailsOnInvalidArgument() | |||
{ | |||
$this->setExpectedException('\InvalidArgumentException'); | |||
$getopt = new Getopt(null); | |||
$getopt->addOptions(new Option('a', 'alpha')); | |||
} | |||
public function testAddOptionsOverwritesExistingOptions() | |||
{ | |||
$getopt = new Getopt(array( | |||
array('a', null, Getopt::REQUIRED_ARGUMENT) | |||
)); | |||
$getopt->addOptions(array( | |||
array('a', null, Getopt::NO_ARGUMENT) | |||
)); | |||
$getopt->parse('-a foo'); | |||
$this->assertEquals(1, $getopt->getOption('a')); | |||
$this->assertEquals('foo', $getopt->getOperand(0)); | |||
} | |||
public function testAddOptionsFailsOnConflict() | |||
{ | |||
$this->setExpectedException('\InvalidArgumentException'); | |||
$getopt = new Getopt(array( | |||
array('v', 'version') | |||
)); | |||
$getopt->addOptions(array( | |||
array('v', 'verbose') | |||
)); | |||
} | |||
public function testParseUsesGlobalArgvWhenNoneGiven() | |||
{ | |||
global $argv; | |||
$argv = array('foo.php', '-a'); | |||
$getopt = new Getopt('a'); | |||
$getopt->parse(); | |||
$this->assertEquals(1, $getopt->getOption('a')); | |||
} | |||
public function testAccessMethods() | |||
{ | |||
$getopt = new Getopt('a'); | |||
$getopt->parse('-a foo'); | |||
$options = $getopt->getOptions(); | |||
$this->assertCount(1, $options); | |||
$this->assertEquals(1, $options['a']); | |||
$this->assertEquals(1, $getopt->getOption('a')); | |||
$operands = $getopt->getOperands(); | |||
$this->assertCount(1, $operands); | |||
$this->assertEquals('foo', $operands[0]); | |||
$this->assertEquals('foo', $getopt->getOperand(0)); | |||
} | |||
public function testCountable() | |||
{ | |||
$getopt = new Getopt('abc'); | |||
$getopt->parse('-abc'); | |||
$this->assertEquals(3, count($getopt)); | |||
} | |||
public function testArrayAccess() | |||
{ | |||
$getopt = new Getopt('q'); | |||
$getopt->parse('-q'); | |||
$this->assertEquals(1, $getopt['q']); | |||
} | |||
public function testIterable() | |||
{ | |||
$getopt = new Getopt(array( | |||
array(null, 'alpha', Getopt::NO_ARGUMENT), | |||
array('b', 'beta', Getopt::REQUIRED_ARGUMENT) | |||
)); | |||
$getopt->parse('--alpha -b foo'); | |||
$expected = array('alpha' => 1, 'b' => 'foo'); // 'beta' should not occur | |||
foreach ($getopt as $option => $value) { | |||
$this->assertEquals($expected[$option], $value); | |||
} | |||
} | |||
public function testHelpText() | |||
{ | |||
$getopt = new Getopt(array( | |||
array('a', 'alpha', Getopt::NO_ARGUMENT, 'Short and long options with no argument'), | |||
array(null, 'beta', Getopt::OPTIONAL_ARGUMENT, 'Long option only with an optional argument'), | |||
array('c', null, Getopt::REQUIRED_ARGUMENT, 'Short option only with a mandatory argument') | |||
)); | |||
$getopt->parse(''); | |||
$script = $_SERVER['PHP_SELF']; | |||
$expected = "Usage: $script [options] [operands]\n"; | |||
$expected .= "Options:\n"; | |||
$expected .= " -a, --alpha Short and long options with no argument\n"; | |||
$expected .= " --beta [<arg>] Long option only with an optional argument\n"; | |||
$expected .= " -c <arg> Short option only with a mandatory argument\n"; | |||
$this->assertEquals($expected, $getopt->getHelpText()); | |||
} | |||
public function testHelpTextWithoutDescriptions() | |||
{ | |||
$getopt = new Getopt(array( | |||
array('a', 'alpha', Getopt::NO_ARGUMENT), | |||
array(null, 'beta', Getopt::OPTIONAL_ARGUMENT), | |||
array('c', null, Getopt::REQUIRED_ARGUMENT) | |||
)); | |||
$getopt->parse(''); | |||
$script = $_SERVER['PHP_SELF']; | |||
$expected = "Usage: $script [options] [operands]\n"; | |||
$expected .= "Options:\n"; | |||
$expected .= " -a, --alpha \n"; | |||
$expected .= " --beta [<arg>] \n"; | |||
$expected .= " -c <arg> \n"; | |||
$this->assertEquals($expected, $getopt->getHelpText()); | |||
} | |||
public function testHelpTextNoParse() | |||
{ | |||
$getopt = new Getopt(); | |||
$expected = "Usage: [options] [operands]\nOptions:\n"; | |||
$this->assertSame($expected, $getopt->getHelpText()); | |||
} | |||
public function testHelpTextWithCustomBanner() | |||
{ | |||
$script = $_SERVER['PHP_SELF']; | |||
$getopt = new Getopt(); | |||
$getopt->setBanner("My custom Banner %s\n"); | |||
$this->assertSame("My custom Banner \nOptions:\n", $getopt->getHelpText()); | |||
$getopt->parse(''); | |||
$this->assertSame("My custom Banner $script\nOptions:\n", $getopt->getHelpText()); | |||
} | |||
} |
@@ -0,0 +1,112 @@ | |||
<?php | |||
namespace Ulrichsg\Getopt; | |||
class OptionParserTest extends \PHPUnit_Framework_TestCase | |||
{ | |||
/** @var OptionParser */ | |||
private $parser; | |||
public function setUp() | |||
{ | |||
$this->parser = new OptionParser(Getopt::REQUIRED_ARGUMENT); | |||
} | |||
public function testParseString() | |||
{ | |||
$options = $this->parser->parseString('ab:c::3'); | |||
$this->assertInternalType('array', $options); | |||
$this->assertCount(4, $options); | |||
foreach ($options as $option) { | |||
$this->assertInstanceOf('Ulrichsg\Getopt\Option', $option); | |||
$this->assertNull($option->long()); | |||
switch ($option->short()) { | |||
case 'a': | |||
case '3': | |||
$this->assertEquals(Getopt::NO_ARGUMENT, $option->mode()); | |||
break; | |||
case 'b': | |||
$this->assertEquals(Getopt::REQUIRED_ARGUMENT, $option->mode()); | |||
break; | |||
case 'c': | |||
$this->assertEquals(Getopt::OPTIONAL_ARGUMENT, $option->mode()); | |||
break; | |||
default: | |||
$this->fail('Unexpected option: '.$option->short()); | |||
} | |||
} | |||
} | |||
public function testParseStringEmpty() | |||
{ | |||
$this->setExpectedException('InvalidArgumentException'); | |||
$this->parser->parseString(''); | |||
} | |||
public function testParseStringInvalidCharacter() | |||
{ | |||
$this->setExpectedException('InvalidArgumentException'); | |||
$this->parser->parseString('ab:c::dä'); | |||
} | |||
public function testParseStringStartsWithColon() | |||
{ | |||
$this->setExpectedException('InvalidArgumentException'); | |||
$this->parser->parseString(':ab:c::d'); | |||
} | |||
public function testParseStringTripleColon() | |||
{ | |||
$this->setExpectedException('InvalidArgumentException'); | |||
$this->parser->parseString('ab:c:::d'); | |||
} | |||
public function testParseArray() | |||
{ | |||
$options = $this->parser->parseArray( | |||
array( | |||
array('a', 'alpha', Getopt::OPTIONAL_ARGUMENT, 'Description', 42), | |||
new Option('b', 'beta'), | |||
array('c') | |||
) | |||
); | |||
$this->assertCount(3, $options); | |||
foreach ($options as $option) { | |||
$this->assertInstanceOf('Ulrichsg\Getopt\Option', $option); | |||
switch ($option->short()) { | |||
case 'a': | |||
$this->assertEquals('alpha', $option->long()); | |||
$this->assertEquals(Getopt::OPTIONAL_ARGUMENT, $option->mode()); | |||
$this->assertEquals('Description', $option->getDescription()); | |||
$this->assertEquals(42, $option->getArgument()->getDefaultValue()); | |||
break; | |||
case 'b': | |||
$this->assertEquals('beta', $option->long()); | |||
$this->assertEquals(Getopt::NO_ARGUMENT, $option->mode()); | |||
$this->assertEquals('', $option->getDescription()); | |||
break; | |||
case 'c': | |||
$this->assertNull($option->long()); | |||
$this->assertEquals(Getopt::REQUIRED_ARGUMENT, $option->mode()); | |||
$this->assertEquals('', $option->getDescription()); | |||
$this->assertFalse($option->getArgument()->hasDefaultValue()); | |||
break; | |||
default: | |||
$this->fail('Unexpected option: '.$option->short()); | |||
} | |||
} | |||
} | |||
public function testParseArrayEmpty() | |||
{ | |||
$this->setExpectedException('InvalidArgumentException'); | |||
$this->parser->parseArray(array()); | |||
} | |||
public function testParseArrayInvalid() | |||
{ | |||
$this->setExpectedException('InvalidArgumentException'); | |||
$this->parser->parseArray(array('a', 'b')); | |||
} | |||
} |
@@ -0,0 +1,72 @@ | |||
<?php | |||
namespace Ulrichsg\Getopt; | |||
class OptionTest extends \PHPUnit_Framework_TestCase | |||
{ | |||
public function testConstruct() | |||
{ | |||
$option = new Option('a', 'az-AZ09_', Getopt::OPTIONAL_ARGUMENT); | |||
$this->assertEquals('a', $option->short()); | |||
$this->assertEquals('az-AZ09_', $option->long()); | |||
$this->assertEquals(Getopt::OPTIONAL_ARGUMENT, $option->mode()); | |||
} | |||
public function testConstructEmptyOption() | |||
{ | |||
$this->setExpectedException('InvalidArgumentException'); | |||
new Option(null, null, Getopt::NO_ARGUMENT); | |||
} | |||
public function testConstructNoLetter() | |||
{ | |||
$this->setExpectedException('InvalidArgumentException'); | |||
new Option('?', null, Getopt::NO_ARGUMENT); | |||
} | |||
public function testConstructInvalidCharacter() | |||
{ | |||
$this->setExpectedException('InvalidArgumentException'); | |||
new Option(null, 'öption', Getopt::NO_ARGUMENT); | |||
} | |||
public function testConstructInvalidArgumentType() | |||
{ | |||
$this->setExpectedException('InvalidArgumentException'); | |||
new Option('a', null, 'no_argument'); | |||
} | |||
public function testConstructLongOptionTooShort() | |||
{ | |||
$this->setExpectedException('InvalidArgumentException'); | |||
new Option(null, 'a', Getopt::REQUIRED_ARGUMENT); | |||
} | |||
public function testSetArgument() | |||
{ | |||
$option = new Option('a', null, Getopt::OPTIONAL_ARGUMENT); | |||
$this->assertEquals($option, $option->setArgument(new Argument())); | |||
$this->assertInstanceof('Ulrichsg\Getopt\Argument', $option->getArgument()); | |||
} | |||
public function testSetArgumentWrongMode() | |||
{ | |||
$this->setExpectedException('InvalidArgumentException'); | |||
$option = new Option('a', null, Getopt::NO_ARGUMENT); | |||
$option->setArgument(new Argument()); | |||
} | |||
public function testSetDefaultValue() | |||
{ | |||
$option = new Option('a', null, Getopt::OPTIONAL_ARGUMENT); | |||
$this->assertEquals($option, $option->setDefaultValue(10)); | |||
$this->assertEquals(10, $option->getArgument()->getDefaultValue()); | |||
} | |||
public function testSetValidation() | |||
{ | |||
$option = new Option('a', null, Getopt::OPTIONAL_ARGUMENT); | |||
$this->assertEquals($option, $option->setValidation('is_numeric')); | |||
$this->assertTrue($option->getArgument()->hasValidation()); | |||
} | |||
} |