diff --git a/src/Records/Record.php b/src/Records/Record.php index 90990fa..016e7f8 100644 --- a/src/Records/Record.php +++ b/src/Records/Record.php @@ -38,7 +38,14 @@ public function __construct(array $attributes) $key = str_replace('-', '_', $key); if (property_exists($this, $key)) { - $this->$key = $this->cast($key, $value); + $return = $this->cast($key, $value); + if(is_array($return)){ + foreach($return as $key => $subvalue){ + $this->$key = $subvalue; + } + } else { + $this->$key = $return; + } } } } @@ -141,4 +148,11 @@ protected function castType(string $value): string { return mb_strtoupper($value); } + + protected function castV(string $value): object + { + preg_match('/v=([a-zA-Z0-9]+);?\W(.*)/', $value, $matches); + $v = "Spatie\\Dns\\TXTRecords\\".mb_strtoupper($matches[1]); + return new $v($matches[2]); + } } diff --git a/src/Records/TXT.php b/src/Records/TXT.php index 3c73d96..bd53685 100644 --- a/src/Records/TXT.php +++ b/src/Records/TXT.php @@ -2,18 +2,22 @@ namespace Spatie\Dns\Records; +use Spatie\Dns\TXTRecords; + /** * @method string txt() + * @method object v() */ class TXT extends Record { protected string $txt; + protected object $v; public static function parse(string $line): ?self { - $attributes = static::lineToArray($line, 5); + $attributes = static::lineToArray($line, 6); - if (count($attributes) < 5) { + if (count($attributes) < 6) { return null; } @@ -23,17 +27,25 @@ public static function parse(string $line): ?self 'class' => $attributes[2], 'type' => $attributes[3], 'txt' => $attributes[4], + 'v' => $attributes[5] ]); } public function __toString(): string { - return "{$this->host}.\t\t{$this->ttl}\t{$this->class}\t{$this->type}\t\"{$this->txt}\""; + return "{$this->host}.\t\t{$this->ttl}\t{$this->class}\t{$this->type}\t\"{$this->txt}\t\"{$this->v}\""; + } + + protected function castTxt(string $value): array + { + return array('txt' => $this->prepareText($value), 'v' => $this->castV($value)); } - protected function castTxt(string $value): string + protected function castV(string $value): object { - return $this->prepareText($value); + preg_match('/v=([a-zA-Z0-9]+);?\W(.*)/', $value, $matches); + $v = "Spatie\\Dns\\TXTRecords\\".mb_strtoupper($matches[1]); + return new $v($matches[2]); } public function toArray() @@ -44,6 +56,7 @@ public function toArray() 'class' => $this->class, 'type' => $this->type, 'txt' => $this->txt, + 'v' => $this->v ]; } } diff --git a/src/TXTRecords/BIMI1.php b/src/TXTRecords/BIMI1.php new file mode 100644 index 0000000..f5c8aad --- /dev/null +++ b/src/TXTRecords/BIMI1.php @@ -0,0 +1,35 @@ +type = 'BIMI'; + $this->version = 1; + $this->l = $this->cast('l',$value); + $this->a = $this->cast('a',$value); + } + + function castL(string $value): string + { + preg_match('/l=(https\:\/\/[a-zA-Z0-9\-\.]+\.[a-zA-Z]{2,3}\/\S*)?/', $value, $matches); + if(count($matches) < 2){ + return ""; + } + return str_replace(";", "",$this->prepareText($matches[1])); + } + + function castA(string $value): string + { + preg_match('/a=(https\:\/\/[a-zA-Z0-9\-\.]+\.[a-zA-Z]{2,3}\/\S*)?/', $value, $matches); + if(count($matches) < 2){ + return ""; + } + return str_replace(";", "",$this->prepareText($matches[1])); + } +} \ No newline at end of file diff --git a/src/TXTRecords/DKIM1.php b/src/TXTRecords/DKIM1.php new file mode 100644 index 0000000..64817b7 --- /dev/null +++ b/src/TXTRecords/DKIM1.php @@ -0,0 +1,35 @@ +type = 'DKIM'; + $this->version = 1; + $this->k = $this->cast('k',$value); + $this->p = $this->cast('p',$value); + } + + function castK(string $value): string + { + preg_match('/k=([a-zA-Z0-9]+)/', $value, $matches); + if(count($matches) < 2){ + return ""; + } + return str_replace(";", "",$this->prepareText($matches[1])); + } + + function castP(string $value): string + { + preg_match('/p=([a-zA-Z0-9_\/\+-=]+)/', $value, $matches); + if(count($matches) < 2){ + return ""; + } + return str_replace(";", "",$this->prepareText($matches[1])); + } +} \ No newline at end of file diff --git a/src/TXTRecords/DMARC1.php b/src/TXTRecords/DMARC1.php new file mode 100644 index 0000000..942ee95 --- /dev/null +++ b/src/TXTRecords/DMARC1.php @@ -0,0 +1,91 @@ +type = 'DMARC'; + $this->version = 1; + $this->p = $this->cast('p',$value); + $this->rua = $this->cast('rua',$value); + $this->ruf = $this->cast('ruf',$value); + $this->sp = $this->cast('sp',$value); + $this->pct = $this->cast('pct',$value); + $this->fo = $this->cast('fo',$value); + } + + function castP(string $value): string + { + preg_match('/p=(none|quarantine|reject)/', $value, $matches); + if(count($matches) < 2){ + return ""; + } + return str_replace(";", "",$this->prepareText($matches[1])); + } + + function castRua(string $value): array + { + preg_match("/rua=([^;]*)(?:;|$)/i", $value, $matches); + if (isset($matches[1])) { + $emails = preg_split("/\s*,/", $matches[1]); + foreach ($emails as $key => $email) { + $emails[$key] = $this->prepareText($email); + } + } + else { + return array(); + } + return $emails; + } + + function castRuf(string $value): array + { + preg_match("/ruf=([^;]*)(?:;|$)/i", $value, $matches); + if (isset($matches[1])) { + $emails = preg_split("/\s*,/", $matches[1]); + foreach ($emails as $key => $email) { + $emails[$key] = $this->prepareText($email); + } + } + else { + return array(); + } + return $emails; + } + + function castSp(string $value): string + { + preg_match('/sp=(none|quarantine|reject)/', $value, $matches); + if(count($matches) < 2){ + return ""; + } + return str_replace(";", "",$this->prepareText($matches[1])); + } + + function castPct(string $value): int + { + preg_match('/pct=([0-9]{1-3}+)/', $value, $matches); + if(count($matches) < 2){ + return 100; + } + return str_replace(";", "",$this->prepareInt($matches[1])); + } + + function castFo(string $value): string + { + preg_match('/fo=([a-zA-Z0-9:]+)/', $value, $matches); + if(count($matches) < 2){ + return ""; + } + return str_replace(";", "",$this->prepareText($matches[1])); + } +} \ No newline at end of file diff --git a/src/TXTRecords/SPF1.php b/src/TXTRecords/SPF1.php new file mode 100644 index 0000000..68dbe22 --- /dev/null +++ b/src/TXTRecords/SPF1.php @@ -0,0 +1,27 @@ +type = 'SPF'; + $this->version = 1; + $this->value = $this->cast('value',$value); + } + + function castValue(string $value): array + { + preg_match_all('/([a-zA-Z0-9:\.-~?]+)+/', $value, $matches); + if(count($matches) < 1){ + return array(); + } + foreach ($matches[1] as $key => $match) { + $matches[1][$key] = $this->prepareText($match); + } + return str_replace(";", "",$matches[1]); + } +} \ No newline at end of file diff --git a/src/TXTRecords/STSV1.php b/src/TXTRecords/STSV1.php new file mode 100644 index 0000000..c06b77c --- /dev/null +++ b/src/TXTRecords/STSV1.php @@ -0,0 +1,21 @@ +type = 'STS'; + $this->version = 1; + $this->id = $this->cast('id',$value); + } + + function castId(string $value): int + { + preg_match('/id=([0-9]+)/', $value, $matches); + return $this->prepareInt($matches[1]); + } +} \ No newline at end of file diff --git a/src/TXTRecords/TLSRPTV1.php b/src/TXTRecords/TLSRPTV1.php new file mode 100644 index 0000000..4ef6d05 --- /dev/null +++ b/src/TXTRecords/TLSRPTV1.php @@ -0,0 +1,30 @@ +type = 'TLSRPT'; + $this->version = 1; + $this->rua = $this->cast('rua',$value); + } + + function castRua(string $value): array + { + preg_match("/rua=([^;]*)(?:;|$)/i", $value, $matches); + if (isset($matches[1])) { + $emails = preg_split("/\s*,/", $matches[1]); + foreach ($emails as $key => $email) { + $emails[$key] = $this->prepareText($email); + } + } + else { + return array(); + } + return $emails; + } +} \ No newline at end of file diff --git a/src/TXTRecords/V.php b/src/TXTRecords/V.php new file mode 100644 index 0000000..21ec8d4 --- /dev/null +++ b/src/TXTRecords/V.php @@ -0,0 +1,76 @@ +getShortName(); + + if ($type !== $expectedType) { + throw InvalidArgument::wrongRecordType($type, $expectedType); + } + + foreach ($attributes as $key => $value) { + $key = str_replace('-', '_', $key); + + if (property_exists($this, $key)) { + $return = $this->cast($key, $value); + if(is_array($return)){ + foreach($return as $key => $subvalue){ + $this->$key = $subvalue; + } + } else { + $this->$key = $return; + } + } + } + } + + public function __call(string $name, array $arguments) + { + if (property_exists($this, $name)) { + return $this->$name; + } + + return $this->macroCall($name, $arguments); + } + + protected function prepareInt($value): int + { + return intval($value); + } + + protected function prepareText(string $value): string + { + if (str_starts_with($value, '"') && str_ends_with($value, '"')) { + $value = substr($value, 1, -1); + } + + return str_replace('" "', '', $value); + } + + protected function cast(string $attribute, $value) + { + $method = sprintf('cast%s', str_replace(' ', '', ucwords(str_replace('_', ' ', $attribute)))); + + if (method_exists($this, $method)) { + return $this->$method($value); + } else { + return $value; + } + + return $value; + } +} \ No newline at end of file