| 
<?phpdeclare(strict_types=1);
 namespace ParagonIE\Paseto\Parsing;
 
 use ParagonIE\ConstantTime\Base64UrlSafe;
 use ParagonIE\Paseto\Exception\{
 SecurityException,
 InvalidVersionException,
 InvalidPurposeException
 };
 
 /**
 * Class PasetoMessage
 * @package ParagonIE\Paseto\Parsing
 */
 final class PasetoMessage
 {
 /** @var Header */
 private $header;
 
 /** @var string */
 private $payload;
 
 /** @var string */
 private $footer;
 
 /**
 * PasetoMessage constructor.
 *
 * @param Header $header
 * @param string $payload
 * @param string $footer
 */
 public function __construct(Header $header, string $payload, string $footer)
 {
 $this->header  = $header;
 $this->payload = $payload;
 $this->footer  = $footer;
 }
 
 /**
 * Parse a string into a deconstructed PasetoMessage object.
 *
 * @param string $tainted      Tainted user-provided string.
 * @return self
 *
 * @throws SecurityException
 * @throws InvalidVersionException
 * @throws InvalidPurposeException
 * @return PasetoMessage
 * @throws \TypeError
 */
 public static function fromString(string $tainted): self
 {
 /** @var array<int, string> $pieces */
 $pieces = \explode('.', $tainted);
 $count = \count($pieces);
 if ($count < 3 || $count > 4) {
 throw new SecurityException('Truncated or invalid token');
 }
 
 $header = new Header($pieces[0], $pieces[1]);
 $payload = Base64UrlSafe::decode($pieces[2]);
 $footer = $count > 3 ? Base64UrlSafe::decode($pieces[3]) : '';
 
 return new self($header, $payload, $footer);
 }
 
 public function header(): Header
 {
 return $this->header;
 }
 
 public function payload(): string
 {
 return $this->payload;
 }
 
 public function footer(): string
 {
 return $this->footer;
 }
 
 /**
 * @return string
 * @throws \TypeError
 */
 public function toString(): string
 {
 $message =  $this->header->toString()
 . Base64UrlSafe::encodeUnpadded($this->payload)
 ;
 
 if ($this->footer === '') {
 return $message;
 }
 
 return $message . "." . Base64UrlSafe::encodeUnpadded($this->footer);
 }
 }
 
 |