path relative to the plugin * folder => accepted sums. The API gives a string OR a list; both become lists here. * A file conforms when its sum is one of the values; sha256 is compared when the * entry has one and the FileEntry carries one, md5 otherwise (WP-CLI behaviour). * * @package Timaub\AfterHackChecklist */ namespace Timaub\AfterHackChecklist\Domain; final class PluginChecksums { /** @var string */ public $slug = ''; /** @var string */ public $version = ''; /** @var array */ public $files = array(); /** * @param mixed $decoded json_decode( $body, true ) of a 200 answer. * @return self|null null when the shape is not the documented one. */ public static function fromApiResponse( $decoded, string $slug, string $version ) { if ( ! is_array( $decoded ) || ! isset( $decoded['files'] ) || ! is_array( $decoded['files'] ) ) { return null; } $p = new self(); $p->slug = $slug; $p->version = $version; foreach ( $decoded['files'] as $path => $sums ) { if ( ! is_array( $sums ) ) { return null; } $p->files[ (string) $path ] = array( 'md5' => self::toList( isset( $sums['md5'] ) ? $sums['md5'] : array() ), 'sha256' => self::toList( isset( $sums['sha256'] ) ? $sums['sha256'] : array() ), ); } return $p; } /** @param mixed $v String or list. */ private static function toList( $v ): array { $out = array(); foreach ( (array) $v as $s ) { if ( is_string( $s ) && '' !== $s ) { $out[] = strtolower( $s ); } } return $out; } public function has( string $relPath ): bool { return isset( $this->files[ $relPath ] ); } /** * @param string $relPath Path relative to the plugin folder, present in files. * @param string|null $md5 File md5. * @param string|null $sha256 File sha256. * @return array{0:bool|null,1:string} conforms (null = nothing comparable on one side), algorithm used. */ public function compare( string $relPath, $md5, $sha256 ): array { $entry = $this->files[ $relPath ]; if ( $entry['sha256'] && null !== $sha256 ) { return array( in_array( strtolower( $sha256 ), $entry['sha256'], true ), 'sha256' ); } if ( ! $entry['md5'] || null === $md5 ) { return array( null, 'md5' ); } return array( in_array( strtolower( $md5 ), $entry['md5'], true ), 'md5' ); } public function toArray(): array { return array( 'slug' => $this->slug, 'version' => $this->version, 'files' => $this->files, ); } public static function fromArray( array $a ): self { $p = new self(); $p->slug = (string) $a['slug']; $p->version = (string) $a['version']; $p->files = (array) $a['files']; return $p; } }