public function setStaticPropertyValue(string $propertyName, $value) : void
    {
        $property = $this->getProperty($propertyName);

        if (! $property || ! $property->isStatic()) {
            throw PropertyDoesNotExist::fromName($propertyName);
        }

        $property->setValue($value);
    }

public function setStaticPropertyValue ( string $ propertyName , $ value ) : void { $ property = $ this -> getProperty ( $ propertyName ) ; if ( ! $ property || ! $ property -> isStatic ( ) ) { throw PropertyDoesNotExist :: fromName ( $ propertyName ) ; } $ property -> setValue ( $ value ) ; }

Set the value of a static property

@param mixed $value

@throws ClassDoesNotExist
@throws NoObjectProvided
@throws NotAnObject
@throws ObjectNotInstanceOfClass


public function setFinal(bool $isFinal) : void
    {
        if (! $this->node instanceof ClassNode) {
            throw NotAClassReflection::fromReflectionClass($this);
        }

        if ($isFinal === true) {
            $this->node->flags |= ClassNode::MODIFIER_FINAL;

            return;
        }

        $this->node->flags &= ~ClassNode::MODIFIER_FINAL;
    }

public function setFinal ( bool $ isFinal ) : void { if ( ! $ this -> node instanceof ClassNode ) { throw NotAClassReflection :: fromReflectionClass ( $ this ) ; } if ( $ isFinal === true ) { $ this -> node -> flags |= ClassNode :: MODIFIER_FINAL ; return ; } $ this -> node -> flags &= ~ ClassNode :: MODIFIER_FINAL ; }

Set whether this class is final or not

@throws NotAClassReflection


public function removeMethod(string $methodName) : bool
    {
        $lowerName = strtolower($methodName);
        foreach ($this->node->stmts as $key => $stmt) {
            if ($stmt instanceof ClassMethod && $lowerName === $stmt->name->toLowerString()) {
                unset($this->node->stmts[$key], $this->cachedMethods);

                return true;
            }
        }

        return false;
    }

public function removeMethod ( string $ methodName ) : bool { $ lowerName = strtolower ( $ methodName ) ; foreach ( $ this -> node -> stmts as $ key => $ stmt ) { if ( $ stmt instanceof ClassMethod && $ lowerName === $ stmt -> name -> toLowerString ( ) ) { unset ( $ this -> node -> stmts [ $ key ] , $ this -> cachedMethods ) ; return true ; } } return false ; }

Remove the named method from the class.

Returns true if method was successfully removed.
Returns false if method was not found, or could not be removed.

Remove the named method from the class .


public function addMethod(string $methodName) : void
    {
        $this->node->stmts[] = new ClassMethod($methodName);
        unset($this->cachedMethods);
    }

public function addMethod ( string $ methodName ) : void { $ this -> node -> stmts [ ] = new ClassMethod ( $ methodName ) ; unset ( $ this -> cachedMethods ) ; }


public function addProperty(
        string $propertyName,
        int $visibility = CoreReflectionProperty::IS_PUBLIC,
        bool $static = false
    ) : void {
        $type = 0;
        switch ($visibility) {
            case CoreReflectionProperty::IS_PRIVATE:
                $type |= ClassNode::MODIFIER_PRIVATE;
                break;
            case CoreReflectionProperty::IS_PROTECTED:
                $type |= ClassNode::MODIFIER_PROTECTED;
                break;
            default:
                $type |= ClassNode::MODIFIER_PUBLIC;
                break;
        }

        if ($static) {
            $type |= ClassNode::MODIFIER_STATIC;
        }

        $this->node->stmts[]             = new PropertyNode($type, [new Node\Stmt\PropertyProperty($propertyName)]);
        $this->cachedProperties          = null;
        $this->cachedImmediateProperties = null;
    }

public function addProperty ( string $ propertyName , int $ visibility = CoreReflectionProperty :: IS_PUBLIC , bool $ static = false ) : void { $ type = 0 ; switch ( $ visibility ) { case CoreReflectionProperty :: IS_PRIVATE : $ type |= ClassNode :: MODIFIER_PRIVATE ; break ; case CoreReflectionProperty :: IS_PROTECTED : $ type |= ClassNode :: MODIFIER_PROTECTED ; break ; default : $ type |= ClassNode :: MODIFIER_PUBLIC ; break ; } if ( $ static ) { $ type |= ClassNode :: MODIFIER_STATIC ; } $ this -> node -> stmts [ ] = new PropertyNode ( $ type , [ new Node \ Stmt \ PropertyProperty ( $ propertyName ) ] ) ; $ this -> cachedProperties = null ; $ this -> cachedImmediateProperties = null ; }

Add a new property to the class.

Visibility defaults to \ReflectionProperty::IS_PUBLIC, or can be ::IS_PROTECTED or ::IS_PRIVATE.


public function removeProperty(string $propertyName) : bool
    {
        $lowerName = strtolower($propertyName);

        foreach ($this->node->stmts as $key => $stmt) {
            if (! ($stmt instanceof PropertyNode)) {
                continue;
            }

            $propertyNames = array_map(static function (Node\Stmt\PropertyProperty $propertyProperty) : string {
                return $propertyProperty->name->toLowerString();
            }, $stmt->props);

            if (in_array($lowerName, $propertyNames, true)) {
                $this->cachedProperties          = null;
                $this->cachedImmediateProperties = null;
                unset($this->node->stmts[$key]);

                return true;
            }
        }

        return false;
    }

public function removeProperty ( string $ propertyName ) : bool { $ lowerName = strtolower ( $ propertyName ) ; foreach ( $ this -> node -> stmts as $ key => $ stmt ) { if ( ! ( $ stmt instanceof PropertyNode ) ) { continue ; } $ propertyNames = array_map ( static function ( Node \ Stmt \ PropertyProperty $ propertyProperty ) : string { return $ propertyProperty -> name -> toLowerString ( ) ; } , $ stmt -> props ) ; if ( in_array ( $ lowerName , $ propertyNames , true ) ) { $ this -> cachedProperties = null ; $ this -> cachedImmediateProperties = null ; unset ( $ this -> node -> stmts [ $ key ] ) ; return true ; } } return false ; }


public function isMatchingReflector(Reflection $reflector) : bool
    {
        if ($this->name === self::IDENTIFIER_CLASS) {
            return $reflector instanceof ReflectionClass;
        }

        if ($this->name === self::IDENTIFIER_FUNCTION) {
            return $reflector instanceof ReflectionFunction;
        }

        return false;
    }

public function isMatchingReflector ( Reflection $ reflector ) : bool { if ( $ this -> name === self :: IDENTIFIER_CLASS ) { return $ reflector instanceof ReflectionClass ; } if ( $ this -> name === self :: IDENTIFIER_FUNCTION ) { return $ reflector instanceof ReflectionFunction ; } return false ; }

Check to see if a reflector is of a valid type specified by this identifier.

Check to see if a reflector is of a valid type specified by this identifier .


public static function export($instance = null) : string
    {
        if ($instance === null) {
            throw new InvalidArgumentException('Class instance must be provided');
        }

        return self::createFromInstance($instance)->__toString();
    }

public
static
function
export
(
$
instance
=
)
:
string
{
if
(
$
instance
===
)
{
throw
new
InvalidArgumentException
(
'Class instance must be provided'
)
;
}
return
self
::
createFromInstance
(
$
instance
)
->
__toString
(
)
;
}

Create a reflection and return the string representation of a class instance

@param object $instance

@throws IdentifierNotFound
@throws ReflectionException
@throws InvalidArgumentException


public static function createFromInstance($object) : ReflectionClass
    {
        if (! is_object($object)) {
            throw new InvalidArgumentException('Can only create from an instance of an object');
        }

        $className = get_class($object);

        if (strpos($className, ReflectionClass::ANONYMOUS_CLASS_NAME_PREFIX) === 0) {
            $reflector = new ClassReflector(new AnonymousClassObjectSourceLocator(
                $object,
                (new BetterReflection())->phpParser()
            ));
        } else {
            $reflector = (new BetterReflection())->classReflector();
        }

        return new self($reflector, $reflector->reflect($className), $object);
    }

Pass an instance of an object to this method to reflect it

@param object $object

@throws ReflectionException
@throws InvalidArgumentException
@throws IdentifierNotFound

@psalm-suppress DocblockTypeContradiction


private function getRuntimeProperties(?int $filter = null) : array
    {
        if (! $this->reflectionClass->isInstance($this->object)) {
            throw new InvalidArgumentException('Cannot reflect runtime properties of a separate class');
        }

        // Ensure we have already cached existing properties so we can add to them
        $this->reflectionClass->getProperties();

        // Only known current way is to use internal ReflectionObject to get
        // the runtime-declared properties  :/
        $reflectionProperties = (new CoreReflectionObject($this->object))->getProperties();
        $runtimeProperties    = [];

        foreach ($reflectionProperties as $property) {
            if ($this->reflectionClass->hasProperty($property->getName())) {
                continue;
            }

            $reflectionProperty = $this->reflectionClass->getProperty($property->getName());

            $runtimeProperty = ReflectionProperty::createFromNode(
                $this->reflector,
                $this->createPropertyNodeFromReflection($property, $this->object),
                0,
                $reflectionProperty
                    ? $reflectionProperty->getDeclaringClass()->getDeclaringNamespaceAst()
                    : null,
                $this,
                $this,
                false
            );

            if ($filter !== null && ! ($filter & $runtimeProperty->getModifiers())) {
                continue;
            }

            $runtimeProperties[$runtimeProperty->getName()] = $runtimeProperty;
        }

        return $runtimeProperties;
    }

Reflect on runtime properties for the current instance

@see ReflectionClass::getProperties() for the usage of $filter

@return ReflectionProperty[]


private function createPropertyNodeFromReflection(CoreReflectionProperty $property, $instance) : PropertyNode
    {
        $builder = new PropertyNodeBuilder($property->getName());
        $builder->setDefault($property->getValue($instance));

        if ($property->isPublic()) {
            $builder->makePublic();
        }

        return $builder->getNode();
    }

private function createPropertyNodeFromReflection ( CoreReflectionProperty $ property , $ instance ) : PropertyNode { $ builder = new PropertyNodeBuilder ( $ property -> getName ( ) ) ; $ builder -> setDefault ( $ property -> getValue ( $ instance ) ) ; if ( $ property -> isPublic ( ) ) { $ builder -> makePublic ( ) ; } return $ builder -> getNode ( ) ; }

Create an AST PropertyNode given a reflection

Note that we don't copy across DocBlock, protected, private or static
because runtime properties can't have these attributes.

@param object $instance


protected function populateFunctionAbstract(
        Reflector $reflector,
        Node\FunctionLike $node,
        LocatedSource $locatedSource,
        ?NamespaceNode $declaringNamespace = null
    ) : void {
        $this->reflector          = $reflector;
        $this->node               = $node;
        $this->locatedSource      = $locatedSource;
        $this->declaringNamespace = $declaringNamespace;

        $this->setNodeOptionalFlag();
    }

protected function populateFunctionAbstract ( Reflector $ reflector , Node \ FunctionLike $ node , LocatedSource $ locatedSource , ? NamespaceNode $ declaringNamespace = null ) : void { $ this -> reflector = $ reflector ; $ this -> node = $ node ; $ this -> locatedSource = $ locatedSource ; $ this -> declaringNamespace = $ declaringNamespace ; $ this -> setNodeOptionalFlag ( ) ; }

Populate the common elements of the function abstract.

@param Node\Stmt\ClassMethod|Node\Stmt\Function_|Node\Expr\Closure $node Node has to be processed by the PhpParser\NodeVisitor\NameResolver

@throws InvalidAbstractFunctionNodeType

Populate the common elements of the function abstract .


private function setNodeOptionalFlag() : void
    {
        $overallOptionalFlag = true;
        $lastParamIndex      = count($this->node->params) - 1;
        for ($i = $lastParamIndex; $i >= 0; $i--) {
            $hasDefault = ($this->node->params[$i]->default !== null);

            // When we find the first parameter that does not have a default,
            // flip the flag as all params for this are no longer optional
            // EVEN if they have a default value
            if (! $hasDefault) {
                $overallOptionalFlag = false;
            }

            $this->node->params[$i]->isOptional = $overallOptionalFlag;
        }
    }

We must determine if params are optional or not ahead of time, but we
must do it in reverse...

We must determine if params are optional or not ahead of time but we must do it in reverse ...


public function getNumberOfRequiredParameters() : int
    {
        return count(array_filter(
            $this->getParameters(),
            static function (ReflectionParameter $p) : bool {
                return ! $p->isOptional();
            }
        ));
    }

public function getNumberOfRequiredParameters ( ) : int { return count ( array_filter ( $ this -> getParameters ( ) , static function ( ReflectionParameter $ p ) : bool { return ! $ p -> isOptional ( ) ; } ) ) ; }

Get the number of required parameters for this method.

Get the number of required parameters for this method .


public function getParameters() : array
    {
        $parameters = [];

        foreach ($this->node->params as $paramIndex => $paramNode) {
            $parameters[] = ReflectionParameter::createFromNode(
                $this->reflector,
                $paramNode,
                $this->declaringNamespace,
                $this,
                $paramIndex
            );
        }

        return $parameters;
    }

public function getParameters ( ) : array { $ parameters = [ ] ; foreach ( $ this -> node -> params as $ paramIndex => $ paramNode ) { $ parameters [ ] = ReflectionParameter :: createFromNode ( $ this -> reflector , $ paramNode , $ this -> declaringNamespace , $ this , $ paramIndex ) ; } return $ parameters ; }

Get an array list of the parameters for this method signature, as an
array of ReflectionParameter instances.

@return ReflectionParameter[]

Get an array list of the parameters for this method signature as an array of ReflectionParameter instances .


public function getParameter(string $parameterName) : ?ReflectionParameter
    {
        foreach ($this->getParameters() as $parameter) {
            if ($parameter->getName() === $parameterName) {
                return $parameter;
            }
        }

        return null;
    }

public function getParameter ( string $ parameterName ) : ? ReflectionParameter { foreach ( $ this -> getParameters ( ) as $ parameter ) { if ( $ parameter -> getName ( ) === $ parameterName ) { return $ parameter ; } } return null ; }

Get a single parameter by name. Returns null if parameter not found for
the function.

Get a single parameter by name . Returns null if parameter not found for the function .


public function isVariadic() : bool
    {
        $parameters = $this->getParameters();

        foreach ($parameters as $parameter) {
            if ($parameter->isVariadic()) {
                return true;
            }
        }

        return false;
    }

public function isVariadic ( ) : bool { $ parameters = $ this -> getParameters ( ) ; foreach ( $ parameters as $ parameter ) { if ( $ parameter -> isVariadic ( ) ) { return true ; } } return false ; }

Check if the function has a variadic parameter.

Check if the function has a variadic parameter .


public function setReturnType(string $newReturnType) : void
    {
        $this->node->returnType = new Node\Name($newReturnType);
    }

public function setReturnType ( string $ newReturnType ) : void { $ this -> node -> returnType = new Node \ Name ( $ newReturnType ) ; }


public function getBodyCode(?PrettyPrinterAbstract $printer = null) : string
    {
        if ($printer === null) {
            $printer = new StandardPrettyPrinter();
        }

        return $printer->prettyPrint($this->getBodyAst());
    }

public function getBodyCode ( ? PrettyPrinterAbstract $ printer = null ) : string { if ( $ printer === null ) { $ printer = new StandardPrettyPrinter ( ) ; } return $ printer -> prettyPrint ( $ this -> getBodyAst ( ) ) ; }

Retrieves the body of this function as code.

If a PrettyPrinter is provided as a parameter, it will be used, otherwise
a default will be used.

Note that the formatting of the code may not be the same as the original
function. If specific formatting is required, you should provide your
own implementation of a PrettyPrinter to unparse the AST.

Retrieves the body of this function as code .


public function getReturnStatementsAst() : array
    {
        $visitor = new ReturnNodeVisitor();

        $traverser = new NodeTraverser();
        $traverser->addVisitor($visitor);

        $traverser->traverse($this->node->getStmts());

        return $visitor->getReturnNodes();
    }

public function getReturnStatementsAst ( ) : array { $ visitor = new ReturnNodeVisitor ( ) ; $ traverser = new NodeTraverser ( ) ; $ traverser -> addVisitor ( $ visitor ) ; $ traverser -> traverse ( $ this -> node -> getStmts ( ) ) ; return $ visitor -> getReturnNodes ( ) ; }

Fetch an array of all return statements found within this function.

Note that return statements within smaller scopes contained (e.g. anonymous classes, closures) are not returned
here as they are not within the immediate scope.

@return Node\Stmt\Return_[]

Fetch an array of all return statements found within this function .


public function locateIdentifiersByType(Reflector $reflector, IdentifierType $identifierType) : array
    {
        return (new DirectoriesSourceLocator(
            $this->mapping->directories(),
            $this->astLocator
        ))->locateIdentifiersByType($reflector, $identifierType);
    }

public function locateIdentifiersByType ( Reflector $ reflector , IdentifierType $ identifierType ) : array { return ( new DirectoriesSourceLocator ( $ this -> mapping -> directories ( ) , $ this -> astLocator ) ) -> locateIdentifiersByType ( $ reflector , $ identifierType ) ; }

Find all identifiers of a type

@return Reflection[]


public static function createFromNode(
        Reflector $reflector,
        ClassConst $node,
        int $positionInNode,
        ReflectionClass $owner
    ) : self {
        $ref                 = new self();
        $ref->node           = $node;
        $ref->positionInNode = $positionInNode;
        $ref->owner          = $owner;
        $ref->reflector      = $reflector;

        return $ref;
    }

public static function createFromNode ( Reflector $ reflector , ClassConst $ node , int $ positionInNode , ReflectionClass $ owner ) : self { $ ref = new self ( ) ; $ ref -> node = $ node ; $ ref -> positionInNode = $ positionInNode ; $ ref -> owner = $ owner ; $ ref -> reflector = $ reflector ; return $ ref ; }

Create a reflection of a class's constant by Const Node

@internal

@param ClassConst $node Node has to be processed by the PhpParser\NodeVisitor\NameResolver

Create a reflection of a class s constant by Const Node


public function getValue()
    {
        if ($this->valueWasCached !== false) {
            return $this->value;
        }

        $this->value          = (new CompileNodeToValue())->__invoke(
            $this->node->consts[$this->positionInNode]->value,
            new CompilerContext($this->reflector, $this->getDeclaringClass())
        );
        $this->valueWasCached = true;

        return $this->value;
    }

public function getValue ( ) { if ( $ this -> valueWasCached !== false ) { return $ this -> value ; } $ this -> value = ( new CompileNodeToValue ( ) ) -> __invoke ( $ this -> node -> consts [ $ this -> positionInNode ] -> value , new CompilerContext ( $ this -> reflector , $ this -> getDeclaringClass ( ) ) ) ; $ this -> valueWasCached = true ; return $ this -> value ; }


public function getModifiers() : int
    {
        $val  = 0;
        $val += $this->isPublic() ? ReflectionProperty::IS_PUBLIC : 0;
        $val += $this->isProtected() ? ReflectionProperty::IS_PROTECTED : 0;
        $val += $this->isPrivate() ? ReflectionProperty::IS_PRIVATE : 0;

        return $val;
    }

public function getModifiers ( ) : int { $ val = 0 ; $ val += $ this -> isPublic ( ) ? ReflectionProperty :: IS_PUBLIC : 0 ; $ val += $ this -> isProtected ( ) ? ReflectionProperty :: IS_PROTECTED : 0 ; $ val += $ this -> isPrivate ( ) ? ReflectionProperty :: IS_PRIVATE : 0 ; return $ val ; }

Returns a bitfield of the access modifiers for this constant


private function generateDoc(string $className, bool $interface = false): array
    {
        $resource = $this->classes[$className]['resource'];
        $annotations = [];

        if (!$interface && isset($this->classes[$className]['interfaceName'])) {
            $annotations[] = '{@inheritdoc}';
            $annotations[] = '';
        } else {
            $annotations = $this->formatDoc((string) $resource->get('rdfs:comment'));
            $annotations[] = '';
            $annotations[] = sprintf('@see %s %s', $resource->getUri(), 'Documentation on Schema.org');
        }

        if ($this->config['author']) {
            $annotations[] = sprintf('@author %s', $this->config['author']);
        }

        return $annotations;
    }

private
function
generateDoc
(
string
$
className
,
bool
$
interface
=
false
)
:
array
{
$
resource
=
$
this
->
classes
[
$
className
]
[
'resource'
]
;
$
annotations
=
[
]
;
if
(
!
$
interface
&&
isset
(
$
this
->
classes
[
$
className
]
[
'interfaceName'
]
)
)
{
$
annotations
[
]
=
'{@inheritdoc}'
;
$
annotations
[
]
=
''
;
}
else
{
$
annotations
=
$
this
->
formatDoc
(
(
string
)
$
resource
->
get
(
'rdfs:comment'
)
)
;
$
annotations
[
]
=
''
;
$
annotations
[
]
=
sprintf
(
'@see %s %s'
,
$
resource
->
getUri
(
)
,
'Documentation on Schema.org'
)
;
}
if
(
$
this
->
config
[
'author'
]
)
{
$
annotations
[
]
=
sprintf
(
'@author %s'
,
$
this
->
config
[
'author'
]
)
;
}
return
$
annotations
;
}


private function formatDoc(string $doc, bool $indent = false): array
    {
        $doc = explode("\n", $this->htmlToMarkdown->convert($doc));

        if ($indent) {
            $count = count($doc);
            for ($i = 1; $i < $count; ++$i) {
                $doc[$i] = self::INDENT.$doc[$i];
            }
        }

        return $doc;
    }

private function formatDoc ( string $ doc , bool $ indent = false ) : array { $ doc = explode ( "\n" , $ this -> htmlToMarkdown -> convert ( $ doc ) ) ; if ( $ indent ) { $ count = count ( $ doc ) ; for ( $ i = 1 ; $ i < $ count ; ++ $ i ) { $ doc [ $ i ] = self :: INDENT . $ doc [ $ i ] ; } } return $ doc ; }


public function extract(): array
    {
        $properties = [];

        foreach ($this->graphs as $graph) {
            foreach ($graph->allOfType('rdf:Property') as $property) {
                $properties[$property->localName()] = $this->extractForProperty($property);
            }
        }

        return $properties;
    }

public function extract ( ) : array { $ properties = [ ] ; foreach ( $ this -> graphs as $ graph ) { foreach ( $ graph -> allOfType ( 'rdf:Property' ) as $ property ) { $ properties [ $ property -> localName ( ) ] = $ this -> extractForProperty ( $ property ) ; } } return $ properties ; }


private function extractForProperty(\EasyRdf_Resource $property): string
    {
        $localName = $property->localName();
        $fromGoodRelations = $this->goodRelationsBridge->extractCardinality($localName);
        if (false !== $fromGoodRelations) {
            return $fromGoodRelations;
        }

        $comment = $property->get('rdfs:comment')->getValue();

        if (
            // http://schema.org/acceptedOffer, http://schema.org/acceptedPaymentMethod, http://schema.org/exerciseType
            preg_match('/\(s\)/', $comment)
            ||
            // http://schema.org/follows
            preg_match('/^The most generic uni-directional social relation./', $comment)
            ||
            preg_match('/one or more/i', $comment)
        ) {
            return self::CARDINALITY_0_N;
        }

        if (
            preg_match('/^is/', $localName)
        ||
            preg_match('/^The /', $comment)
        ) {
            return self::CARDINALITY_0_1;
        }

        return self::CARDINALITY_UNKNOWN;
    }

Extracts the cardinality of a property.

Based on [Geraint Luff work](https://github.com/geraintluff/schema-org-gen).

@param \EasyRdf_Resource $property

@return string The cardinality

Extracts the cardinality of a property .


private function isEnum(\EasyRdf_Resource $type): bool
    {
        $subClassOf = $type->get('rdfs:subClassOf');

        return $subClassOf && self::SCHEMA_ORG_ENUMERATION === $subClassOf->getUri();
    }

private function isEnum ( \ EasyRdf_Resource $ type ) : bool { $ subClassOf = $ type -> get ( 'rdfs:subClassOf' ) ; return $ subClassOf && self :: SCHEMA_ORG_ENUMERATION === $ subClassOf -> getUri ( ) ; }


private function createPropertiesMap(array $types)
    {
        $typesAsString = [];
        $map = [];
        foreach ($types as $type) {
            // get all parent classes until the root
            $parentClasses = $this->getParentClasses($type);
            $typesAsString[] = $parentClasses;
            $map[$type->getUri()] = [];
        }

        foreach ($this->graphs as $graph) {
            foreach ($graph->allOfType('rdf:Property') as $property) {
                foreach ($property->all(self::SCHEMA_ORG_DOMAIN) as $domain) {
                    foreach ($typesAsString as $typesAsStringItem) {
                        if (in_array($domain->getUri(), $typesAsStringItem, true)) {
                            $map[$typesAsStringItem[0]][] = $property;
                        }
                    }
                }
            }
        }

        return $map;
    }

Creates a map between classes and properties.

@param array $types

@return array

Creates a map between classes and properties .


private function namespaceToDir(array $config, string $namespace): string
    {
        if (null !== ($prefix = $config['namespaces']['prefix'] ?? null) && 0 === strpos($namespace, $prefix)) {
            $namespace = substr($namespace, strlen($prefix));
        }

        return sprintf('%s/%s/', $config['output'], strtr($namespace, '\\', '/'));
    }

private function namespaceToDir ( array $ config , string $ namespace ) : string { if ( null !== ( $ prefix = $ config [ 'namespaces' ] [ 'prefix' ] ?? null ) && 0 === strpos ( $ namespace , $ prefix ) ) { $ namespace = substr ( $ namespace , strlen ( $ prefix ) ) ; } return sprintf ( '%s/%s/' , $ config [ 'output' ] , strtr ( $ namespace , '\\' , '/' ) ) ; }

Converts a namespace to a directory path according to PSR-4.

Converts a namespace to a directory path according to PSR - 4 .


private function fixCs(array $files): void
    {
        $fileInfos = [];
        foreach ($files as $file) {
            $fileInfos[] = new \SplFileInfo($file);
        }

        $fixers = (new FixerFactory())
            ->registerBuiltInFixers()
            ->useRuleSet(new RuleSet([
                '@Symfony' => true,
                'array_syntax' => ['syntax' => 'short'],
                'phpdoc_order' => true,
                'declare_strict_types' => true,
            ]))
            ->getFixers();

        $runner = new Runner(
            new \ArrayIterator($fileInfos),
            $fixers,
            new NullDiffer(),
            null,
            new ErrorsManager(),
            new Linter(),
            false,
            new NullCacheManager()
        );
        $runner->fix();
    }

private function fixCs ( array $ files ) : void { $ fileInfos = [ ] ; foreach ( $ files as $ file ) { $ fileInfos [ ] = new \ SplFileInfo ( $ file ) ; } $ fixers = ( new FixerFactory ( ) ) -> registerBuiltInFixers ( ) -> useRuleSet ( new RuleSet ( [ '@Symfony' => true , 'array_syntax' => [ 'syntax' => 'short' ] , 'phpdoc_order' => true , 'declare_strict_types' => true , ] ) ) -> getFixers ( ) ; $ runner = new Runner ( new \ ArrayIterator ( $ fileInfos ) , $ fixers , new NullDiffer ( ) , null , new ErrorsManager ( ) , new Linter ( ) , false , new NullCacheManager ( ) ) ; $ runner -> fix ( ) ; }

Uses PHP CS Fixer to make generated files following PSR and Symfony Coding Standards.

Uses PHP CS Fixer to make generated files following PSR and Symfony Coding Standards .


public function exist(string $id): bool
    {
        foreach ($this->relations as $relation) {
            $result = $relation->xpath(sprintf('//*[@rdf:about="%s"]', $this->getPropertyUrl($id)));
            if (!empty($result)) {
                return true;
            }
        }

        return false;
    }

public function exist ( string $ id ) : bool { foreach ( $ this -> relations as $ relation ) { $ result = $ relation -> xpath ( sprintf ( '//*[@rdf:about="%s"]' , $ this -> getPropertyUrl ( $ id ) ) ) ; if ( ! empty ( $ result ) ) { return true ; } } return false ; }

Checks if a property exists in GoodRelations.

Checks if a property exists in GoodRelations .


public function extractCardinality(string $id)
    {
        foreach ($this->relations as $relation) {
            $result = $relation->xpath(sprintf('//*[@rdf:about="%s"]/rdfs:label', $this->getPropertyUrl($id)));
            if (count($result)) {
                preg_match('/\(.\.\..\)/', $result[0]->asXML(), $matches);

                return $matches[0];
            }
        }

        return false;
    }

public function extractCardinality ( string $ id ) { foreach ( $ this -> relations as $ relation ) { $ result = $ relation -> xpath ( sprintf ( '//*[@rdf:about="%s"]/rdfs:label' , $ this -> getPropertyUrl ( $ id ) ) ) ; if ( count ( $ result ) ) { preg_match ( '/\(.\.\..\)/' , $ result [ 0 ] -> asXML ( ) , $ matches ) ; return $ matches [ 0 ] ; } } return false ; }

Extracts cardinality from the Good Relations OWL.

@return string|bool

Extracts cardinality from the Good Relations OWL .


private function getPropertyUrl(string $id): string
    {
        $propertyId = $this->datatypePropertiesTable[$id] ?? $this->objectPropertiesTable[$id] ?? $id;

        return self::GOOD_RELATIONS_NAMESPACE.$propertyId;
    }

private function getPropertyUrl ( string $ id ) : string { $ propertyId = $ this -> datatypePropertiesTable [ $ id ] ?? $ this -> objectPropertiesTable [ $ id ] ?? $ id ; return self :: GOOD_RELATIONS_NAMESPACE . $ propertyId ; }


protected function toPhpType(array $field, bool $adderOrRemover = false): string
    {
        $range = $field['range'];

        if ($field['isEnum']) {
            if ($field['isArray']) {
                return 'string[]';
            }

            return 'string';
        }

        $data = false;
        switch ($range) {
            case 'Boolean':
                $data = 'bool';
                break;
            case 'Date':
            case 'DateTime':
            case 'Time':
                $data = '\\'.\DateTimeInterface::class;
                break;
            case 'Number':
            case 'Float':
                $data = 'float';
                break;
            case 'Integer':
                $data = 'integer';
                break;
            case 'Text':
            case 'URL':
                $data = 'string';
                break;
        }

        if (false !== $data) {
            if ($field['isArray']) {
                return sprintf('%s[]', $data);
            }

            return $data;
        }

        if (isset($this->classes[$field['range']]['interfaceName'])) {
            $range = $this->classes[$field['range']]['interfaceName'];
        }

        if ($field['isArray'] && !$adderOrRemover) {
            if ($this->config['doctrine']['useCollection']) {
                return sprintf('Collection<%s>', $range);
            }

            return sprintf('%s[]', $range);
        }

        return $range;
    }

protected function toPhpType ( array $ field , bool $ adderOrRemover = false ) : string { $ range = $ field [ 'range' ] ; if ( $ field [ 'isEnum' ] ) { if ( $ field [ 'isArray' ] ) { return 'string[]' ; } return 'string' ; } $ data = false ; switch ( $ range ) { case 'Boolean' : $ data = 'bool' ; break ; case 'Date' : case 'DateTime' : case 'Time' : $ data = '\\' . \ DateTimeInterface :: class ; break ; case 'Number' : case 'Float' : $ data = 'float' ; break ; case 'Integer' : $ data = 'integer' ; break ; case 'Text' : case 'URL' : $ data = 'string' ; break ; } if ( false !== $ data ) { if ( $ field [ 'isArray' ] ) { return sprintf ( '%s[]' , $ data ) ; } return $ data ; } if ( isset ( $ this -> classes [ $ field [ 'range' ] ] [ 'interfaceName' ] ) ) { $ range = $ this -> classes [ $ field [ 'range' ] ] [ 'interfaceName' ] ; } if ( $ field [ 'isArray' ] && ! $ adderOrRemover ) { if ( $ this -> config [ 'doctrine' ] [ 'useCollection' ] ) { return sprintf ( 'Collection<%s>' , $ range ) ; } return sprintf ( '%s[]' , $ range ) ; } return $ range ; }

Converts a Schema.org range to a PHP type.

Converts a Schema . org range to a PHP type .


private function getRelationName(string $range): string
    {
        $class = $this->classes[$range];

        if (isset($class['interfaceName'])) {
            return $class['interfaceName'];
        }

        if (isset($this->config['types'][$class['name']]['namespaces']['class'])) {
            return sprintf('%s\\%s', $this->config['types'][$class['name']]['namespaces']['class'], $class['name']);
        }

        if (isset($this->config['namespaces']['entity'])) {
            return sprintf('%s\\%s', $this->config['namespaces']['entity'], $class['name']);
        }

        return $class['name'];
    }

private function getRelationName ( string $ range ) : string { $ class = $ this -> classes [ $ range ] ; if ( isset ( $ class [ 'interfaceName' ] ) ) { return $ class [ 'interfaceName' ] ; } if ( isset ( $ this -> config [ 'types' ] [ $ class [ 'name' ] ] [ 'namespaces' ] [ 'class' ] ) ) { return sprintf ( '%s\\%s' , $ this -> config [ 'types' ] [ $ class [ 'name' ] ] [ 'namespaces' ] [ 'class' ] , $ class [ 'name' ] ) ; } if ( isset ( $ this -> config [ 'namespaces' ] [ 'entity' ] ) ) { return sprintf ( '%s\\%s' , $ this -> config [ 'namespaces' ] [ 'entity' ] , $ class [ 'name' ] ) ; } return $ class [ 'name' ] ; }

Gets class or interface name to use in relations.

Gets class or interface name to use in relations .


private function finishFile()
    {
        if ($this->writer !== null) {
            $this->writer->endElement();
            $this->writer->endDocument();

            /* To prevent infinite recursion through flush */
            $this->urlsCount = 0;

            $this->flush(0);
            $this->writerBackend->finish();
            $this->writerBackend = null;

            $this->byteCount = 0;
        }
    }


private function flush($footSize = 10)
    {
        $data = $this->writer->flush(true);
        $dataSize = mb_strlen($data, '8bit');

        /*
         * Limit the file size of each single site map
         *
         * We use a heuristic of 10 Bytes for the remainder of the file,
         * i.e. </urlset> plus a new line.
         */
        if ($this->byteCount + $dataSize + $footSize > $this->maxBytes) {
            if ($this->urlsCount <= 1) {
                throw new \OverflowException('The buffer size is too big for the defined file size limit');
            }
            $this->finishFile();
            $this->createNewFile();
        }

        $this->writerBackend->append($data);
        $this->byteCount += $dataSize;
    }

Flushes buffer into file

@param int $footSize Size of the remaining closing tags
@throws \OverflowException


public function addItem($location, $lastModified = null, $changeFrequency = null, $priority = null)
    {
        if ($this->urlsCount >= $this->maxUrls) {
            $this->finishFile();
        }

        if ($this->writerBackend === null) {
            $this->createNewFile();
        }

        if (is_array($location)) {
            $this->addMultiLanguageItem($location, $lastModified, $changeFrequency, $priority);
        } else {
            $this->addSingleLanguageItem($location, $lastModified, $changeFrequency, $priority);
        }

        $this->urlsCount++;

        if ($this->urlsCount % $this->bufferSize === 0) {
            $this->flush();
        }
    }

public function addItem ( $ location , $ lastModified = null , $ changeFrequency = null , $ priority = null ) { if ( $ this -> urlsCount >= $ this -> maxUrls ) { $ this -> finishFile ( ) ; } if ( $ this -> writerBackend === null ) { $ this -> createNewFile ( ) ; } if ( is_array ( $ location ) ) { $ this -> addMultiLanguageItem ( $ location , $ lastModified , $ changeFrequency , $ priority ) ; } else { $ this -> addSingleLanguageItem ( $ location , $ lastModified , $ changeFrequency , $ priority ) ; } $ this -> urlsCount ++ ; if ( $ this -> urlsCount % $ this -> bufferSize === 0 ) { $ this -> flush ( ) ; } }

Adds a new item to sitemap

@param string|array $location location item URL
@param integer $lastModified last modification timestamp
@param string $changeFrequency change frequency. Use one of self:: constants here
@param string $priority item's priority (0.0-1.0). Default null is equal to 0.5

@throws \InvalidArgumentException


private function addSingleLanguageItem($location, $lastModified, $changeFrequency, $priority)
    {
        $this->validateLocation($location);

        $this->writer->startElement('url');

        $this->writer->writeElement('loc', $location);

        if ($lastModified !== null) {
            $this->writer->writeElement('lastmod', date('c', $lastModified));
        }

        if ($changeFrequency !== null) {
            if (!in_array($changeFrequency, $this->validFrequencies, true)) {
                throw new \InvalidArgumentException(
                    'Please specify valid changeFrequency. Valid values are: '
                    . implode(', ', $this->validFrequencies)
                    . "You have specified: {$changeFrequency}."
                );
            }

            $this->writer->writeElement('changefreq', $changeFrequency);
        }

        if ($priority !== null) {
            if (!is_numeric($priority) || $priority < 0 || $priority > 1) {
                throw new \InvalidArgumentException(
                    "Please specify valid priority. Valid values range from 0.0 to 1.0. You have specified: {$priority}."
                );
            }
            $this->writer->writeElement('priority', number_format($priority, 1, '.', ','));
        }

        $this->writer->endElement();
    }

Adds a new single item to sitemap

@param string $location location item URL
@param integer $lastModified last modification timestamp
@param float $changeFrequency change frequency. Use one of self:: constants here
@param string $priority item's priority (0.0-1.0). Default null is equal to 0.5

@throws \InvalidArgumentException

@see addItem


private function addMultiLanguageItem($locations, $lastModified, $changeFrequency, $priority)
    {
        foreach ($locations as $language => $url) {
            $this->validateLocation($url);

            $this->writer->startElement('url');

            $this->writer->writeElement('loc', $url);

            if ($lastModified !== null) {
                $this->writer->writeElement('lastmod', date('c', $lastModified));
            }

            if ($changeFrequency !== null) {
                if (!in_array($changeFrequency, $this->validFrequencies, true)) {
                    throw new \InvalidArgumentException(
                        'Please specify valid changeFrequency. Valid values are: '
                        . implode(', ', $this->validFrequencies)
                        . "You have specified: {$changeFrequency}."
                    );
                }

                $this->writer->writeElement('changefreq', $changeFrequency);
            }

            if ($priority !== null) {
                if (!is_numeric($priority) || $priority < 0 || $priority > 1) {
                    throw new \InvalidArgumentException(
                        "Please specify valid priority. Valid values range from 0.0 to 1.0. You have specified: {$priority}."
                    );
                }
                $this->writer->writeElement('priority', number_format($priority, 1, '.', ','));
            }

            foreach ($locations as $hreflang => $href) {

                $this->writer->startElement('xhtml:link');
                $this->writer->startAttribute('rel');
                $this->writer->text('alternate');
                $this->writer->endAttribute();

                $this->writer->startAttribute('hreflang');
                $this->writer->text($hreflang);
                $this->writer->endAttribute();

                $this->writer->startAttribute('href');
                $this->writer->text($href);
                $this->writer->endAttribute();
                $this->writer->endElement();
            }

            $this->writer->endElement();
        }
    }

Adds a multi-language item, based on multiple locations with alternate hrefs to sitemap

@param array $locations array of language => link pairs
@param integer $lastModified last modification timestamp
@param float $changeFrequency change frequency. Use one of self:: constants here
@param string $priority item's priority (0.0-1.0). Default null is equal to 0.5

@throws \InvalidArgumentException

@see addItem

Adds a multi - language item based on multiple locations with alternate hrefs to sitemap


public function getSitemapUrls($baseUrl)
    {
        $urls = array();
        foreach ($this->writtenFilePaths as $file) {
            $urls[] = $baseUrl . pathinfo($file, PATHINFO_BASENAME);
        }
        return $urls;
    }

public function getSitemapUrls ( $ baseUrl ) { $ urls = array ( ) ; foreach ( $ this -> writtenFilePaths as $ file ) { $ urls [ ] = $ baseUrl . pathinfo ( $ file , PATHINFO_BASENAME ) ; } return $ urls ; }

Returns an array of URLs written

@param string $baseUrl base URL of all the sitemaps written
@return array URLs of sitemaps written


public function setUseGzip($value)
    {
        if ($value && !extension_loaded('zlib')) {
            throw new \RuntimeException('Zlib extension must be enabled to gzip the sitemap.');
        }
        if ($this->writerBackend !== null && $value != $this->useGzip) {
            throw new \RuntimeException('Cannot change the gzip value once items have been added to the sitemap.');
        }
        $this->useGzip = $value;
    }

Sets whether the resulting files will be gzipped or not.
@param bool $value
@throws \RuntimeException when trying to enable gzip while zlib is not available or when trying to change
setting when some items are already written

Sets whether the resulting files will be gzipped or not .


public function addSitemap($location, $lastModified = null)
    {
        if (false === filter_var($location, FILTER_VALIDATE_URL)) {
            throw new \InvalidArgumentException(
                "The location must be a valid URL. You have specified: {$location}."
            );
        }

        if ($this->writer === null) {
            $this->createNewFile();
        }

        $this->writer->startElement('sitemap');
        $this->writer->writeElement('loc', $location);

        if ($lastModified !== null) {
            $this->writer->writeElement('lastmod', date('c', $lastModified));
        }
        $this->writer->endElement();
    }

Adds sitemap link to the index file

@param string $location URL of the sitemap
@param integer $lastModified unix timestamp of sitemap modification time
@throws \InvalidArgumentException


private function write($data, $flushMode)
    {
        assert($this->file !== null);

        $compressedChunk = deflate_add($this->deflateContext, $data, $flushMode);
        fwrite($this->file, $compressedChunk);
    }

private function write ( $ data , $ flushMode ) { assert ( $ this -> file !== null ) ; $ compressedChunk = deflate_add ( $ this -> deflateContext , $ data , $ flushMode ) ; fwrite ( $ this -> file , $ compressedChunk ) ; }

Deflate data in a deflate context and write it to the target file

@param string $data
@param int $flushMode zlib flush mode to use for writing


public function finish()
    {
        $this->write('', ZLIB_FINISH);

        $this->file = null;
        $this->deflateContext = null;
    }

public function finish ( ) { $ this -> write ( '' , ZLIB_FINISH ) ; $ this -> file = null ; $ this -> deflateContext = null ; }


public function finish()
    {
        assert($this->tempFile !== null);

        $file = fopen('compress.zlib://' . $this->filename, 'wb');
        rewind($this->tempFile);
        stream_copy_to_stream($this->tempFile, $file);

        fclose($file);
        fclose($this->tempFile);
        $this->tempFile = null;
    }

public function finish ( ) { assert ( $ this -> tempFile !== null ) ; $ file = fopen ( 'compress.zlib://' . $ this -> filename , 'wb' ) ; rewind ( $ this -> tempFile ) ; stream_copy_to_stream ( $ this -> tempFile , $ file ) ; fclose ( $ file ) ; fclose ( $ this -> tempFile ) ; $ this -> tempFile = null ; }


public function setExpirationDate($date)
    {
        if (is_int($date) || ctype_digit(strval($date))) {
            $expirationDate = intval($date);
        } else {
            $expirationDate = strtotime($date);
        }

        if ($expirationDate === false) {
            throw new InvalidArgumentException(
                sprintf(
                    'Invalid expiration date format: "%s". Please use a ' .
                    'format compatible with PHP\'s strtotime().',
                    $date
                )
            );
        }

        if ($expirationDate !== 0 && $expirationDate < time() + 86400) {
            throw new InvalidArgumentException(
                'Expiration date must be at least a day in the future.'
            );
        }

        // GnuPG suffers from the 2038 bug
        if ($expirationDate > 2147483647) {
            throw new InvalidArgumentException(
                'Expiration date must not be greater than 2038-01-19T03:14:07.'
            );
        }

        $this->expirationDate = $expirationDate;

        return $this;
    }

Sets the expiration date of generated keys

@param string|integer $date either a string that may be parsed by
PHP's strtotime() function, or an integer
timestamp representing the number of seconds
since the UNIX epoch. This date must be at
least one date in the future. Keys that
expire in the past may not be generated. Use
an expiration date of 0 for keys that do not
expire.

@throws InvalidArgumentException if the date is not a valid format, or
if the date is not at least one day in
the future, or if the date is greater
than 2038-01-19T03:14:07.

@return Crypt_GPG_KeyGenerator the current object, for fluent interface.


public function setKeyParams($algorithm, $size = 0, $usage = 0)
    {
        $algorithm = intval($algorithm);

        if ($algorithm === Crypt_GPG_SubKey::ALGORITHM_ELGAMAL_ENC) {
            throw new Crypt_GPG_InvalidKeyParamsException(
                'Primary key algorithm must be capable of signing. The ' .
                'Elgamal algorithm can only encrypt.',
                0,
                $algorithm,
                $size,
                $usage
            );
        }

        if ($size != 0) {
            $size = intval($size);
        }

        if ($usage != 0) {
            $usage = intval($usage);
        }

        $usageEncrypt = Crypt_GPG_SubKey::USAGE_ENCRYPT;

        if ($algorithm === Crypt_GPG_SubKey::ALGORITHM_DSA
            && ($usage & $usageEncrypt) === $usageEncrypt
        ) {
            throw new Crypt_GPG_InvalidKeyParamsException(
                'The DSA algorithm is not capable of encrypting. Please ' .
                'specify a different algorithm or do not include encryption ' .
                'as a usage for the primary key.',
                0,
                $algorithm,
                $size,
                $usage
            );
        }

        $this->keyAlgorithm = $algorithm;

        if ($size != 0) {
            $this->keySize = $size;
        }

        if ($usage != 0) {
            $this->keyUsage = $usage;
        }

        return $this;
    }

Sets the parameters for the primary key of generated key-pairs

@param integer $algorithm the algorithm used by the key. This should be
one of the Crypt_GPG_SubKey::ALGORITHM_*
constants.
@param integer $size      optional. The size of the key. Different
algorithms have different size requirements.
If not specified, the default size for the
specified algorithm will be used. If an
invalid key size is used, GnuPG will do its
best to round it to a valid size.
@param integer $usage     optional. A bitwise combination of key usages.
If not specified, the primary key will be used
only to sign and certify. This is the default
behavior of GnuPG in interactive mode. Use
the Crypt_GPG_SubKey::USAGE_* constants here.
The primary key may be used to certify even
if the certify usage is not specified.

@return Crypt_GPG_KeyGenerator the current object, for fluent interface.

Sets the parameters for the primary key of generated key - pairs


public function setSubKeyParams($algorithm, $size = '', $usage = 0)
    {
        $algorithm = intval($algorithm);

        if ($size != 0) {
            $size = intval($size);
        }

        if ($usage != 0) {
            $usage = intval($usage);
        }

        $usageSign = Crypt_GPG_SubKey::USAGE_SIGN;

        if ($algorithm === Crypt_GPG_SubKey::ALGORITHM_ELGAMAL_ENC
            && ($usage & $usageSign) === $usageSign
        ) {
            throw new Crypt_GPG_InvalidKeyParamsException(
                'The Elgamal algorithm is not capable of signing. Please ' .
                'specify a different algorithm or do not include signing ' .
                'as a usage for the sub-key.',
                0,
                $algorithm,
                $size,
                $usage
            );
        }

        $usageEncrypt = Crypt_GPG_SubKey::USAGE_ENCRYPT;

        if ($algorithm === Crypt_GPG_SubKey::ALGORITHM_DSA
            && ($usage & $usageEncrypt) === $usageEncrypt
        ) {
            throw new Crypt_GPG_InvalidKeyParamsException(
                'The DSA algorithm is not capable of encrypting. Please ' .
                'specify a different algorithm or do not include encryption ' .
                'as a usage for the sub-key.',
                0,
                $algorithm,
                $size,
                $usage
            );
        }

        $this->subKeyAlgorithm = $algorithm;

        if ($size != 0) {
            $this->subKeySize = $size;
        }

        if ($usage != 0) {
            $this->subKeyUsage = $usage;
        }

        return $this;
    }

Sets the parameters for the sub-key of generated key-pairs

@param integer $algorithm the algorithm used by the key. This should be
one of the Crypt_GPG_SubKey::ALGORITHM_*
constants.
@param integer $size      optional. The size of the key. Different
algorithms have different size requirements.
If not specified, the default size for the
specified algorithm will be used. If an
invalid key size is used, GnuPG will do its
best to round it to a valid size.
@param integer $usage     optional. A bitwise combination of key usages.
If not specified, the sub-key will be used
only to encrypt. This is the default behavior
of GnuPG in interactive mode. Use the
Crypt_GPG_SubKey::USAGE_* constants here.

@return Crypt_GPG_KeyGenerator the current object, for fluent interface.

Sets the parameters for the sub - key of generated key - pairs


protected function getUsage($usage)
    {
        $map = array(
            Crypt_GPG_SubKey::USAGE_ENCRYPT        => 'encrypt',
            Crypt_GPG_SubKey::USAGE_SIGN           => 'sign',
            Crypt_GPG_SubKey::USAGE_CERTIFY        => 'cert',
            Crypt_GPG_SubKey::USAGE_AUTHENTICATION => 'auth',
        );

        // cert is always used for primary keys and does not need to be
        // specified
        $usage &= ~Crypt_GPG_SubKey::USAGE_CERTIFY;

        $usageArray = array();

        foreach ($map as $key => $value) {
            if (($usage & $key) === $key) {
                $usageArray[] = $value;
            }
        }

        return implode(',', $usageArray);
    }

Builds a GnuPG key usage string suitable for key generation

See <b>doc/DETAILS</b> in the
{@link http://www.gnupg.org/download/ GPG distribution} for detailed
information on the key usage format.

@param integer $usage a bitwise combination of the key usages. This is
a combination of the Crypt_GPG_SubKey::USAGE_*
constants.

@return string the key usage string.


protected function getUserId($name, $email = '', $comment = '')
    {
        if ($name instanceof Crypt_GPG_UserId) {
            $userId = $name;
        } else {
            $userId = new Crypt_GPG_UserId();
            $userId->setName($name)->setEmail($email)->setComment($comment);
        }

        return $userId;
    }

protected function getUserId ( $ name , $ email = '' , $ comment = '' ) { if ( $ name instanceof Crypt_GPG_UserId ) { $ userId = $ name ; } else { $ userId = new Crypt_GPG_UserId ( ) ; $ userId -> setName ( $ name ) -> setEmail ( $ email ) -> setComment ( $ comment ) ; } return $ userId ; }

Gets a user id object from parameters

@param string|Crypt_GPG_UserId $name    either a {@link Crypt_GPG_UserId}
object, or a string containing
the name of the user id.
@param string                  $email   optional. If $name is
specified as a string, this is
the email address of the user id.
@param string                  $comment optional. If $name is
specified as a string, this is
the comment of the user id.

@return Crypt_GPG_UserId a user id object for the specified parameters.


public static function parse($string)
    {
        $userId  = new Crypt_GPG_UserId();
        $name    = '';
        $email   = '';
        $comment = '';

        // get email address from end of string if it exists
        $matches = array();
        if (preg_match('/^(.*?)<([^>]+)>$/', $string, $matches) === 1) {
            $string = trim($matches[1]);
            $email  = $matches[2];
        }

        // get comment from end of string if it exists
        $matches = array();
        if (preg_match('/^(.+?) \(([^\)]+)\)$/', $string, $matches) === 1) {
            $string  = $matches[1];
            $comment = $matches[2];
        }

        // there can be an email without a name
        if (!$email && preg_match('/^[\S]+@[\S]+$/', $string, $matches) === 1) {
            $email = $string;
        } else {
            $name = $string;
        }

        $userId->setName($name);
        $userId->setComment($comment);
        $userId->setEmail($email);

        return $userId;
    }

Parses a user id object from a user id string

A user id string is of the form:
name (comment) <email-address> with the comment
and email-address fields being optional.

@param string $string the user id string to parse.

@return Crypt_GPG_UserId the user id object parsed from the string.


public function isRunning()
    {
        $running = false;

        if (function_exists('posix_getpgid')) {
            $running = false !== posix_getpgid($this->pid);
        } elseif (PHP_OS === 'WINNT') {
            $command = 'tasklist /fo csv /nh /fi '
                . escapeshellarg('PID eq ' . $this->pid);

            $result  = exec($command);
            $parts   = explode(',', $result);
            $running = (count($parts) > 1 && trim($parts[1], '"') == $this->pid);
        } else {
            $result  = exec('ps -p ' . escapeshellarg($this->pid) . ' -o pid=');
            $running = (trim($result) == $this->pid);
        }

        return $running;
    }

public
function
isRunning
(
)
{
$
running
=
false
;
if
(
function_exists
(
'posix_getpgid'
)
)
{
$
running
=
false
!==
posix_getpgid
(
$
this
->
pid
)
;
}
elseif
(
PHP_OS
===
'WINNT'
)
{
$
command
=
'tasklist /fo csv /nh /fi '
.
escapeshellarg
(
'PID eq '
.
$
this
->
pid
)
;
$
result
=
exec
(
$
command
)
;
$
parts
=
explode
(
','
,
$
result
)
;
$
running
=
(
count
(
$
parts
)
>
1
&&
trim
(
$
parts
[
1
]
,
'"'
)
==
$
this
->
pid
)
;
}
else
{
$
result
=
exec
(
'ps -p '
.
escapeshellarg
(
$
this
->
pid
)
.
' -o pid='
)
;
$
running
=
(
trim
(
$
result
)
==
$
this
->
pid
)
;
}
return
$
running
;
}

Checks if the process is running

If the posix extension is available, posix_getpgid()
is used. Otherwise ps is used on UNIX-like systems and
tasklist on Windows.

@return boolean true if the process is running, false if not.


public function terminate()
    {
        if (function_exists('posix_kill')) {
            posix_kill($this->pid, 15);
        } elseif (PHP_OS === 'WINNT') {
            exec('taskkill /PID ' . escapeshellarg($this->pid));
        } else {
            exec('kill -15 ' . escapeshellarg($this->pid));
        }
    }

public
function
terminate
(
)
{
if
(
function_exists
(
'posix_kill'
)
)
{
posix_kill
(
$
this
->
pid
,
15
)
;
}
elseif
(
PHP_OS
===
'WINNT'
)
{
exec
(
'taskkill /PID '
.
escapeshellarg
(
$
this
->
pid
)
)
;
}
else
{
exec
(
'kill -15 '
.
escapeshellarg
(
$
this
->
pid
)
)
;
}
}

Ends the process gracefully

The signal SIGTERM is sent to the process. The gpg-agent process will
end gracefully upon receiving the SIGTERM signal. Upon 3 consecutive
SIGTERM signals the gpg-agent will forcefully shut down.

If the posix extension is available, posix_kill()
is used. Otherwise kill is used on UNIX-like systems and
taskkill is used in Windows.

@return void


public function setOperation($operation)
    {
        $op    = null;
        $opArg = null;

        // Regexp matching all GPG "operational" arguments
        $regexp = '/--('
            . 'version|import|list-public-keys|list-secret-keys'
            . '|list-keys|delete-key|delete-secret-key|encrypt|sign|clearsign'
            . '|detach-sign|decrypt|verify|export-secret-keys|export|gen-key'
            . ')/';

        if (strpos($operation, ' ') === false) {
            $op = trim($operation, '- ');
        } else if (preg_match($regexp, $operation, $matches, PREG_OFFSET_CAPTURE)) {
            $op      = trim($matches[0][0], '-');
            $op_len  = $matches[0][1] + mb_strlen($op, '8bit') + 3;
            $command = mb_substr($operation, $op_len, null, '8bit');

            // we really need the argument if it is a key ID/fingerprint or email
            // address se we can use simplified regexp to "revert escapeshellarg()"
            if (preg_match('/^[\'"]([a-zA-Z0-9:@._-]+)[\'"]/', $command, $matches)) {
                $opArg = $matches[1];
            }
        }

        $this->operation        = $op;
        $this->operationArg     = $opArg;
        $this->data['Warnings'] = array();
    }

Sets the operation that is being performed by the engine.

@param string $operation The GPG operation to perform.

@return void

Sets the operation that is being performed by the engine .


public function handleError($line)
    {
        if (stripos($line, 'gpg: WARNING: ') !== false) {
            $this->data['Warnings'][] = substr($line, 14);
        }

        if ($this->errorCode !== Crypt_GPG::ERROR_NONE) {
            return;
        }

        $pattern = '/no valid OpenPGP data found/';
        if (preg_match($pattern, $line) === 1) {
            $this->errorCode = Crypt_GPG::ERROR_NO_DATA;
            return;
        }

        $pattern = '/No secret key|secret key not available/';
        if (preg_match($pattern, $line) === 1) {
            $this->errorCode = Crypt_GPG::ERROR_KEY_NOT_FOUND;
            return;
        }

        $pattern = '/No public key|public key not found/';
        if (preg_match($pattern, $line) === 1) {
            $this->errorCode = Crypt_GPG::ERROR_KEY_NOT_FOUND;
            return;
        }

        $pattern = '/can\'t (?:access|open) `(.*?)\'/';
        if (preg_match($pattern, $line, $matches) === 1) {
            $this->data['ErrorFilename'] = $matches[1];
            $this->errorCode = Crypt_GPG::ERROR_FILE_PERMISSIONS;
            return;
        }

        // GnuPG 2.1: It should return MISSING_PASSPHRASE, but it does not
        // we have to detect it this way. This happens e.g. on private key import
        $pattern = '/key ([0-9A-F]+).* (Bad|No) passphrase/';
        if (preg_match($pattern, $line, $matches) === 1) {
            $keyId = $matches[1];
            // @TODO: Get user name/email
            if (empty($this->data['BadPassphrases'][$keyId])) {
                $this->data['BadPassphrases'][$keyId] = $keyId;
            }

            if ($matches[2] == 'Bad') {
                $this->errorCode = Crypt_GPG::ERROR_BAD_PASSPHRASE;
            } else {
                $this->errorCode = Crypt_GPG::ERROR_MISSING_PASSPHRASE;
                if (empty($this->data['MissingPassphrases'][$keyId])) {
                    $this->data['MissingPassphrases'][$keyId] = $keyId;
                }
            }

            return;
        }

        if ($this->operation == 'gen-key') {
            $pattern = '/:([0-9]+): invalid algorithm$/';
            if (preg_match($pattern, $line, $matches) === 1) {
                $this->errorCode          = Crypt_GPG::ERROR_BAD_KEY_PARAMS;
                $this->data['LineNumber'] = intval($matches[1]);
            }
        }
    }

Handles error values in the error output from GPG

This method is responsible for setting the
{@link Crypt_GPG_Engine::$_errorCode}.

@param string $line the error line to handle.

@return void


protected function setErrorCode($exitcode)
    {
        if ($this->needPassphrase > 0) {
            return Crypt_GPG::ERROR_MISSING_PASSPHRASE;
        }

        if ($this->operation == 'import') {
            return Crypt_GPG::ERROR_NONE;
        }

        if ($this->operation == 'decrypt' && !empty($this->data['DecryptionOkay'])) {
            if (!empty($this->data['IgnoreVerifyErrors'])) {
                return Crypt_GPG::ERROR_NONE;
            }
            if (!empty($this->data['MissingKeys'])) {
                return Crypt_GPG::ERROR_KEY_NOT_FOUND;
            }
        }

        return Crypt_GPG::ERROR_UNKNOWN;
    }

protected function setErrorCode ( $ exitcode ) { if ( $ this -> needPassphrase > 0 ) { return Crypt_GPG :: ERROR_MISSING_PASSPHRASE ; } if ( $ this -> operation == 'import' ) { return Crypt_GPG :: ERROR_NONE ; } if ( $ this -> operation == 'decrypt' && ! empty ( $ this -> data [ 'DecryptionOkay' ] ) ) { if ( ! empty ( $ this -> data [ 'IgnoreVerifyErrors' ] ) ) { return Crypt_GPG :: ERROR_NONE ; } if ( ! empty ( $ this -> data [ 'MissingKeys' ] ) ) { return Crypt_GPG :: ERROR_KEY_NOT_FOUND ; } } return Crypt_GPG :: ERROR_UNKNOWN ; }

Check exit code of the GPG operation.

@param int $exitcode GPG process exit code

@return int Internal error code


public function setData($name, $value)
    {
        switch ($name) {
        case 'Handle':
            $this->data[$name] = strval($value);
            break;

        case 'IgnoreVerifyErrors':
            $this->data[$name] = (bool) $value;
            break;
        }
    }

public function setData ( $ name , $ value ) { switch ( $ name ) { case 'Handle' : $ this -> data [ $ name ] = strval ( $ value ) ; break ; case 'IgnoreVerifyErrors' : $ this -> data [ $ name ] = ( bool ) $ value ; break ; } }

Set data for the process execution.

@param string $name  Data element name:
- Handle: The unique key handle used by this handler
The key handle is used to track GPG status output
for a particular key on --gen-key command before
the key has its own identifier.
- IgnoreVerifyErrors: Do not throw exceptions
when signature verification failes because
of a missing public key.
@param mixed  $value Data element value

@return void


protected function badPassException($code, $message)
    {
        $badPassphrases = array_diff_key(
            isset($this->data['BadPassphrases']) ? $this->data['BadPassphrases'] : array(),
            isset($this->data['MissingPassphrases']) ? $this->data['MissingPassphrases'] : array()
        );

        $missingPassphrases = array_intersect_key(
            isset($this->data['BadPassphrases']) ? $this->data['BadPassphrases'] : array(),
            isset($this->data['MissingPassphrases']) ? $this->data['MissingPassphrases'] : array()
        );

        if (count($badPassphrases) > 0) {
            $message .= ' Incorrect passphrase provided for keys: "' .
                implode('", "', $badPassphrases) . '".';
        }
        if (count($missingPassphrases) > 0) {
            $message .= ' No passphrase provided for keys: "' .
                implode('", "', $missingPassphrases) . '".';
        }

        return new Crypt_GPG_BadPassphraseException(
            $message,
            $code,
            $badPassphrases,
            $missingPassphrases
        );
    }

Create Crypt_GPG_BadPassphraseException from operation data.

@param int    $code    Error code
@param string $message Error message

@return Crypt_GPG_BadPassphraseException

Create Crypt_GPG_BadPassphraseException from operation data .


protected function getPin($key)
    {
        $passphrase  = '';
        $keyIdLength = mb_strlen($key, '8bit');

        if ($keyIdLength && !empty($_ENV['PINENTRY_USER_DATA'])) {
            $passphrases = json_decode($_ENV['PINENTRY_USER_DATA'], true);
            foreach ($passphrases as $_keyId => $pass) {
                $keyId        = $key;
                $_keyIdLength = mb_strlen($_keyId, '8bit');

                // Get last X characters of key identifier to compare
                if ($keyIdLength < $_keyIdLength) {
                    $_keyId = mb_substr($_keyId, -$keyIdLength, null, '8bit');
                } else if ($keyIdLength > $_keyIdLength) {
                    $keyId = mb_substr($keyId, -$_keyIdLength, null, '8bit');
                }

                if ($_keyId === $keyId) {
                    $passphrase = $pass;
                    break;
                }
            }
        }

        return $passphrase;
    }

Get registered passphrase for specified key.

@param string $key Key identifier

@return string Passphrase

Get registered passphrase for specified key .


public function getHashAlgorithmName()
    {
        if (!isset(self::$hashAlgorithmNames[$this->hashAlgorithm])) {
            return null;
        }
        return self::$hashAlgorithmNames[$this->hashAlgorithm];
    }

public function getHashAlgorithmName ( ) { if ( ! isset ( self :: $ hashAlgorithmNames [ $ this -> hashAlgorithm ] ) ) { return null ; } return self :: $ hashAlgorithmNames [ $ this -> hashAlgorithm ] ; }

Get a name for the used hashing algorithm.

@return string|null

Get a name for the used hashing algorithm .


public function setCanSign($canSign)
    {
        if ($canSign) {
            $this->_usage |= self::USAGE_SIGN;
        } else {
            $this->_usage &= ~self::USAGE_SIGN;
        }

        return $this;
    }

public function setCanSign ( $ canSign ) { if ( $ canSign ) { $ this -> _usage |= self :: USAGE_SIGN ; } else { $ this -> _usage &= ~ self :: USAGE_SIGN ; } return $ this ; }

Sets whether or not this sub-key can sign data

@param boolean $canSign true if this sub-key can sign data and false if
it can not.

@return Crypt_GPG_SubKey the current object, for fluent interface.

Sets whether or not this sub - key can sign data


public function setCanEncrypt($canEncrypt)
    {
        if ($canEncrypt) {
            $this->_usage |= self::USAGE_ENCRYPT;
        } else {
            $this->_usage &= ~self::USAGE_ENCRYPT;
        }

        return $this;
    }

public function setCanEncrypt ( $ canEncrypt ) { if ( $ canEncrypt ) { $ this -> _usage |= self :: USAGE_ENCRYPT ; } else { $ this -> _usage &= ~ self :: USAGE_ENCRYPT ; } return $ this ; }

Sets whether or not this sub-key can encrypt data

@param boolean $canEncrypt true if this sub-key can encrypt data and
false if it can not.

@return Crypt_GPG_SubKey the current object, for fluent interface.

Sets whether or not this sub - key can encrypt data


public static function parse($string)
    {
        $tokens = explode(':', $string);

        $subKey = new Crypt_GPG_SubKey();

        $subKey->setId($tokens[4]);
        $subKey->setLength($tokens[2]);
        $subKey->setAlgorithm($tokens[3]);
        $subKey->setCreationDate(self::_parseDate($tokens[5]));
        $subKey->setExpirationDate(self::_parseDate($tokens[6]));

        if ($tokens[1] == 'r') {
            $subKey->setRevoked(true);
        }

        $usage = 0;
        $usage_map = array(
            'a' => self::USAGE_AUTHENTICATION,
            'c' => self::USAGE_CERTIFY,
            'e' => self::USAGE_ENCRYPT,
            's' => self::USAGE_SIGN,
        );

        foreach ($usage_map as $key => $flag) {
            if (strpos($tokens[11], $key) !== false) {
                $usage |= $flag;
            }
        }

        $subKey->setUsage($usage);

        return $subKey;
    }

public static function parse ( $ string ) { $ tokens = explode ( ':' , $ string ) ; $ subKey = new Crypt_GPG_SubKey ( ) ; $ subKey -> setId ( $ tokens [ 4 ] ) ; $ subKey -> setLength ( $ tokens [ 2 ] ) ; $ subKey -> setAlgorithm ( $ tokens [ 3 ] ) ; $ subKey -> setCreationDate ( self :: _parseDate ( $ tokens [ 5 ] ) ) ; $ subKey -> setExpirationDate ( self :: _parseDate ( $ tokens [ 6 ] ) ) ; if ( $ tokens [ 1 ] == 'r' ) { $ subKey -> setRevoked ( true ) ; } $ usage = 0 ; $ usage_map = array ( 'a' => self :: USAGE_AUTHENTICATION , 'c' => self :: USAGE_CERTIFY , 'e' => self :: USAGE_ENCRYPT , 's' => self :: USAGE_SIGN , ) ; foreach ( $ usage_map as $ key => $ flag ) { if ( strpos ( $ tokens [ 11 ] , $ key ) !== false ) { $ usage |= $ flag ; } } $ subKey -> setUsage ( $ usage ) ; return $ subKey ; }

Parses a sub-key object from a sub-key string

See <b>doc/DETAILS</b> in the
{@link http://www.gnupg.org/download/ GPG distribution} for information
on how the sub-key string is parsed.

@param string $string the string containing the sub-key.

@return Crypt_GPG_SubKey the sub-key object parsed from the string.

Parses a sub - key object from a sub - key string


private static function _parseDate($string)
    {
        if ($string == '') {
            $timestamp = 0;
        } else {
            // all times are in UTC according to GPG documentation
            $timeZone = new DateTimeZone('UTC');

            if (strpos($string, 'T') === false) {
                // interpret as UNIX timestamp
                $string = '@' . $string;
            }

            $date = new DateTime($string, $timeZone);

            // convert to UNIX timestamp
            $timestamp = intval($date->format('U'));
        }

        return $timestamp;
    }

Parses a date string as provided by GPG into a UNIX timestamp

@param string $string the date string.

@return integer the UNIX timestamp corresponding to the provided date
string.


public function deletePublicKey($keyId)
    {
        $fingerprint = $this->getFingerprint($keyId);

        if ($fingerprint === null) {
            throw new Crypt_GPG_KeyNotFoundException(
                'Public key not found: ' . $keyId,
                self::ERROR_KEY_NOT_FOUND,
                $keyId
            );
        }

        $operation = '--delete-key ' . escapeshellarg($fingerprint);
        $arguments = array(
            '--batch',
            '--yes'
        );

        $this->engine->reset();
        $this->engine->setOperation($operation, $arguments);
        $this->engine->run();
    }

public
function
deletePublicKey
(
$
keyId
)
{
$
fingerprint
=
$
this
->
getFingerprint
(
$
keyId
)
;
if
(
$
fingerprint
===
)
{
throw
new
Crypt_GPG_KeyNotFoundException
(
'Public key not found: '
.
$
keyId
,
self
::
ERROR_KEY_NOT_FOUND
,
$
keyId
)
;
}
$
operation
=
'--delete-key '
.
escapeshellarg
(
$
fingerprint
)
;
$
arguments
=
array
(
'--batch'
,
'--yes'
)
;
$
this
->
engine
->
reset
(
)
;
$
this
->
engine
->
setOperation
(
$
operation
,
$
arguments
)
;
$
this
->
engine
->
run
(
)
;
}

Deletes a public key from the keyring

If more than one key fingerprint is available for the specified
$keyId (for example, if you use a non-unique uid) only the
first public key is deleted.

The private key must be deleted first or an exception will be thrown.
In GnuPG >= 2.1 this limitation does not exist.
See {@link Crypt_GPG::deletePrivateKey()}.

@param string $keyId either the full uid of the public key, the email
part of the uid of the public key or the key id of
the public key. For example,
"Test User (example) <test@example.com>",
"test@example.com" or a hexadecimal string.

@return void

@throws Crypt_GPG_KeyNotFoundException if a public key with the given
$keyId is not found.

@throws Crypt_GPG_DeletePrivateKeyException if the specified public key
has an associated private key on the keyring. The private key
must be deleted first (when using GnuPG < 2.1).

@throws Crypt_GPG_Exception if an unknown or unexpected error occurs.
Use the debug option and file a bug report if these
exceptions occur.


public function getFingerprint($keyId, $format = self::FORMAT_NONE)
    {
        $output    = '';
        $operation = '--list-keys ' . escapeshellarg($keyId);
        $arguments = array(
            '--with-colons',
            '--with-fingerprint'
        );

        $this->engine->reset();
        $this->engine->setOutput($output);
        $this->engine->setOperation($operation, $arguments);
        $this->engine->run();

        $fingerprint = null;

        foreach (explode(PHP_EOL, $output) as $line) {
            if (mb_substr($line, 0, 3, '8bit') == 'fpr') {
                $lineExp     = explode(':', $line);
                $fingerprint = $lineExp[9];

                switch ($format) {
                case self::FORMAT_CANONICAL:
                    $fingerprintExp = str_split($fingerprint, 4);
                    $format         = '%s %s %s %s %s  %s %s %s %s %s';
                    $fingerprint    = vsprintf($format, $fingerprintExp);
                    break;

                case self::FORMAT_X509:
                    $fingerprintExp = str_split($fingerprint, 2);
                    $fingerprint    = implode(':', $fingerprintExp);
                    break;
                }

                break;
            }
        }

        return $fingerprint;
    }

public
function
getFingerprint
(
$
keyId
,
$
format
=
self
::
FORMAT_NONE
)
{
$
output
=
''
;
$
operation
=
'--list-keys '
.
escapeshellarg
(
$
keyId
)
;
$
arguments
=
array
(
'--with-colons'
,
'--with-fingerprint'
)
;
$
this
->
engine
->
reset
(
)
;
$
this
->
engine
->
setOutput
(
$
output
)
;
$
this
->
engine
->
setOperation
(
$
operation
,
$
arguments
)
;
$
this
->
engine
->
run
(
)
;
$
fingerprint
=
;
foreach
(
explode
(
PHP_EOL
,
$
output
)
as
$
line
)
{
if
(
mb_substr
(
$
line
,
0
,
3
,
'8bit'
)
==
'fpr'
)
{
$
lineExp
=
explode
(
':'
,
$
line
)
;
$
fingerprint
=
$
lineExp
[
9
]
;
switch
(
$
format
)
{
case
self
::
FORMAT_CANONICAL
:
$
fingerprintExp
=
str_split
(
$
fingerprint
,
4
)
;
$
format
=
'%s %s %s %s %s  %s %s %s %s %s'
;
$
fingerprint
=
vsprintf
(
$
format
,
$
fingerprintExp
)
;
break
;
case
self
::
FORMAT_X509
:
$
fingerprintExp
=
str_split
(
$
fingerprint
,
2
)
;
$
fingerprint
=
implode
(
':'
,
$
fingerprintExp
)
;
break
;
}
break
;
}
}
return
$
fingerprint
;
}

Gets a key fingerprint from the keyring

If more than one key fingerprint is available (for example, if you use
a non-unique user id) only the first key fingerprint is returned.

Calls the GPG --list-keys command with the
--with-fingerprint option to retrieve a public key
fingerprint.

@param string  $keyId  either the full user id of the key, the email
part of the user id of the key, or the key id of
the key. For example,
"Test User (example) <test@example.com>",
"test@example.com" or a hexadecimal string.
@param integer $format optional. How the fingerprint should be formatted.
Use {@link Crypt_GPG::FORMAT_X509} for X.509
certificate format,
{@link Crypt_GPG::FORMAT_CANONICAL} for the format
used by GnuPG output and
{@link Crypt_GPG::FORMAT_NONE} for no formatting.
Defaults to Crypt_GPG::FORMAT_NONE.

@return string the fingerprint of the key, or null if no fingerprint
is found for the given $keyId.

@throws Crypt_GPG_Exception if an unknown or unexpected error occurs.
Use the debug option and file a bug report if these
exceptions occur.


public function encrypt($data, $armor = self::ARMOR_ASCII)
    {
        return $this->_encrypt($data, false, null, $armor);
    }

public function encrypt ( $ data , $ armor = self :: ARMOR_ASCII ) { return $ this -> _encrypt ( $ data , false , null , $ armor ) ; }

Encrypts string data

Data is ASCII armored by default but may optionally be returned as
binary.

@param string  $data  the data to be encrypted.
@param boolean $armor optional. If true, ASCII armored data is returned;
otherwise, binary data is returned. Defaults to
true.

@return string the encrypted data.

@throws Crypt_GPG_KeyNotFoundException if no encryption key is specified.
See {@link Crypt_GPG::addEncryptKey()}.

@throws Crypt_GPG_Exception if an unknown or unexpected error occurs.
Use the <kbd>debug</kbd> option and file a bug report if these
exceptions occur.

@sensitive $data


public function encryptFile(
        $filename,
        $encryptedFile = null,
        $armor = self::ARMOR_ASCII
    ) {
        return $this->_encrypt($filename, true, $encryptedFile, $armor);
    }

public function encryptFile ( $ filename , $ encryptedFile = null , $ armor = self :: ARMOR_ASCII ) { return $ this -> _encrypt ( $ filename , true , $ encryptedFile , $ armor ) ; }

Encrypts a file

Encrypted data is ASCII armored by default but may optionally be saved
as binary.

@param string  $filename      the filename of the file to encrypt.
@param string  $encryptedFile optional. The filename of the file in
which to store the encrypted data. If null
or unspecified, the encrypted data is
returned as a string.
@param boolean $armor         optional. If true, ASCII armored data is
returned; otherwise, binary data is
returned. Defaults to true.

@return void|string if the $encryptedFile parameter is null,
a string containing the encrypted data is returned.

@throws Crypt_GPG_KeyNotFoundException if no encryption key is specified.
See {@link Crypt_GPG::addEncryptKey()}.

@throws Crypt_GPG_FileException if the output file is not writeable or
if the input file is not readable.

@throws Crypt_GPG_Exception if an unknown or unexpected error occurs.
Use the debug option and file a bug report if these
exceptions occur.


public function encryptAndSign($data, $armor = self::ARMOR_ASCII)
    {
        return $this->_encryptAndSign($data, false, null, $armor);
    }

public function encryptAndSign ( $ data , $ armor = self :: ARMOR_ASCII ) { return $ this -> _encryptAndSign ( $ data , false , null , $ armor ) ; }

Encrypts and signs data

Data is encrypted and signed in a single pass.

NOTE: Until GnuPG version 1.4.10, it was not possible to verify
encrypted-signed data without decrypting it at the same time. If you try
to use {@link Crypt_GPG::verify()} method on encrypted-signed data with
earlier GnuPG versions, you will get an error. Please use
{@link Crypt_GPG::decryptAndVerify()} to verify encrypted-signed data.

@param string  $data  the data to be encrypted and signed.
@param boolean $armor optional. If true, ASCII armored data is returned;
otherwise, binary data is returned. Defaults to
true.

@return string the encrypted signed data.

@throws Crypt_GPG_KeyNotFoundException if no encryption key is specified
or if no signing key is specified. See
{@link Crypt_GPG::addEncryptKey()} and
{@link Crypt_GPG::addSignKey()}.

@throws Crypt_GPG_BadPassphraseException if a specified passphrase is
incorrect or if a required passphrase is not specified.

@throws Crypt_GPG_Exception if an unknown or unexpected error occurs.
Use the <kbd>debug</kbd> option and file a bug report if these
exceptions occur.

@see Crypt_GPG::decryptAndVerify()


public function encryptAndSignFile(
        $filename,
        $signedFile = null,
        $armor = self::ARMOR_ASCII
    ) {
        return $this->_encryptAndSign($filename, true, $signedFile, $armor);
    }

public function encryptAndSignFile ( $ filename , $ signedFile = null , $ armor = self :: ARMOR_ASCII ) { return $ this -> _encryptAndSign ( $ filename , true , $ signedFile , $ armor ) ; }

Encrypts and signs a file

The file is encrypted and signed in a single pass.

NOTE: Until GnuPG version 1.4.10, it was not possible to verify
encrypted-signed files without decrypting them at the same time. If you
try to use {@link Crypt_GPG::verify()} method on encrypted-signed files
with earlier GnuPG versions, you will get an error. Please use
{@link Crypt_GPG::decryptAndVerifyFile()} to verify encrypted-signed
files.

@param string  $filename   the name of the file containing the data to
be encrypted and signed.
@param string  $signedFile optional. The name of the file in which the
encrypted, signed data should be stored. If
null or unspecified, the encrypted, signed
data is returned as a string.
@param boolean $armor      optional. If true, ASCII armored data is
returned; otherwise, binary data is returned.
Defaults to true.

@return void|string if the $signedFile parameter is null, a
string containing the encrypted, signed data is
returned.

@throws Crypt_GPG_KeyNotFoundException if no encryption key is specified
or if no signing key is specified. See
{@link Crypt_GPG::addEncryptKey()} and
{@link Crypt_GPG::addSignKey()}.

@throws Crypt_GPG_BadPassphraseException if a specified passphrase is
incorrect or if a required passphrase is not specified.

@throws Crypt_GPG_FileException if the output file is not writeable or
if the input file is not readable.

@throws Crypt_GPG_Exception if an unknown or unexpected error occurs.
Use the debug option and file a bug report if these
exceptions occur.

@see Crypt_GPG::decryptAndVerifyFile()


public function decryptAndVerify($encryptedData, $ignoreVerifyErrors = false)
    {
        return $this->_decryptAndVerify($encryptedData, false, null, $ignoreVerifyErrors);
    }

public function decryptAndVerify ( $ encryptedData , $ ignoreVerifyErrors = false ) { return $ this -> _decryptAndVerify ( $ encryptedData , false , null , $ ignoreVerifyErrors ) ; }

Decrypts and verifies string data

This method assumes the required private key is available in the keyring
and throws an exception if the private key is not available. To add a
private key to the keyring, use the {@link Crypt_GPG::importKey()} or
{@link Crypt_GPG::importKeyFile()} methods.

@param string  $encryptedData      the encrypted, signed data to be decrypted
and verified.
@param boolean $ignoreVerifyErrors enables ignoring of signature
verification errors caused by missing public key
When enabled Crypt_GPG_KeyNotFoundException
will not be thrown.

@return array two element array. The array has an element 'data'
containing the decrypted data and an element
'signatures' containing an array of
{@link Crypt_GPG_Signature} objects for the signed data.

@throws Crypt_GPG_KeyNotFoundException if the private key needed to
decrypt the data or the public key to verify the signature
is not in the user's keyring.

@throws Crypt_GPG_NoDataException if specified data does not contain
GPG encrypted data.

@throws Crypt_GPG_BadPassphraseException if a required passphrase is
incorrect or if a required passphrase is not specified. See
{@link Crypt_GPG::addDecryptKey()}.

@throws Crypt_GPG_Exception if an unknown or unexpected error occurs.
Use the <kbd>debug</kbd> option and file a bug report if these
exceptions occur.


public function decryptAndVerifyFile($encryptedFile, $decryptedFile = null, $ignoreVerifyErrors = false)
    {
        return $this->_decryptAndVerify($encryptedFile, true, $decryptedFile, $ignoreVerifyErrors);
    }

public function decryptAndVerifyFile ( $ encryptedFile , $ decryptedFile = null , $ ignoreVerifyErrors = false ) { return $ this -> _decryptAndVerify ( $ encryptedFile , true , $ decryptedFile , $ ignoreVerifyErrors ) ; }

Decrypts and verifies a signed, encrypted file

This method assumes the required private key is available in the keyring
and throws an exception if the private key is not available. To add a
private key to the keyring, use the {@link Crypt_GPG::importKey()} or
{@link Crypt_GPG::importKeyFile()} methods.

@param string  $encryptedFile      the name of the signed, encrypted file to
to decrypt and verify.
@param string  $decryptedFile      optional. The name of the file to which the
decrypted data should be written. If null
or unspecified, the decrypted data is
returned in the results array.
@param boolean $ignoreVerifyErrors enables ignoring of signature
verification errors caused by missing public key
When enabled Crypt_GPG_KeyNotFoundException
will not be thrown.

@return array two element array. The array has an element 'data'
containing the decrypted data and an element
'signatures' containing an array of
{@link Crypt_GPG_Signature} objects for the signed data.
If the decrypted data is written to a file, the 'data'
element is null.

@throws Crypt_GPG_KeyNotFoundException if the private key needed to
decrypt the data or the public key to verify the signature
is not in the user's keyring.

@throws Crypt_GPG_NoDataException if specified data does not contain
GPG encrypted data.

@throws Crypt_GPG_BadPassphraseException if a required passphrase is
incorrect or if a required passphrase is not specified. See
{@link Crypt_GPG::addDecryptKey()}.

@throws Crypt_GPG_FileException if the output file is not writeable or
if the input file is not readable.

@throws Crypt_GPG_Exception if an unknown or unexpected error occurs.
Use the <kbd>debug</kbd> option and file a bug report if these
exceptions occur.

Decrypts and verifies a signed encrypted file


public function signFile(
        $filename,
        $signedFile = null,
        $mode = self::SIGN_MODE_NORMAL,
        $armor = self::ARMOR_ASCII,
        $textmode = self::TEXT_RAW
    ) {
        return $this->_sign(
            $filename,
            true,
            $signedFile,
            $mode,
            $armor,
            $textmode
        );
    }

public function signFile ( $ filename , $ signedFile = null , $ mode = self :: SIGN_MODE_NORMAL , $ armor = self :: ARMOR_ASCII , $ textmode = self :: TEXT_RAW ) { return $ this -> _sign ( $ filename , true , $ signedFile , $ mode , $ armor , $ textmode ) ; }

Signs a file

The file may be signed using any one of the three available signing
modes:
- {@link Crypt_GPG::SIGN_MODE_NORMAL}
- {@link Crypt_GPG::SIGN_MODE_CLEAR}
- {@link Crypt_GPG::SIGN_MODE_DETACHED}

@param string  $filename   the name of the file containing the data to
be signed.
@param string  $signedFile optional. The name of the file in which the
signed data should be stored. If null or
unspecified, the signed data is returned as a
string.
@param int     $mode       optional. The data signing mode to use. Should
be one of {@link Crypt_GPG::SIGN_MODE_NORMAL},
{@link Crypt_GPG::SIGN_MODE_CLEAR} or
{@link Crypt_GPG::SIGN_MODE_DETACHED}. If not
specified, defaults to
Crypt_GPG::SIGN_MODE_NORMAL.
@param boolean $armor      optional. If true, ASCII armored data is
returned; otherwise, binary data is returned.
Defaults to true. This has no effect if the
mode Crypt_GPG::SIGN_MODE_CLEAR is
used.
@param boolean $textmode   optional. If true, line-breaks in signed data
are normalized. Use this option when signing
e-mail, or for greater compatibility between
systems with different line-break formats.
Defaults to false. This has no effect if the
mode Crypt_GPG::SIGN_MODE_CLEAR is
used as clear-signing always uses textmode.

@return void|string if the $signedFile parameter is null, a
string containing the signed data (or the signature
data if a detached signature is requested) is
returned.

@throws Crypt_GPG_KeyNotFoundException if no signing key is specified.
See {@link Crypt_GPG::addSignKey()}.

@throws Crypt_GPG_BadPassphraseException if a specified passphrase is
incorrect or if a required passphrase is not specified.

@throws Crypt_GPG_FileException if the output file is not writeable or
if the input file is not readable.

@throws Crypt_GPG_Exception if an unknown or unexpected error occurs.
Use the debug option and file a bug report if these
exceptions occur.


public function addDecryptKey($key, $passphrase = null)
    {
        $this->_addKey($this->decryptKeys, false, false, $key, $passphrase);
        return $this;
    }

public function addDecryptKey ( $ key , $ passphrase = null ) { $ this -> _addKey ( $ this -> decryptKeys , false , false , $ key , $ passphrase ) ; return $ this ; }

Adds a key to use for decryption

@param mixed  $key        the key to use. This may be a key identifier,
user id, fingerprint, {@link Crypt_GPG_Key} or
{@link Crypt_GPG_SubKey}. The key must be able
to encrypt.
@param string $passphrase optional. The passphrase of the key required
for decryption.

@return Crypt_GPG the current object, for fluent interface.

@see Crypt_GPG::decrypt()
@see Crypt_GPG::decryptFile()
@see Crypt_GPG::clearDecryptKeys()
@see Crypt_GPG::_addKey()

@sensitive $passphrase


public function addEncryptKey($key)
    {
        $this->_addKey($this->encryptKeys, true, false, $key);
        return $this;
    }

public function addEncryptKey ( $ key ) { $ this -> _addKey ( $ this -> encryptKeys , true , false , $ key ) ; return $ this ; }

Adds a key to use for encryption

@param mixed $key the key to use. This may be a key identifier, user id
user id, fingerprint, {@link Crypt_GPG_Key} or
{@link Crypt_GPG_SubKey}. The key must be able to
encrypt.

@return Crypt_GPG the current object, for fluent interface.

@see Crypt_GPG::encrypt()
@see Crypt_GPG::encryptFile()
@see Crypt_GPG::clearEncryptKeys()
@see Crypt_GPG::_addKey()


public function addSignKey($key, $passphrase = null)
    {
        $this->_addKey($this->signKeys, false, true, $key, $passphrase);
        return $this;
    }

public function addSignKey ( $ key , $ passphrase = null ) { $ this -> _addKey ( $ this -> signKeys , false , true , $ key , $ passphrase ) ; return $ this ; }

Adds a key to use for signing

@param mixed  $key        the key to use. This may be a key identifier,
user id, fingerprint, {@link Crypt_GPG_Key} or
{@link Crypt_GPG_SubKey}. The key must be able
to sign.
@param string $passphrase optional. The passphrase of the key required
for signing.

@return Crypt_GPG the current object, for fluent interface.

@see Crypt_GPG::sign()
@see Crypt_GPG::signFile()
@see Crypt_GPG::clearSignKeys()
@see Crypt_GPG::_addKey()

@sensitive $passphrase


protected function _addKey(array &$array, $encrypt, $sign, $key,
        $passphrase = null
    ) {
        $subKeys = array();

        if (is_scalar($key)) {
            $keys = $this->getKeys($key);
            if (count($keys) == 0) {
                throw new Crypt_GPG_KeyNotFoundException(
                    'Key not found: ' . $key,
                    self::ERROR_KEY_NOT_FOUND,
                    $key
                );
            }
            $key = $keys[0];
        }

        if ($key instanceof Crypt_GPG_Key) {
            if ($encrypt && !$key->canEncrypt()) {
                throw new InvalidArgumentException(
                    'Key "' . $key . '" cannot encrypt.'
                );
            }

            if ($sign && !$key->canSign()) {
                throw new InvalidArgumentException(
                    'Key "' . $key . '" cannot sign.'
                );
            }

            foreach ($key->getSubKeys() as $subKey) {
                $canEncrypt = $subKey->canEncrypt();
                $canSign    = $subKey->canSign();
                if (($encrypt && $sign && $canEncrypt && $canSign)
                    || ($encrypt && !$sign && $canEncrypt)
                    || (!$encrypt && $sign && $canSign)
                    || (!$encrypt && !$sign)
                ) {
                    // We add all subkeys that meet the requirements because we
                    // were not told which subkey is required.
                    $subKeys[] = $subKey;
                }
            }
        } elseif ($key instanceof Crypt_GPG_SubKey) {
            $subKeys[] = $key;
        }

        if (count($subKeys) === 0) {
            throw new InvalidArgumentException(
                'Key "' . $key . '" is not in a recognized format.'
            );
        }

        foreach ($subKeys as $subKey) {
            if ($encrypt && !$subKey->canEncrypt()) {
                throw new InvalidArgumentException(
                    'Key "' . $key . '" cannot encrypt.'
                );
            }

            if ($sign && !$subKey->canSign()) {
                throw new InvalidArgumentException(
                    'Key "' . $key . '" cannot sign.'
                );
            }

            $array[$subKey->getId()] = array(
                'fingerprint' => $subKey->getFingerprint(),
                'passphrase'  => $passphrase
            );
        }
    }

Adds a key to one of the internal key arrays

This handles resolving full key objects from the provided
<kbd>$key</kbd> value.

@param array   &$array     the array to which the key should be added.
@param boolean $encrypt    whether or not the key must be able to
encrypt.
@param boolean $sign       whether or not the key must be able to sign.
@param mixed   $key        the key to add. This may be a key identifier,
user id, fingerprint, {@link Crypt_GPG_Key} or
{@link Crypt_GPG_SubKey}.
@param string  $passphrase optional. The passphrase associated with the
key.

@return void

@sensitive $passphrase


protected function _importKey($key, $isFile)
    {
        $result    = array();
        $arguments = array();
        $input     = $this->_prepareInput($key, $isFile, false);
        $version   = $this->engine->getVersion();

        if (version_compare($version, '1.0.5', 'ge')
            && version_compare($version, '1.0.7', 'lt')
        ) {
            $arguments[] = '--allow-secret-key-import';
        }

        if (empty($this->passphrases)) {
            $arguments[] = '--batch';
        }

        $this->engine->reset();
        $this->engine->setPins($this->passphrases);
        $this->engine->setOperation('--import', $arguments);
        $this->engine->setInput($input);
        $this->engine->run();

        return $this->engine->getProcessData('Import');
    }

protected function _importKey ( $ key , $ isFile ) { $ result = array ( ) ; $ arguments = array ( ) ; $ input = $ this -> _prepareInput ( $ key , $ isFile , false ) ; $ version = $ this -> engine -> getVersion ( ) ; if ( version_compare ( $ version , '1.0.5' , 'ge' ) && version_compare ( $ version , '1.0.7' , 'lt' ) ) { $ arguments [ ] = '--allow-secret-key-import' ; } if ( empty ( $ this -> passphrases ) ) { $ arguments [ ] = '--batch' ; } $ this -> engine -> reset ( ) ; $ this -> engine -> setPins ( $ this -> passphrases ) ; $ this -> engine -> setOperation ( '--import' , $ arguments ) ; $ this -> engine -> setInput ( $ input ) ; $ this -> engine -> run ( ) ; return $ this -> engine -> getProcessData ( 'Import' ) ; }

Imports a public or private key into the keyring

@param string  $key    the key to be imported.
@param boolean $isFile whether or not the input is a filename.

@return array an associative array containing the following elements:
- fingerprint       - the fingerprint of the
imported key,
- public_imported   - the number of public
keys imported,
- public_unchanged  - the number of unchanged
public keys,
- private_imported  - the number of private
keys imported,
- private_unchanged - the number of unchanged
private keys.

@throws Crypt_GPG_NoDataException if the key data is missing or if the
data is is not valid key data.

@throws Crypt_GPG_FileException if the key file is not readable.

@throws Crypt_GPG_BadPassphraseException if a required passphrase is
incorrect or if a required passphrase is not specified. See
{@link Crypt_GPG::addPassphrase()}.

@throws Crypt_GPG_Exception if an unknown or unexpected error occurs.
Use the debug option and file a bug report if these
exceptions occur.


protected function _exportKey($keyId, $armor = true, $private = false)
    {
        $fingerprint = $this->getFingerprint($keyId);

        if ($fingerprint === null) {
            throw new Crypt_GPG_KeyNotFoundException(
                'Key not found: ' . $keyId,
                self::ERROR_KEY_NOT_FOUND,
                $keyId
            );
        }

        $keyData   = '';
        $operation = $private ? '--export-secret-keys' : '--export';
        $operation .= ' ' . escapeshellarg($fingerprint);
        $arguments = $armor ? array('--armor') : array();

        $this->engine->reset();
        $this->engine->setPins($this->passphrases);
        $this->engine->setOutput($keyData);
        $this->engine->setOperation($operation, $arguments);
        $this->engine->run();

        return $keyData;
    }

protected
function
_exportKey
(
$
keyId
,
$
armor
=
true
,
$
private
=
false
)
{
$
fingerprint
=
$
this
->
getFingerprint
(
$
keyId
)
;
if
(
$
fingerprint
===
)
{
throw
new
Crypt_GPG_KeyNotFoundException
(
'Key not found: '
.
$
keyId
,
self
::
ERROR_KEY_NOT_FOUND
,
$
keyId
)
;
}
$
keyData
=
''
;
$
operation
=
$
private
'--export-secret-keys'
:
'--export'
;
$
operation
.=
' '
.
escapeshellarg
(
$
fingerprint
)
;
$
arguments
=
$
armor
array
(
'--armor'
)
:
array
(
)
;
$
this
->
engine
->
reset
(
)
;
$
this
->
engine
->
setPins
(
$
this
->
passphrases
)
;
$
this
->
engine
->
setOutput
(
$
keyData
)
;
$
this
->
engine
->
setOperation
(
$
operation
,
$
arguments
)
;
$
this
->
engine
->
run
(
)
;
return
$
keyData
;
}

Exports a private or public key from the keyring

If more than one key fingerprint is available for the specified
$keyId (for example, if you use a non-unique uid) only the
first key is exported.

@param string  $keyId   either the full uid of the key, the email
part of the uid of the key or the key id.
@param boolean $armor   optional. If true, ASCII armored data is returned;
otherwise, binary data is returned. Defaults to
true.
@param boolean $private return private instead of public key

@return string the key data.

@throws Crypt_GPG_KeyNotFoundException if a key with the given
$keyId is not found.

@throws Crypt_GPG_BadPassphraseException if a required passphrase is
incorrect or if a required passphrase is not specified. See
{@link Crypt_GPG::addPassphrase()}.

@throws Crypt_GPG_Exception if an unknown or unexpected error occurs.
Use the debug option and file a bug report if these
exceptions occur.