diff --git a/PhpOptions.min.php b/PhpOptions.min.php index 09a6e80..7e21474 100644 --- a/PhpOptions.min.php +++ b/PhpOptions.min.php @@ -1 +1 @@ - @license "New" BSD License */ namespace PhpOptions; class Arguments { private static $options = NULL; private static $arguments = NULL; public static function options() { self::setAll(); return self::$options; } public static function arguments() { self::setAll(); return self::$arguments; } private static function setAll() { if (is_null(self::$options) || is_null(self::$arguments)) { $all = self::readAll(); self::$options = $all['options']; self::$arguments = $all['arguments']; } } private static function readAll() { $cmdOptions = array(); $cmdArguments = array(); $args = $_SERVER['argv']; array_shift($args); if (count($args) > 0) { $argsClean = array(); foreach ($args as $arg) { $position = strpos($arg, '='); if ($position === 0) { $argsClean[] = substr($arg, 1); } elseif ($position !== FALSE) { $argsClean[] = substr($arg, 0, $position); $argsClean[] = substr($arg, $position + 1); } else { $argsClean[] = $arg; } } $args = $argsClean; $previous = NULL; foreach ($args as $arg) { if (substr($arg, 0, 2) == '--') { $option = substr($arg, 2); $cmdOptions[$option] = TRUE; $previous = $option; } elseif (substr($arg, 0, 1) == '-' && !(preg_match('/^-[0-9]+([.,][0-9]+)?$/', $arg))) { foreach (str_split(substr($arg, 1)) as $char) { $cmdOptions[$char] = TRUE; $previous = $char; } } elseif ($previous) { $cmdOptions[$previous] = $arg; $previous = NULL; } else { $cmdArguments[] = $arg; } } } return array('options' => $cmdOptions, 'arguments' => $cmdArguments); } } namespace PhpOptions; class InvalidArgumentException extends \Exception { } class LogicException extends \Exception { } class UserBadCallException extends \Exception { } namespace PhpOptions; class Option { const VALUE_NO = 'value_no'; const VALUE_REQUIRE = 'value_require'; const VALUE_OPTIONAL = 'value_optional'; const HELP_INDENT_LENGTH = 4; private static $types = NULL; private $name; private $type = NULL; private $value = NULL; private $short; private $long; private $defaults = NULL; private $required = FALSE; private $valueRequired = self::VALUE_NO; private $description = ''; private $needed = array(); public function __construct($name) { if (!$name) { throw new InvalidArgumentException('Name of option cannot be empty.'); } $this->name = $name; $long = strtolower($name); $long = preg_replace('/[^a-z0-9]+/', '-', $long); $long = preg_replace('/-+/', '-', $long); $this->long($long); $this->short(substr($long, 0, 1)); } public static function make($name) { return new Option($name); } public static function __callStatic($type, $settings) { $name = (isset($settings[0])) ? array_shift($settings) : ''; $option = self::make($name); $option->type = self::getTypes()->getType($type, $settings); $option->value(); return $option; } public static function registerType($name, $className, $classPath) { self::getTypes()->register($name, $className, $classPath); } public function short($short = NULL) { if (is_null($short) && is_null($this->long)) { throw new LogicException($this->name . ': Short and long varint cannot be undefined together.'); } if (!is_null($short) && strlen($short) != 1) { throw new InvalidArgumentException($this->name . ': Short variant has to be only one character.'); } $this->short = $short; return $this; } public function long($long = NULL) { if (is_null($long) && is_null($this->short)) { throw new LogicException($this->name . ': Short and long varint cannot be undefined together.'); } $this->long = $long; return $this; } public function defaults($defaults = NULL) { if (!is_null($defaults) && !( ($this->valueRequired == self::VALUE_OPTIONAL) || ($this->valueRequired == self::VALUE_REQUIRE && $this->required == FALSE) )) { throw new LogicException($this->name . ': The default value makes sense only for options with optional value or optional option with optional or required value.'); } $this->defaults = $defaults; return $this; } public function required($required = TRUE) { if ($this->valueRequired == self::VALUE_REQUIRE && !is_null($this->defaults)) { throw new LogicException($this->name . ': The required option does not make sense for option with default value and required value.'); } $this->required = (bool)$required; return $this; } public function value($value = TRUE) { $value = ((bool)$value) ? self::VALUE_REQUIRE : self::VALUE_OPTIONAL; if (!is_null($this->defaults) && $value != self::VALUE_OPTIONAL) { throw new LogicException($this->name . ': The require/non value makes sense only for option without default value.'); } $this->valueRequired = $value; return $this; } public function description($description = '') { $this->description = $description; return $this; } public function dependences($needed) { $this->needed = $needed; return $this; } public function getName() { return $this->name; } public function getShort() { return $this->short; } public function getLong() { return $this->long; } public function getDefaults() { return $this->defaults; } public function getValue($isDefaultSet = FALSE) { if (is_null($this->value)) { $this->value = $this->readValue($isDefaultSet); } return $this->value; } public function getOptions($value = '') { $options = ''; $options .= ($this->short ? '-' . $this->short . $value : ''); $options .= ($this->short && $this->long ? ', ' : ''); $options .= ($this->long ? '--' . $this->long . $value : ''); return $options; } public function getHelp($maxLength, $indent = 0) { $indentString = str_repeat(' ', self::HELP_INDENT_LENGTH); if ($indent) { $indent = implode('', array_fill(0, $indent, $indentString)); } else { $indent = ''; } $valueType = 'VALUE'; if ($this->type) { $valueType = $this->type->getName(); } switch ($this->valueRequired) { case self::VALUE_NO: $value = ''; break; case self::VALUE_OPTIONAL: $value = '[="' . $valueType . '"]'; break; case self::VALUE_REQUIRE: $value = '="' . $valueType . '"'; break; } $help = $this->getOptions($value); if (!$this->required) { $help = '[' . $help . ']'; } $help = $this->wordwrap($help, $maxLength, $indent); if (!is_null($this->defaults)) { switch (gettype($this->defaults)) { case 'boolean': $defaults = $this->defaults ? 'TRUE' : 'FALSE'; break; case 'array': $defaults = 'array(' . implode(',', $this->defaults) . ')'; break; default: $defaults = $this->defaults; break; } $help .= PHP_EOL . $this->wordwrap('DEFAULT="' . $defaults . '"', $maxLength, $indentString . $indent); } if (count($this->needed) > 0) { $helpNeeded = array(); foreach ($this->needed as $neededOption) { $helpNeeded[] = $neededOption->getOptions(); } $help .= PHP_EOL . $this->wordwrap('NEEDED: ' . implode('; ', $helpNeeded), $maxLength, $indentString . $indent); } if ($this->description) { $help .= PHP_EOL . $this->wordwrap(str_replace(PHP_EOL, PHP_EOL . $indentString . $indent, $this->description), $maxLength, $indentString . $indent); } return $help; } private static function getTypes() { if (!self::$types) { self::$types = new Types\Types(); } return self::$types; } private function readValue($isDefaultSet) { $options = Arguments::options(); $short = isset($options[$this->short]) ? $options[$this->short] : FALSE; $long = isset($options[$this->long]) ? $options[$this->long] : FALSE; if ($short !== FALSE && $long !== FALSE) { throw new UserBadCallException($this->getOptions() . ': Option has value set by short and long variant.'); } elseif ($short === FALSE && $long === FALSE) { $value = FALSE; } elseif ($short !== FALSE) { $value = $short; } else { $value = $long; } if (!$isDefaultSet && $this->required && $value === FALSE) { throw new UserBadCallException($this->getOptions() . ': Option is required.'); } switch ($this->valueRequired) { case self::VALUE_NO: if (!is_bool($value)) { throw new UserBadCallException($this->getOptions() . ': Option has value, but any is expected.'); } break; case self::VALUE_OPTIONAL: if (is_bool($value) && !is_null($this->defaults)) { $value = $this->defaults; } break; case self::VALUE_REQUIRE: if ($value === TRUE) { throw new UserBadCallException($this->getOptions() . ': Option has require value, but no set.'); } else if ($value === FALSE && !is_null($this->defaults)) { $value = $this->defaults; } break; } if (($value !== FALSE) && !is_null($this->type)) { if (!$this->type->check($value)) { throw new UserBadCallException($this->getOptions() . ': Option has bad format.'); } if (($this->valueRequired != self::VALUE_OPTIONAL) || !is_bool($value)) { $value = $this->type->filter($value); } } return $value; } private function wordwrap($string, $maxLength, $prefix) { $string = wordwrap($string, $maxLength - strlen($prefix), PHP_EOL, FALSE); $strings = explode(PHP_EOL, $string); array_walk($strings, function (&$item, $key, $prefix) { $item = $prefix . trim($item); }, $prefix ); $string = implode(PHP_EOL, $strings); return $string; } } namespace PhpOptions; class Options { const VERSION = '1.2.0'; const HELP_MAX_LENGTH = 75; private $options = array(); private $optionsValues = array(); private $optionsShorts = array(); private $optionsLongs = array(); private $defaults = NULL; private $description = ''; private $groups = array(); public function __construct() { if (php_sapi_name() !== 'cli') { throw new UserBadCallException('Script have to run from command line.'); } } public static function arguments() { return Arguments::arguments(); } public function add($options = array()) { if (!is_array($options)) { $options = array($options); } foreach ($options as $option) { $this->addOne($option); } return $this; } public function defaults($name) { if (!isset($this->options[$name])) { throw new InvalidArgumentException($name . ': Unknown option.'); } $value = $this->options[$name]->getDefaults(); $this->defaults['name'] = $name; $this->defaults['value'] = $value; if (is_null($value)) { $this->defaults['value'] = TRUE; } return $this; } public function description($description) { $this->description = $description; return $this; } public function get($name) { $nameInput = $name; if (substr($name, 0, 2) == '--') { $long = substr($name, 2); $name = isset($this->optionsLongs[$long]) ? $this->optionsLongs[$long] : NULL; } elseif (substr($name, 0, 1) == '-') { $short = substr($name, 1); $name = isset($this->optionsShorts[$short]) ? $this->optionsShorts[$short] : NULL; } if (!isset($this->optionsValues[$name])) { throw new InvalidArgumentException($nameInput . ': Unknown option.'); } if (!is_null($this->defaults) && ($this->defaults['name'] == $name) && (count(Arguments::options()) == 0)) { return $this->defaults['value']; } return $this->optionsValues[$name]; } public function dependences($main, $needed, $groupName = NULL) { if (!is_array($needed)) { $needed = array($needed); } if (!isset($this->optionsValues[$main])) { throw new InvalidArgumentException($main . ': Unknown option.'); } $neededOptions = array(); foreach ($needed as $name) { if (!isset($this->optionsValues[$name])) { throw new InvalidArgumentException($name . ': Unknown option.'); } $neededOptions[] = $this->options[$name]; } if ($this->get($main) !== FALSE) { foreach ($needed as $name) { if ($this->get($name) === FALSE) { $mainOptions = $this->options[$main]->getOptions(); $nameOptions = $this->options[$name]->getOptions(); throw new UserBadCallException('Option "' . $mainOptions . '" needs option "'. $nameOptions . '".'); } } } $this->options[$main]->dependences($neededOptions); if ($groupName) { array_unshift($needed, $main); $this->group($groupName, $needed); } return $this; } public function group($name, $options) { if (in_array($name, array_keys($this->groups))) { throw new LogicException($name . ': Group already exists.'); } if (!is_array($options)) { $options = array($options); } foreach ($options as $optionName) { if (!isset($this->options[$optionName])) { throw new LogicException($optionName . ': Option does not exist.'); } } $this->groups[$name] = $options; return $this; } public function getHelp($maxLength = self::HELP_MAX_LENGTH) { $help = $this->wordwrap($this->description, $maxLength) . PHP_EOL . PHP_EOL; $optionsNongroup = $this->options; $indent = 0; if ($this->groups) { foreach ($this->groups as $groupName => $optionsNames) { $help .= $this->wordwrap($groupName, $maxLength) . PHP_EOL; foreach ($optionsNames as $optionName) { $help .= $this->options[$optionName]->getHelp($maxLength, 1) . PHP_EOL; if (isset($optionsNongroup[$optionName])) { unset($optionsNongroup[$optionName]); } } } if (count($optionsNongroup) > 0) { $help .= PHP_EOL . $this->wordwrap('NON GROUP OPTIONS:', $maxLength) . PHP_EOL; } $indent = 1; } foreach ($optionsNongroup as $option) { $help .= $option->getHelp($maxLength, $indent) . PHP_EOL; } return $help; } private function addOne(Option $option) { $this->checkConflicts($option); $name = $option->getName(); $this->options[$name] = $option; $this->optionsValues[$name] = $option->getValue((bool)($this->defaults['value'])); if ($option->getShort()) { $this->optionsShorts[$option->getShort()] = $name; } if ($option->getLong()) { $this->optionsLongs[$option->getLong()] = $name; } } private function checkConflicts(Option $option) { $name = $option->getName(); if (isset($this->options[$name])) { throw new LogicException($name . ': Option already exists.'); } $short = $option->getShort(); if (in_array($short, array_keys($this->optionsShorts))) { throw new LogicException($name . ': Option with short variant "' . $short . '" already exists.'); } $long = $option->getLong(); if (in_array($long, array_keys($this->optionsLongs))) { throw new LogicException($name . ': Option with long variant "' . $long . '" already exists.'); } } private function wordwrap($string, $maxLength) { return wordwrap($string, $maxLength, PHP_EOL, TRUE); } } namespace PhpOptions\Types; abstract class AType { protected $useFilter = TRUE; public function __construct(&$settings = array()) { if ($this->settingsHasFlag('notFilter', $settings)) { $this->useFilter = FALSE; } } public function check($value) { return TRUE; } public function getName() { $className = get_class($this); $start = strrpos($className, '\\') + 1; $name = substr($className, $start, -4); return strtoupper($name); } final public function filter($value) { if ($this->useFilter) { return $this->useFilter($value); } else { return $value; } } protected function useFilter($value) { return $value; } protected function settingsHasFlag($flag, &$settings) { $flag = strtolower($flag); $settingsLower = $settings; array_walk($settingsLower, function (&$item, $key) { if (is_string($item)) { $item = strtolower($item); } }); $flagIdx = array_search($flag, $settingsLower); if ($flagIdx !== FALSE) { $hasFlag = TRUE; unset($settings[$flagIdx]); $settings = array_values($settings); } else { $hasFlag = FALSE; } return $hasFlag; } } namespace PhpOptions\Types; class Types { private $registeredTypes = array(); private static $serializedDeafultTypes = 'a:13:{s:4:"Char";a:2:{s:9:"className";s:26:"\PhpOptions\Types\CharType";s:9:"classPath";s:63:"C:\DATA\Viktor\Develop\PhpOptions\PhpOptions\Types\CharType.php";}s:4:"Date";a:2:{s:9:"className";s:26:"\PhpOptions\Types\DateType";s:9:"classPath";s:63:"C:\DATA\Viktor\Develop\PhpOptions\PhpOptions\Types\DateType.php";}s:8:"Datetime";a:2:{s:9:"className";s:30:"\PhpOptions\Types\DatetimeType";s:9:"classPath";s:67:"C:\DATA\Viktor\Develop\PhpOptions\PhpOptions\Types\DatetimeType.php";}s:9:"Directory";a:2:{s:9:"className";s:31:"\PhpOptions\Types\DirectoryType";s:9:"classPath";s:68:"C:\DATA\Viktor\Develop\PhpOptions\PhpOptions\Types\DirectoryType.php";}s:5:"Email";a:2:{s:9:"className";s:27:"\PhpOptions\Types\EmailType";s:9:"classPath";s:64:"C:\DATA\Viktor\Develop\PhpOptions\PhpOptions\Types\EmailType.php";}s:4:"Enum";a:2:{s:9:"className";s:26:"\PhpOptions\Types\EnumType";s:9:"classPath";s:63:"C:\DATA\Viktor\Develop\PhpOptions\PhpOptions\Types\EnumType.php";}s:4:"File";a:2:{s:9:"className";s:26:"\PhpOptions\Types\FileType";s:9:"classPath";s:63:"C:\DATA\Viktor\Develop\PhpOptions\PhpOptions\Types\FileType.php";}s:7:"Inifile";a:2:{s:9:"className";s:29:"\PhpOptions\Types\InifileType";s:9:"classPath";s:66:"C:\DATA\Viktor\Develop\PhpOptions\PhpOptions\Types\InifileType.php";}s:7:"Integer";a:2:{s:9:"className";s:29:"\PhpOptions\Types\IntegerType";s:9:"classPath";s:66:"C:\DATA\Viktor\Develop\PhpOptions\PhpOptions\Types\IntegerType.php";}s:4:"Real";a:2:{s:9:"className";s:26:"\PhpOptions\Types\RealType";s:9:"classPath";s:63:"C:\DATA\Viktor\Develop\PhpOptions\PhpOptions\Types\RealType.php";}s:6:"Series";a:2:{s:9:"className";s:28:"\PhpOptions\Types\SeriesType";s:9:"classPath";s:65:"C:\DATA\Viktor\Develop\PhpOptions\PhpOptions\Types\SeriesType.php";}s:6:"String";a:2:{s:9:"className";s:28:"\PhpOptions\Types\StringType";s:9:"classPath";s:65:"C:\DATA\Viktor\Develop\PhpOptions\PhpOptions\Types\StringType.php";}s:4:"Time";a:2:{s:9:"className";s:26:"\PhpOptions\Types\TimeType";s:9:"classPath";s:63:"C:\DATA\Viktor\Develop\PhpOptions\PhpOptions\Types\TimeType.php";}}'; public function __construct() { foreach ($this->getDefaultTypes() as $name => $class) { $this->register($name, $class['className'], $class['classPath']); } } public function register($name, $className, $classPath) { $name = strtolower($name); $this->registeredTypes[$name]['className'] = $className; $this->registeredTypes[$name]['classPath'] = $classPath; } public function getType($type, $settings) { if (!isset($this->registeredTypes[$type])) { throw new \PhpOptions\InvalidArgumentException($type . ': Undefined type of option.'); } $className = $this->registeredTypes[$type]['className']; $typeClass = new $className($settings); if (!($typeClass instanceof \PhpOptions\Types\AType)) { throw new \PhpOptions\InvalidArgumentException($type . ': Type have to be instance of \PhpOptions\Types\AType.'); } return $typeClass; } public function getDefaultTypes() { if (self::$serializedDeafultTypes) { return unserialize(self::$serializedDeafultTypes); } $types = array(); $files = scandir(__DIR__); foreach ($files as $file) { if (substr($file, -8) == 'Type.php') { $nameOfType = substr($file, 0, -8); $className = '\\PhpOptions\\Types\\' . substr($file, 0, -4); $types[$nameOfType]['className'] = $className; $types[$nameOfType]['classPath'] = __DIR__ . DIRECTORY_SEPARATOR . $file; } } unset($types['A']); return $types; } } namespace PhpOptions\Types; class CharType extends AType { public function check($value) { return (bool)(strlen($value) == 1); } } namespace PhpOptions\Types; class DateType extends AType { private $timestamp = FALSE; public function __construct($settings = array()) { parent::__construct($settings); if ($this->settingsHasFlag('timestamp', $settings)) { $this->timestamp = TRUE; } } public function check($value) { $dateString = $this->getDatetimeString($value); $isDate = FALSE; if ($dateString) { try { $dateObj = new \DateTime($dateString); $isDate = ($dateObj) ? TRUE : FALSE; } catch (\Exception $e) { $isDate = FALSE; } } return $isDate; } protected function useFilter($value) { $dateString = $this->getDatetimeString($value); $date = FALSE; if ($dateString) { $date = new \DateTime($dateString); if ($this->timestamp) { $date = $date->getTimestamp(); } } return $date; } private function getDatetimeString($value) { $match = preg_match('/^([0-9]{4})[-.]([0-9a-zA-Z]+)[-.]([0-9]{1,2})$/', $value, $matches); $date = ''; if ($match) { $year = $matches[1]; $month = $this->complete($matches[2]); $day = $this->complete($matches[3]); $date = $year . '-' . $month . '-' . $day . ' 00:00:00'; } return $date; } private function complete($value) { if (strlen($value) == 1) { $value = '0' . $value; } return $value; } } namespace PhpOptions\Types; class DatetimeType extends AType { private $timestamp = FALSE; public function __construct($settings = array()) { parent::__construct($settings); if ($this->settingsHasFlag('timestamp', $settings)) { $this->timestamp = TRUE; } } public function check($value) { $dateString = $this->getDatetimeString($value); $isDate = FALSE; if ($dateString) { try { $dateObj = new \DateTime($dateString); $isDate = ($dateObj) ? TRUE : FALSE; } catch (\Exception $e) { $isDate = FALSE; } } return $isDate; } protected function useFilter($value) { $dateString = $this->getDatetimeString($value); $date = FALSE; if ($dateString) { $date = new \DateTime($dateString); if ($this->timestamp) { $date = $date->getTimestamp(); } } return $date; } private function getDatetimeString($value) { $match = preg_match('/^([0-9]{4})[-.]([0-9a-zA-Z]+)[-.]([0-9]{1,2})( +([0-9]{1,2})([-:]([0-9]{1,2})([-:]([0-9]{1,2}))?)?( *(AM|am|A|a|PM|pm|P|p))?)?$/', $value, $matches); $date = ''; if ($match) { $year = $matches[1]; $month = $this->complete($matches[2]); $day = $this->complete($matches[3]); $hours = $this->complete(isset($matches[5]) ? $matches[5] : ''); $minutes = $this->complete(isset($matches[7]) ? $matches[7] : ''); $seconds = $this->complete(isset($matches[9]) ? $matches[9] : ''); $hoursFormat = isset($matches[11]) ? $matches[11] : ''; if (strlen($hoursFormat) == 1) { $hoursFormat = $hoursFormat . 'M'; } $hoursFormat = strtoupper($hoursFormat); $date = $year . '-' . $month . '-' . $day . ' ' . $hours . ':' . $minutes . ':' . $seconds . $hoursFormat; } return $date; } private function complete($value) { $length = strlen($value); if ($length == 1) { $value = '0' . $value; } elseif ($length == 0) { $value = '00'; } return $value; } } namespace PhpOptions\Types; class DirectoryType extends AType { private $base = NULL; private $makeDir = FALSE; public function __construct($settings = array()) { parent::__construct($settings); if ($this->settingsHasFlag('makeDir', $settings)) { $this->makeDir = TRUE; } if (isset($settings[0])) { $this->base = $settings[0]; } } public function check($value) { $isDir = FALSE; if (is_dir($value)) { $isDir = TRUE; } elseif ($this->base && is_dir($this->make($this->base, $value))) { $isDir = TRUE; } if (!$isDir && $this->makeDir) { $value = $this->useFilter($value); if ($this->isFullPath($value)) { $isDir = mkdir($value, 0, TRUE); } } return $isDir; } protected function useFilter($value) { if ($this->base && !$this->isFullPath($value)) { $value = $this->make($this->base, $value); } $value = $this->make($value , '/'); return $value; } private function isFullPath($path) { return (bool)preg_match('/^([a-zA-Z]:\\\|\/)/', $path); } private function make() { $pathParts = func_get_args(); $ds = DIRECTORY_SEPARATOR; $path = implode($ds, $pathParts); $path = str_replace('/', $ds, $path); $path = str_replace('\\', $ds, $path); while (strpos($path, $ds . '.' . $ds) !== FALSE || strpos($path, $ds . $ds) !== FALSE) { $path = str_replace($ds . $ds, $ds, $path); $path = str_replace($ds . '.' . $ds, $ds, $path); } return $path; } } namespace PhpOptions\Types; class EmailType extends AType { public function check($value) { return (bool)preg_match('/[a-zA-Z0-9._%-]+@[a-zA-Z0-9.-]+[.][a-zA-Z]{2,4}/', $value); } } namespace PhpOptions\Types; class EnumType extends AType { private $values = array(); public function __construct($settings = array()) { parent::__construct($settings); $values = isset($settings[0]) ? $settings[0] : array(); if (!is_array($values)) { $values = preg_replace('/[,; |]+/', ',', $values); $values = explode(',', $values); $this->useFilter = FALSE; } $this->values = $values; } public function check($value) { return in_array($value, $this->values); } public function getName() { return '(' . implode('|', $this->values) . ')'; } protected function useFilter($value) { return array_search($value, $this->values); } } namespace PhpOptions\Types; class FileType extends AType { private $base = NULL; public function __construct($settings = array()) { parent::__construct($settings); if (isset($settings[0])) { $this->base = $settings[0]; } } public function check($value) { $isDir = FALSE; if (is_file($value)) { $isDir = TRUE; } elseif ($this->base && is_file($this->base . DIRECTORY_SEPARATOR . $value)) { $isDir = TRUE; } return $isDir; } protected function useFilter($value) { if ($this->base && !preg_match('/^([a-zA-Z]:\\\|\/)/', $value)) { $value = $this->make($this->base, $value); } $value = $this->make($value); return $value; } private function make() { $pathParts = func_get_args(); $ds = DIRECTORY_SEPARATOR; $path = implode($ds, $pathParts); $path = str_replace('/', $ds, $path); $path = str_replace('\\', $ds, $path); while (strpos($path, $ds . '.' . $ds) !== FALSE || strpos($path, $ds . $ds) !== FALSE) { $path = str_replace($ds . $ds, $ds, $path); $path = str_replace($ds . '.' . $ds, $ds, $path); } return $path; } } namespace PhpOptions\Types; class InifileType extends FileType { private $sections = TRUE; private $delimiters = ';|'; public function __construct($settings = array()) { parent::__construct($settings); if ($this->settingsHasFlag('notSections', $settings)) { $this->sections = FALSE; } } protected function useFilter($value) { $file = parent::useFilter($value); $content = parse_ini_file($file, $this->sections); if ($this->sections) { $content = $this->mergeParent($content); $contentTmp = array(); foreach ($content as $section => $values) { $contentTmp[$section] = $this->makeSubArray($values); } $content = $contentTmp; } else { $content = $this->makeSubArray($content); } return $content; } private function mergeParent($content) { $contentTmp = array(); foreach ($content as $section => $values) { $position = strpos($section, '<'); if ($position !== FALSE) { $child = trim(substr($section, 0, $position - 1)); $parent = trim(substr($section, $position + 1)); if ($child && $parent && isset($contentTmp[$parent])) { $section = $child; $values = array_merge($contentTmp[$parent], $values); } } $contentTmp[$section] = $values; } return $contentTmp; } private function makeSubArray($content) { $contentNew = array(); foreach ($content as $key => $value) { $keysNew = explode('.', $key); $contentNewPointer = &$contentNew; foreach ($keysNew as $keyNew) { if (!isset($contentNewPointer[$keyNew])) { $contentNewPointer[$keyNew] = array(); } $contentNewPointer = &$contentNewPointer[$keyNew]; } $value = preg_replace('/[' . $this->delimiters . ']+/', $this->delimiters[0], $value); $value = explode($this->delimiters[0], $value); $contentNewPointer = (count($value) == 1) ? $value[0] : $value; } return $contentNew; } } namespace PhpOptions\Types; class IntegerType extends AType { private $unsigned = FALSE; public function __construct($settings = array()) { parent::__construct($settings); if ($this->settingsHasFlag('unsigned', $settings)) { $this->unsigned = TRUE; } } public function check($value) { if ($this->unsigned) { return (bool) preg_match('/^[+]?[0-9]+$/', $value); } else { return (bool) preg_match('/^[-+]?[0-9]+$/', $value); } } public function getName() { return parent::getName() . ($this->unsigned ? ' UNSIGNED' : ''); } protected function useFilter($value) { return (integer)$value; } } namespace PhpOptions\Types; class RealType extends AType { private $unsigned = FALSE; public function __construct($settings = array()) { parent::__construct($settings); if ($this->settingsHasFlag('unsigned', $settings)) { $this->unsigned = TRUE; } } public function check($value) { if ($this->unsigned) { return (bool) preg_match('/^[+]?[0-9]+([.,][0-9]+)?$/', $value); } else { return (bool) preg_match('/^[-+]?[0-9]+([.,][0-9]+)?$/', $value); } } public function getName() { return parent::getName() . ($this->unsigned ? ' UNSIGNED' : ''); } protected function useFilter($value) { return (real)str_replace(',', '.', $value); } } namespace PhpOptions\Types; class SeriesType extends AType { private $delimiters = ', ;|'; public function __construct($settings = array()) { parent::__construct($settings); if (isset($settings[0])) { $this->delimiters = $settings[0]; } } public function getName() { return 'ARRAY'; } protected function useFilter($value) { if (is_array($value)) { return $value; } $value = preg_replace('/[' . $this->delimiters . ']+/', $this->delimiters[0], $value); return explode($this->delimiters[0], $value); } } namespace PhpOptions\Types; class StringType extends AType { } namespace PhpOptions\Types; class TimeType extends AType { public function check($value) { $dateString = $this->getTimeString($value); $isDate = FALSE; if ($dateString) { try { $dateObj = new \DateTime($dateString); $isDate = ($dateObj) ? TRUE : FALSE; } catch (\Exception $e) { $isDate = FALSE; } } return $isDate; } protected function useFilter($value) { return $this->getTimeString($value); } private function getTimeString($value) { $match = preg_match('/^([0-9]{1,2})([-:]([0-9]{1,2})([-:]([0-9]{1,2}))?)?( *(AM|am|A|a|PM|pm|P|p))?$/', $value, $matches); $date = ''; if ($match) { $hours = $this->complete(isset($matches[1]) ? $matches[1] : ''); $minutes = $this->complete(isset($matches[3]) ? $matches[3] : ''); $seconds = $this->complete(isset($matches[5]) ? $matches[5] : ''); $hoursFormat = isset($matches[7]) ? $matches[7] : ''; if (strlen($hoursFormat) == 1) { $hoursFormat = $hoursFormat . 'M'; } $hoursFormat = strtoupper($hoursFormat); $date = $hours . ':' . $minutes . ':' . $seconds . $hoursFormat; } return $date; } private function complete($value) { $length = strlen($value); if ($length == 1) { $value = '0' . $value; } elseif ($length == 0) { $value = '00'; } return $value; } } \ No newline at end of file + @license "New" BSD License */ namespace PhpOptions; class Arguments { private static $options = NULL; private static $arguments = NULL; public static function options() { self::setAll(); return self::$options; } public static function getArguments() { self::setAll(); return self::$arguments; } private static function setAll() { if (is_null(self::$options) || is_null(self::$arguments)) { $all = self::readAll(); self::$options = $all['options']; self::$arguments = $all['arguments']; } } private static function readAll() { $cmdOptions = array(); $cmdArguments = array(); $args = $_SERVER['argv']; array_shift($args); if (count($args) > 0) { $argsClean = array(); foreach ($args as $arg) { $position = strpos($arg, '='); if ($position === 0) { $argsClean[] = substr($arg, 1); } elseif ($position !== FALSE) { $argsClean[] = substr($arg, 0, $position); $argsClean[] = substr($arg, $position + 1); } else { $argsClean[] = $arg; } } $args = $argsClean; $previous = NULL; foreach ($args as $arg) { if (substr($arg, 0, 2) == '--') { $option = substr($arg, 2); $cmdOptions[$option] = TRUE; $previous = $option; } elseif (substr($arg, 0, 1) == '-' && !(preg_match('/^-[0-9]+([.,][0-9]+)?$/', $arg))) { foreach (str_split(substr($arg, 1)) as $char) { $cmdOptions[$char] = TRUE; $previous = $char; } } elseif ($previous) { $cmdOptions[$previous] = $arg; $previous = NULL; } else { $cmdArguments[] = $arg; } } } return array('options' => $cmdOptions, 'arguments' => $cmdArguments); } } namespace PhpOptions; class InvalidArgumentException extends \Exception { } class LogicException extends \Exception { } class UserBadCallException extends \Exception { } namespace PhpOptions; class Option { const VALUE_NO = 'value_no'; const VALUE_REQUIRE = 'value_require'; const VALUE_OPTIONAL = 'value_optional'; const HELP_INDENT_LENGTH = 4; private static $types = NULL; private $name; private $type = NULL; private $value = NULL; private $short; private $long; private $defaults = NULL; private $required = FALSE; private $valueRequired = self::VALUE_NO; private $description = ''; private $needed = array(); public function __construct($name) { if (!$name) { throw new InvalidArgumentException('Name of option cannot be empty.'); } $this->name = $name; $long = strtolower($name); $long = preg_replace('/[^a-z0-9]+/', '-', $long); $long = preg_replace('/-+/', '-', $long); $this->long($long); $this->short(substr($long, 0, 1)); } public static function make($name) { return new Option($name); } public static function __callStatic($type, $settings) { $name = (isset($settings[0])) ? array_shift($settings) : ''; $option = self::make($name); $option->type = self::getTypes()->getType($type, $settings); $option->value(); return $option; } public static function registerType($name, $className, $classPath) { self::getTypes()->register($name, $className, $classPath); } public function short($short = NULL) { if (is_null($short) && is_null($this->long)) { throw new LogicException($this->name . ': Short and long varint cannot be undefined together.'); } if (!is_null($short) && strlen($short) != 1) { throw new InvalidArgumentException($this->name . ': Short variant has to be only one character.'); } $this->short = $short; return $this; } public function long($long = NULL) { if (is_null($long) && is_null($this->short)) { throw new LogicException($this->name . ': Short and long varint cannot be undefined together.'); } $this->long = $long; return $this; } public function defaults($defaults = NULL) { if (!is_null($defaults) && !( ($this->valueRequired == self::VALUE_OPTIONAL) || ($this->valueRequired == self::VALUE_REQUIRE && $this->required == FALSE) )) { throw new LogicException($this->name . ': The default value makes sense only for options with optional value or optional option with optional or required value.'); } $this->defaults = $defaults; return $this; } public function required($required = TRUE) { if ($this->valueRequired == self::VALUE_REQUIRE && !is_null($this->defaults)) { throw new LogicException($this->name . ': The required option does not make sense for option with default value and required value.'); } $this->required = (bool)$required; return $this; } public function value($value = TRUE) { $value = ((bool)$value) ? self::VALUE_REQUIRE : self::VALUE_OPTIONAL; if (!is_null($this->defaults) && $value != self::VALUE_OPTIONAL) { throw new LogicException($this->name . ': The require/non value makes sense only for option without default value.'); } $this->valueRequired = $value; return $this; } public function description($description = '') { $this->description = $description; return $this; } public function dependences($needed) { $this->needed = $needed; return $this; } public function getName() { return $this->name; } public function getShort() { return $this->short; } public function getLong() { return $this->long; } public function getDefaults() { return $this->defaults; } public function getValue($isDefaultSet = FALSE) { if (is_null($this->value)) { $this->value = $this->readValue($isDefaultSet); } return $this->value; } public function getOptions($value = '') { $options = ''; $options .= ($this->short ? '-' . $this->short . $value : ''); $options .= ($this->short && $this->long ? ', ' : ''); $options .= ($this->long ? '--' . $this->long . $value : ''); return $options; } public function getHelp($maxLength, $indent = 0) { $indentString = str_repeat(' ', self::HELP_INDENT_LENGTH); if ($indent) { $indent = implode('', array_fill(0, $indent, $indentString)); } else { $indent = ''; } $valueType = 'VALUE'; if ($this->type) { $valueType = $this->type->getName(); } switch ($this->valueRequired) { case self::VALUE_NO: $value = ''; break; case self::VALUE_OPTIONAL: $value = '[="' . $valueType . '"]'; break; case self::VALUE_REQUIRE: $value = '="' . $valueType . '"'; break; } $help = $this->getOptions($value); if (!$this->required) { $help = '[' . $help . ']'; } $help = $this->wordwrap($help, $maxLength, $indent); if (!is_null($this->defaults)) { switch (gettype($this->defaults)) { case 'boolean': $defaults = $this->defaults ? 'TRUE' : 'FALSE'; break; case 'array': $defaults = 'array(' . implode(',', $this->defaults) . ')'; break; default: $defaults = $this->defaults; break; } $help .= PHP_EOL . $this->wordwrap('DEFAULT="' . $defaults . '"', $maxLength, $indentString . $indent); } if (count($this->needed) > 0) { $helpNeeded = array(); foreach ($this->needed as $neededOption) { $helpNeeded[] = $neededOption->getOptions(); } $help .= PHP_EOL . $this->wordwrap('NEEDED: ' . implode('; ', $helpNeeded), $maxLength, $indentString . $indent); } if ($this->description) { $help .= PHP_EOL . $this->wordwrap(str_replace(PHP_EOL, PHP_EOL . $indentString . $indent, $this->description), $maxLength, $indentString . $indent); } return $help; } private static function getTypes() { if (!self::$types) { self::$types = new Types\Types(); } return self::$types; } private function readValue($isDefaultSet) { $options = Arguments::options(); $short = isset($options[$this->short]) ? $options[$this->short] : FALSE; $long = isset($options[$this->long]) ? $options[$this->long] : FALSE; if ($short !== FALSE && $long !== FALSE) { throw new UserBadCallException($this->getOptions() . ': Option has value set by short and long variant.'); } elseif ($short === FALSE && $long === FALSE) { $value = FALSE; } elseif ($short !== FALSE) { $value = $short; } else { $value = $long; } if (!$isDefaultSet && $this->required && $value === FALSE) { throw new UserBadCallException($this->getOptions() . ': Option is required.'); } switch ($this->valueRequired) { case self::VALUE_NO: if (!is_bool($value)) { throw new UserBadCallException($this->getOptions() . ': Option has value, but any is expected.'); } break; case self::VALUE_OPTIONAL: if (is_bool($value) && !is_null($this->defaults)) { $value = $this->defaults; } break; case self::VALUE_REQUIRE: if ($value === TRUE) { throw new UserBadCallException($this->getOptions() . ': Option has require value, but no set.'); } else if ($value === FALSE && !is_null($this->defaults)) { $value = $this->defaults; } break; } if (($value !== FALSE) && !is_null($this->type)) { if (!$this->type->check($value)) { throw new UserBadCallException($this->getOptions() . ': Option has bad format.'); } if (($this->valueRequired != self::VALUE_OPTIONAL) || !is_bool($value)) { $value = $this->type->filter($value); } } return $value; } private function wordwrap($string, $maxLength, $prefix) { $string = wordwrap($string, $maxLength - strlen($prefix), PHP_EOL, FALSE); $strings = explode(PHP_EOL, $string); array_walk($strings, function (&$item, $key, $prefix) { $item = $prefix . trim($item); }, $prefix ); $string = implode(PHP_EOL, $strings); return $string; } } namespace PhpOptions; class Options { const VERSION = '1.3.0'; const HELP_MAX_LENGTH = 75; private $options = array(); private $optionsValues = array(); private $optionsShorts = array(); private $optionsLongs = array(); private $defaults = NULL; private $description = ''; private $groups = array(); public function __construct() { if (php_sapi_name() !== 'cli') { throw new UserBadCallException('Script have to run from command line.'); } } public static function arguments() { return Arguments::getArguments(); } public function add($options = array()) { if (!is_array($options)) { $options = array($options); } foreach ($options as $option) { $this->addOne($option); } return $this; } public function defaults($name) { if (!isset($this->options[$name])) { throw new InvalidArgumentException($name . ': Unknown option.'); } $value = $this->options[$name]->getDefaults(); $this->defaults['name'] = $name; $this->defaults['value'] = $value; if (is_null($value)) { $this->defaults['value'] = TRUE; } return $this; } public function description($description) { $this->description = $description; return $this; } public function get($name) { $nameInput = $name; if (substr($name, 0, 2) == '--') { $long = substr($name, 2); $name = isset($this->optionsLongs[$long]) ? $this->optionsLongs[$long] : NULL; } elseif (substr($name, 0, 1) == '-') { $short = substr($name, 1); $name = isset($this->optionsShorts[$short]) ? $this->optionsShorts[$short] : NULL; } if (!isset($this->optionsValues[$name])) { throw new InvalidArgumentException($nameInput . ': Unknown option.'); } if (!is_null($this->defaults) && ($this->defaults['name'] == $name) && (count(Arguments::options()) == 0)) { return $this->defaults['value']; } return $this->optionsValues[$name]; } public function dependences($main, $needed, $groupName = NULL) { if (!is_array($needed)) { $needed = array($needed); } if (!isset($this->optionsValues[$main])) { throw new InvalidArgumentException($main . ': Unknown option.'); } $neededOptions = array(); foreach ($needed as $name) { if (!isset($this->optionsValues[$name])) { throw new InvalidArgumentException($name . ': Unknown option.'); } $neededOptions[] = $this->options[$name]; } if ($this->get($main) !== FALSE) { foreach ($needed as $name) { if ($this->get($name) === FALSE) { $mainOptions = $this->options[$main]->getOptions(); $nameOptions = $this->options[$name]->getOptions(); throw new UserBadCallException('Option "' . $mainOptions . '" needs option "'. $nameOptions . '".'); } } } $this->options[$main]->dependences($neededOptions); if ($groupName) { array_unshift($needed, $main); $this->group($groupName, $needed); } return $this; } public function group($name, $options) { if (in_array($name, array_keys($this->groups))) { throw new LogicException($name . ': Group already exists.'); } if (!is_array($options)) { $options = array($options); } foreach ($options as $optionName) { if (!isset($this->options[$optionName])) { throw new LogicException($optionName . ': Option does not exist.'); } } $this->groups[$name] = $options; return $this; } public function getHelp($maxLength = self::HELP_MAX_LENGTH) { $help = $this->wordwrap($this->description, $maxLength) . PHP_EOL . PHP_EOL; $optionsNongroup = $this->options; $indent = 0; if ($this->groups) { foreach ($this->groups as $groupName => $optionsNames) { $help .= $this->wordwrap($groupName, $maxLength) . PHP_EOL; foreach ($optionsNames as $optionName) { $help .= $this->options[$optionName]->getHelp($maxLength, 1) . PHP_EOL; if (isset($optionsNongroup[$optionName])) { unset($optionsNongroup[$optionName]); } } } if (count($optionsNongroup) > 0) { $help .= PHP_EOL . $this->wordwrap('NON GROUP OPTIONS:', $maxLength) . PHP_EOL; } $indent = 1; } foreach ($optionsNongroup as $option) { $help .= $option->getHelp($maxLength, $indent) . PHP_EOL; } return $help; } private function addOne(Option $option) { $this->checkConflicts($option); $name = $option->getName(); $this->options[$name] = $option; $this->optionsValues[$name] = $option->getValue((bool)($this->defaults['value'])); if ($option->getShort()) { $this->optionsShorts[$option->getShort()] = $name; } if ($option->getLong()) { $this->optionsLongs[$option->getLong()] = $name; } } private function checkConflicts(Option $option) { $name = $option->getName(); if (isset($this->options[$name])) { throw new LogicException($name . ': Option already exists.'); } $short = $option->getShort(); if (in_array($short, array_keys($this->optionsShorts))) { throw new LogicException($name . ': Option with short variant "' . $short . '" already exists.'); } $long = $option->getLong(); if (in_array($long, array_keys($this->optionsLongs))) { throw new LogicException($name . ': Option with long variant "' . $long . '" already exists.'); } } private function wordwrap($string, $maxLength) { return wordwrap($string, $maxLength, PHP_EOL, TRUE); } } namespace PhpOptions\Types; abstract class AType { protected $useFilter = TRUE; public function __construct(&$settings = array()) { if ($this->settingsHasFlag('notFilter', $settings)) { $this->useFilter = FALSE; } } public function check($value) { return TRUE; } public function getName() { $className = get_class($this); $start = strrpos($className, '\\') + 1; $name = substr($className, $start, -4); return strtoupper($name); } final public function filter($value) { if ($this->useFilter) { return $this->useFilter($value); } else { return $value; } } protected function useFilter($value) { return $value; } protected function settingsHasFlag($flag, &$settings) { $flag = strtolower($flag); $settingsLower = $settings; array_walk($settingsLower, function (&$item, $key) { if (is_string($item)) { $item = strtolower($item); } }); $flagIdx = array_search($flag, $settingsLower); if ($flagIdx !== FALSE) { $hasFlag = TRUE; unset($settings[$flagIdx]); $settings = array_values($settings); } else { $hasFlag = FALSE; } return $hasFlag; } } namespace PhpOptions\Types; class Types { private $registeredTypes = array(); private static $serializedDeafultTypes = 'a:13:{s:4:"Char";a:2:{s:9:"className";s:26:"\PhpOptions\Types\CharType";s:9:"classPath";s:63:"C:\DATA\Viktor\Develop\PhpOptions\PhpOptions\Types\CharType.php";}s:4:"Date";a:2:{s:9:"className";s:26:"\PhpOptions\Types\DateType";s:9:"classPath";s:63:"C:\DATA\Viktor\Develop\PhpOptions\PhpOptions\Types\DateType.php";}s:8:"Datetime";a:2:{s:9:"className";s:30:"\PhpOptions\Types\DatetimeType";s:9:"classPath";s:67:"C:\DATA\Viktor\Develop\PhpOptions\PhpOptions\Types\DatetimeType.php";}s:9:"Directory";a:2:{s:9:"className";s:31:"\PhpOptions\Types\DirectoryType";s:9:"classPath";s:68:"C:\DATA\Viktor\Develop\PhpOptions\PhpOptions\Types\DirectoryType.php";}s:5:"Email";a:2:{s:9:"className";s:27:"\PhpOptions\Types\EmailType";s:9:"classPath";s:64:"C:\DATA\Viktor\Develop\PhpOptions\PhpOptions\Types\EmailType.php";}s:4:"Enum";a:2:{s:9:"className";s:26:"\PhpOptions\Types\EnumType";s:9:"classPath";s:63:"C:\DATA\Viktor\Develop\PhpOptions\PhpOptions\Types\EnumType.php";}s:4:"File";a:2:{s:9:"className";s:26:"\PhpOptions\Types\FileType";s:9:"classPath";s:63:"C:\DATA\Viktor\Develop\PhpOptions\PhpOptions\Types\FileType.php";}s:7:"Inifile";a:2:{s:9:"className";s:29:"\PhpOptions\Types\InifileType";s:9:"classPath";s:66:"C:\DATA\Viktor\Develop\PhpOptions\PhpOptions\Types\InifileType.php";}s:7:"Integer";a:2:{s:9:"className";s:29:"\PhpOptions\Types\IntegerType";s:9:"classPath";s:66:"C:\DATA\Viktor\Develop\PhpOptions\PhpOptions\Types\IntegerType.php";}s:4:"Real";a:2:{s:9:"className";s:26:"\PhpOptions\Types\RealType";s:9:"classPath";s:63:"C:\DATA\Viktor\Develop\PhpOptions\PhpOptions\Types\RealType.php";}s:6:"Series";a:2:{s:9:"className";s:28:"\PhpOptions\Types\SeriesType";s:9:"classPath";s:65:"C:\DATA\Viktor\Develop\PhpOptions\PhpOptions\Types\SeriesType.php";}s:6:"String";a:2:{s:9:"className";s:28:"\PhpOptions\Types\StringType";s:9:"classPath";s:65:"C:\DATA\Viktor\Develop\PhpOptions\PhpOptions\Types\StringType.php";}s:4:"Time";a:2:{s:9:"className";s:26:"\PhpOptions\Types\TimeType";s:9:"classPath";s:63:"C:\DATA\Viktor\Develop\PhpOptions\PhpOptions\Types\TimeType.php";}}'; public function __construct() { foreach ($this->getDefaultTypes() as $name => $class) { $this->register($name, $class['className'], $class['classPath']); } } public function register($name, $className, $classPath) { $name = strtolower($name); $this->registeredTypes[$name]['className'] = $className; $this->registeredTypes[$name]['classPath'] = $classPath; } public function getType($type, $settings) { if (!isset($this->registeredTypes[$type])) { throw new \PhpOptions\InvalidArgumentException($type . ': Undefined type of option.'); } $className = $this->registeredTypes[$type]['className']; $typeClass = new $className($settings); if (!($typeClass instanceof \PhpOptions\Types\AType)) { throw new \PhpOptions\InvalidArgumentException($type . ': Type have to be instance of \PhpOptions\Types\AType.'); } return $typeClass; } public function getDefaultTypes() { if (self::$serializedDeafultTypes) { return unserialize(self::$serializedDeafultTypes); } $types = array(); $files = scandir(__DIR__); foreach ($files as $file) { if (substr($file, -8) == 'Type.php') { $nameOfType = substr($file, 0, -8); $className = '\\PhpOptions\\Types\\' . substr($file, 0, -4); $types[$nameOfType]['className'] = $className; $types[$nameOfType]['classPath'] = __DIR__ . DIRECTORY_SEPARATOR . $file; } } unset($types['A']); return $types; } } namespace PhpOptions\Types; class CharType extends AType { public function check($value) { return (bool)(strlen($value) == 1); } } namespace PhpOptions\Types; class DateType extends AType { private $timestamp = FALSE; public function __construct($settings = array()) { parent::__construct($settings); if ($this->settingsHasFlag('timestamp', $settings)) { $this->timestamp = TRUE; } } public function check($value) { $dateString = $this->getDatetimeString($value); $isDate = FALSE; if ($dateString) { try { $dateObj = new \DateTime($dateString); $isDate = ($dateObj) ? TRUE : FALSE; } catch (\Exception $e) { $isDate = FALSE; } } return $isDate; } protected function useFilter($value) { $dateString = $this->getDatetimeString($value); $date = FALSE; if ($dateString) { $date = new \DateTime($dateString); if ($this->timestamp) { $date = $date->getTimestamp(); } } return $date; } private function getDatetimeString($value) { $match = preg_match('/^([0-9]{4})[-.]([0-9a-zA-Z]+)[-.]([0-9]{1,2})$/', $value, $matches); $date = ''; if ($match) { $year = $matches[1]; $month = $this->complete($matches[2]); $day = $this->complete($matches[3]); $date = $year . '-' . $month . '-' . $day . ' 00:00:00'; } return $date; } private function complete($value) { if (strlen($value) == 1) { $value = '0' . $value; } return $value; } } namespace PhpOptions\Types; class DatetimeType extends AType { private $timestamp = FALSE; public function __construct($settings = array()) { parent::__construct($settings); if ($this->settingsHasFlag('timestamp', $settings)) { $this->timestamp = TRUE; } } public function check($value) { $dateString = $this->getDatetimeString($value); $isDate = FALSE; if ($dateString) { try { $dateObj = new \DateTime($dateString); $isDate = ($dateObj) ? TRUE : FALSE; } catch (\Exception $e) { $isDate = FALSE; } } return $isDate; } protected function useFilter($value) { $dateString = $this->getDatetimeString($value); $date = FALSE; if ($dateString) { $date = new \DateTime($dateString); if ($this->timestamp) { $date = $date->getTimestamp(); } } return $date; } private function getDatetimeString($value) { $match = preg_match('/^([0-9]{4})[-.]([0-9a-zA-Z]+)[-.]([0-9]{1,2})( +([0-9]{1,2})([-:]([0-9]{1,2})([-:]([0-9]{1,2}))?)?( *(AM|am|A|a|PM|pm|P|p))?)?$/', $value, $matches); $date = ''; if ($match) { $year = $matches[1]; $month = $this->complete($matches[2]); $day = $this->complete($matches[3]); $hours = $this->complete(isset($matches[5]) ? $matches[5] : ''); $minutes = $this->complete(isset($matches[7]) ? $matches[7] : ''); $seconds = $this->complete(isset($matches[9]) ? $matches[9] : ''); $hoursFormat = isset($matches[11]) ? $matches[11] : ''; if (strlen($hoursFormat) == 1) { $hoursFormat = $hoursFormat . 'M'; } $hoursFormat = strtoupper($hoursFormat); $date = $year . '-' . $month . '-' . $day . ' ' . $hours . ':' . $minutes . ':' . $seconds . $hoursFormat; } return $date; } private function complete($value) { $length = strlen($value); if ($length == 1) { $value = '0' . $value; } elseif ($length == 0) { $value = '00'; } return $value; } } namespace PhpOptions\Types; class DirectoryType extends AType { private $base = NULL; private $makeDir = FALSE; public function __construct($settings = array()) { parent::__construct($settings); if ($this->settingsHasFlag('makeDir', $settings)) { $this->makeDir = TRUE; } if (isset($settings[0])) { $this->base = $settings[0]; } } public function check($value) { $isDir = FALSE; if (is_dir($value)) { $isDir = TRUE; } elseif ($this->base && is_dir($this->make($this->base, $value))) { $isDir = TRUE; } if (!$isDir && $this->makeDir) { $value = $this->useFilter($value); if ($this->isFullPath($value)) { $isDir = mkdir($value, 0700, TRUE); } } return $isDir; } protected function useFilter($value) { if ($this->base && !$this->isFullPath($value)) { $value = $this->make($this->base, $value); } $value = $this->make($value , '/'); return $value; } private function isFullPath($path) { return (bool)preg_match('/^([a-zA-Z]:\\\|\/)/', $path); } private function make() { $pathParts = func_get_args(); $ds = DIRECTORY_SEPARATOR; $path = implode($ds, $pathParts); $path = str_replace('/', $ds, $path); $path = str_replace('\\', $ds, $path); while (strpos($path, $ds . '.' . $ds) !== FALSE || strpos($path, $ds . $ds) !== FALSE) { $path = str_replace($ds . $ds, $ds, $path); $path = str_replace($ds . '.' . $ds, $ds, $path); } return $path; } } namespace PhpOptions\Types; class EmailType extends AType { public function check($value) { return (bool)preg_match('/[a-zA-Z0-9._%-]+@[a-zA-Z0-9.-]+[.][a-zA-Z]{2,4}/', $value); } } namespace PhpOptions\Types; class EnumType extends AType { private $values = array(); public function __construct($settings = array()) { parent::__construct($settings); $values = isset($settings[0]) ? $settings[0] : array(); if (!is_array($values)) { $values = preg_replace('/[,; |]+/', ',', $values); $values = explode(',', $values); $this->useFilter = FALSE; } $this->values = $values; } public function check($value) { return in_array($value, $this->values); } public function getName() { return '(' . implode('|', $this->values) . ')'; } protected function useFilter($value) { return array_search($value, $this->values); } } namespace PhpOptions\Types; class FileType extends AType { private $base = NULL; public function __construct($settings = array()) { parent::__construct($settings); if (isset($settings[0])) { $this->base = $settings[0]; } } public function check($value) { $isDir = FALSE; if (is_file($value)) { $isDir = TRUE; } elseif ($this->base && is_file($this->base . DIRECTORY_SEPARATOR . $value)) { $isDir = TRUE; } return $isDir; } protected function useFilter($value) { if ($this->base && !preg_match('/^([a-zA-Z]:\\\|\/)/', $value)) { $value = $this->make($this->base, $value); } $value = $this->make($value); return $value; } private function make() { $pathParts = func_get_args(); $ds = DIRECTORY_SEPARATOR; $path = implode($ds, $pathParts); $path = str_replace('/', $ds, $path); $path = str_replace('\\', $ds, $path); while (strpos($path, $ds . '.' . $ds) !== FALSE || strpos($path, $ds . $ds) !== FALSE) { $path = str_replace($ds . $ds, $ds, $path); $path = str_replace($ds . '.' . $ds, $ds, $path); } return $path; } } namespace PhpOptions\Types; class InifileType extends FileType { private $sections = TRUE; private $delimiters = ';|'; public function __construct($settings = array()) { parent::__construct($settings); if ($this->settingsHasFlag('notSections', $settings)) { $this->sections = FALSE; } } protected function useFilter($value) { $file = parent::useFilter($value); $content = parse_ini_file($file, $this->sections); if ($this->sections) { $content = $this->mergeParent($content); $contentTmp = array(); foreach ($content as $section => $values) { $contentTmp[$section] = $this->makeSubArray($values); } $content = $contentTmp; } else { $content = $this->makeSubArray($content); } return $content; } private function mergeParent($content) { $contentTmp = array(); foreach ($content as $section => $values) { $position = strpos($section, '<'); if ($position !== FALSE) { $child = trim(substr($section, 0, $position - 1)); $parent = trim(substr($section, $position + 1)); if ($child && $parent && isset($contentTmp[$parent])) { $section = $child; $values = array_merge($contentTmp[$parent], $values); } } $contentTmp[$section] = $values; } return $contentTmp; } private function makeSubArray($content) { $contentNew = array(); foreach ($content as $key => $value) { $keysNew = explode('.', $key); $contentNewPointer = &$contentNew; foreach ($keysNew as $keyNew) { if (!isset($contentNewPointer[$keyNew])) { $contentNewPointer[$keyNew] = array(); } $contentNewPointer = &$contentNewPointer[$keyNew]; } $value = preg_replace('/[' . $this->delimiters . ']+/', $this->delimiters[0], $value); $value = explode($this->delimiters[0], $value); $contentNewPointer = (count($value) == 1) ? $value[0] : $value; } return $contentNew; } } namespace PhpOptions\Types; class IntegerType extends AType { private $unsigned = FALSE; public function __construct($settings = array()) { parent::__construct($settings); if ($this->settingsHasFlag('unsigned', $settings)) { $this->unsigned = TRUE; } } public function check($value) { if ($this->unsigned) { return (bool) preg_match('/^[+]?[0-9]+$/', $value); } else { return (bool) preg_match('/^[-+]?[0-9]+$/', $value); } } public function getName() { return parent::getName() . ($this->unsigned ? ' UNSIGNED' : ''); } protected function useFilter($value) { return (integer)$value; } } namespace PhpOptions\Types; class RealType extends AType { private $unsigned = FALSE; public function __construct($settings = array()) { parent::__construct($settings); if ($this->settingsHasFlag('unsigned', $settings)) { $this->unsigned = TRUE; } } public function check($value) { if ($this->unsigned) { return (bool) preg_match('/^[+]?[0-9]+([.,][0-9]+)?$/', $value); } else { return (bool) preg_match('/^[-+]?[0-9]+([.,][0-9]+)?$/', $value); } } public function getName() { return parent::getName() . ($this->unsigned ? ' UNSIGNED' : ''); } protected function useFilter($value) { return (real)str_replace(',', '.', $value); } } namespace PhpOptions\Types; class SeriesType extends AType { private $delimiters = ', ;|'; public function __construct($settings = array()) { parent::__construct($settings); if (isset($settings[0])) { $this->delimiters = $settings[0]; } } public function getName() { return 'ARRAY'; } protected function useFilter($value) { if (is_array($value)) { return $value; } $value = preg_replace('/[' . $this->delimiters . ']+/', $this->delimiters[0], $value); return explode($this->delimiters[0], $value); } } namespace PhpOptions\Types; class StringType extends AType { } namespace PhpOptions\Types; class TimeType extends AType { public function check($value) { $dateString = $this->getTimeString($value); $isDate = FALSE; if ($dateString) { try { $dateObj = new \DateTime($dateString); $isDate = ($dateObj) ? TRUE : FALSE; } catch (\Exception $e) { $isDate = FALSE; } } return $isDate; } protected function useFilter($value) { return $this->getTimeString($value); } private function getTimeString($value) { $match = preg_match('/^([0-9]{1,2})([-:]([0-9]{1,2})([-:]([0-9]{1,2}))?)?( *(AM|am|A|a|PM|pm|P|p))?$/', $value, $matches); $date = ''; if ($match) { $hours = $this->complete(isset($matches[1]) ? $matches[1] : ''); $minutes = $this->complete(isset($matches[3]) ? $matches[3] : ''); $seconds = $this->complete(isset($matches[5]) ? $matches[5] : ''); $hoursFormat = isset($matches[7]) ? $matches[7] : ''; if (strlen($hoursFormat) == 1) { $hoursFormat = $hoursFormat . 'M'; } $hoursFormat = strtoupper($hoursFormat); $date = $hours . ':' . $minutes . ':' . $seconds . $hoursFormat; } return $date; } private function complete($value) { $length = strlen($value); if ($length == 1) { $value = '0' . $value; } elseif ($length == 0) { $value = '00'; } return $value; } } \ No newline at end of file diff --git a/PhpOptions/Arguments.php b/PhpOptions/Arguments.php index 3a036bd..f1cbce4 100644 --- a/PhpOptions/Arguments.php +++ b/PhpOptions/Arguments.php @@ -59,7 +59,7 @@ public static function options() * * @return array */ - public static function arguments() + public static function getArguments() { self::setAll(); return self::$arguments; diff --git a/PhpOptions/Options.php b/PhpOptions/Options.php index d9591a3..efc99a5 100644 --- a/PhpOptions/Options.php +++ b/PhpOptions/Options.php @@ -23,7 +23,7 @@ class Options /** * Version of PhpOptions */ - const VERSION = '1.2.0'; + const VERSION = '1.3.0'; /** * Max length of one line @@ -101,7 +101,7 @@ public function __construct() */ public static function arguments() { - return Arguments::arguments(); + return Arguments::getArguments(); } diff --git a/PhpOptions/Types/DirectoryType.php b/PhpOptions/Types/DirectoryType.php index 9df03ac..ee64ba9 100644 --- a/PhpOptions/Types/DirectoryType.php +++ b/PhpOptions/Types/DirectoryType.php @@ -81,7 +81,7 @@ public function check($value) $value = $this->useFilter($value); if ($this->isFullPath($value)) { - $isDir = mkdir($value, 0, TRUE); + $isDir = mkdir($value, 0700, TRUE); } } diff --git a/Tools/Runner.php b/Tools/Runner.php index 55a17d9..0b287d9 100644 --- a/Tools/Runner.php +++ b/Tools/Runner.php @@ -180,8 +180,7 @@ private function runTestsUnit() $coverage = $this->setDirSep(DATA_TOOLS . '/Coverage'); $tests = $this->setDirSep(TESTS_TOOLS . '/Unit'); $this->setArguments('boot.php', - '--strict - --coverage-html ' . $coverage . ' + '--coverage-html ' . $coverage . ' ' . $tests ); \PHPUnit_TextUI_Command::main(FALSE); @@ -204,8 +203,7 @@ private function runTestsRegression() // run tests $tests = $this->setDirSep(TESTS_TOOLS . '/Regression'); $this->setArguments('boot.php', - '--strict - ' . $tests + $tests ); \PHPUnit_TextUI_Command::main(FALSE); @@ -229,8 +227,7 @@ private function runTestsMinifing() // run tests $tests = $this->setDirSep(TESTS_TOOLS . '/Minifing'); $this->setArguments('boot.php', - '--strict - ' . $tests + $tests ); \PHPUnit_TextUI_Command::main(FALSE); diff --git a/Tools/Tests/Unit/Arguments/ArgumentsTest.php b/Tools/Tests/Unit/Arguments/ArgumentsTest.php index 0173cb9..8b9bb9d 100644 --- a/Tools/Tests/Unit/Arguments/ArgumentsTest.php +++ b/Tools/Tests/Unit/Arguments/ArgumentsTest.php @@ -18,7 +18,7 @@ * * @author Viktor Mašíček * - * @covers PhpOptions\Arguments::arguments + * @covers PhpOptions\Arguments::getArguments * @covers PhpOptions\Arguments::setAll * @covers PhpOptions\Arguments::readAll */ @@ -35,7 +35,7 @@ public function test($arguments, $expectedOptions) $this->setPropertyValue('Arguments', 'PhpOptions\Arguments::$options', NULL); $this->setArguments($arguments); - $this->assertEquals($expectedOptions, Arguments::arguments()); + $this->assertEquals($expectedOptions, Arguments::getArguments()); }