Code Coverage
 
Classes and Traits
Functions and Methods
Lines
Total
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
8 / 8
CRAP
100.00% covered (success)
100.00%
27 / 27
Token
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
8 / 8
14
100.00% covered (success)
100.00%
27 / 27
 __construct
100.00% covered (success)
100.00%
1 / 1
1
100.00% covered (success)
100.00%
2 / 2
 expiresIn
100.00% covered (success)
100.00%
1 / 1
2
100.00% covered (success)
100.00%
4 / 4
 toString
100.00% covered (success)
100.00%
1 / 1
2
100.00% covered (success)
100.00%
4 / 4
 __toString
100.00% covered (success)
100.00%
1 / 1
1
100.00% covered (success)
100.00%
1 / 1
 jsonSerialize
100.00% covered (success)
100.00%
1 / 1
1
100.00% covered (success)
100.00%
1 / 1
 equals
100.00% covered (success)
100.00%
1 / 1
2
100.00% covered (success)
100.00%
3 / 3
 isExpired
100.00% covered (success)
100.00%
1 / 1
2
100.00% covered (success)
100.00%
3 / 3
 fromString
100.00% covered (success)
100.00%
1 / 1
3
100.00% covered (success)
100.00%
9 / 9
<?php declare(strict_types = 1);
/**
 * Copyright (c) 2016 Holger Woltersdorf & Contributors
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 */
namespace IceHawk\Forms\Security;
use IceHawk\Forms\Exceptions\InvalidExpiryInterval;
use IceHawk\Forms\Exceptions\InvalidTokenString;
use IceHawk\Forms\Interfaces\IdentifiesFormRequestSource;
/**
 * Class Token
 * @package IceHawk\Forms\Security
 */
final class Token implements IdentifiesFormRequestSource
{
    const DELIMITER   = '[expiry]';
    const DATE_FORMAT = 'Y-m-d H:i:s';
    /** @var string */
    private $token;
    /** @var \DateTimeImmutable */
    private $expiry;
    public function __construct()
    {
        $this->token = base64_encode( random_bytes( 64 ) );
    }
    public function expiresIn( int $seconds ) : Token
    {
        if ( $seconds > 0 )
        {
            $this->expiry = new \DateTimeImmutable( sprintf( '+%d seconds', $seconds ) );
            return $this;
        }
        throw (new InvalidExpiryInterval())->withSeconds( $seconds );
    }
    public function toString() : string
    {
        if ( $this->expiry instanceof \DateTimeImmutable )
        {
            $rawToken = $this->token . self::DELIMITER . $this->expiry->format( self::DATE_FORMAT );
        }
        else
        {
            $rawToken = $this->token;
        }
        return base64_encode( $rawToken );
    }
    public function __toString() : string
    {
        return $this->toString();
    }
    public function jsonSerialize()
    {
        return $this->toString();
    }
    public function equals( IdentifiesFormRequestSource $other ) : bool
    {
        if ( $other instanceof Token )
        {
            return ($other->token == $this->token);
        }
        return false;
    }
    public function isExpired() : bool
    {
        if ( $this->expiry instanceof \DateTimeImmutable )
        {
            return (new \DateTimeImmutable() > $this->expiry);
        }
        return false;
    }
    public static function fromString( string $tokenString ) : Token
    {
        $rawToken = base64_decode( $tokenString, true );
        if ( $rawToken !== false )
        {
            $parts = explode( self::DELIMITER, $rawToken );
            $token        = new self();
            $token->token = $parts[0];
            if ( count( $parts ) == 2 )
            {
                $token->expiry = \DateTimeImmutable::createFromFormat( self::DATE_FORMAT, $parts[1] );
            }
            return $token;
        }
        throw (new InvalidTokenString())->withTokenString( $tokenString );
    }
}