transport = $transport; } /** * @return array{request_id:string,deletion_url:string,retention_until:string} */ public function submit( string $json ): array { $response = $this->transport->post( WordPressReviewTransport::ENDPOINT, $json, 16384, 15 ); if ( ! in_array( $response['status'], array( 200, 201 ), true ) ) { throw new ExternalRequestException( 'review_endpoint_unavailable' ); } try { $value = json_decode( $response['body'], true, 16, JSON_THROW_ON_ERROR ); } catch ( JsonException $exception ) { throw new ExternalRequestException( 'review_response_invalid' ); } if ( ! is_array( $value ) || array( 'deletion_url', 'request_id', 'retention_until' ) !== $this->sorted_keys( $value ) || ! is_string( $value['request_id'] ) || 1 !== preg_match( '/^SA-[0-9]{8}-[A-F0-9]{10}$/D', $value['request_id'] ) || ! is_string( $value['retention_until'] ) || ! $this->valid_retention_date( $value['retention_until'] ) || ! is_string( $value['deletion_url'] ) || ! $this->valid_deletion_url( $value['deletion_url'], $value['request_id'] ) ) { throw new ExternalRequestException( 'review_response_invalid' ); } return array( 'request_id' => $value['request_id'], 'deletion_url' => $value['deletion_url'], 'retention_until' => $value['retention_until'], ); } private function valid_deletion_url( string $url, string $request_id ): bool { $parts = wp_parse_url( $url ); if ( ! is_array( $parts ) || 'https' !== ( $parts['scheme'] ?? null ) || 'wp-content.ru' !== ( $parts['host'] ?? null ) || '/review-request/delete/' !== ( $parts['path'] ?? null ) || isset( $parts['user'] ) || isset( $parts['pass'] ) || isset( $parts['fragment'] ) || ! isset( $parts['query'] ) || ! is_string( $parts['query'] ) ) { return false; } return 1 === preg_match( '/^request_id=' . preg_quote( $request_id, '/' ) . '&token=[a-f0-9]{64}$/D', $parts['query'] ); } private function valid_retention_date( string $value ): bool { if ( 1 !== preg_match( '/^([0-9]{4})-([0-9]{2})-([0-9]{2})$/D', $value, $matches ) || ! checkdate( (int) $matches[2], (int) $matches[3], (int) $matches[1] ) ) { return false; } $today = gmmktime( 0, 0, 0, (int) gmdate( 'n' ), (int) gmdate( 'j' ), (int) gmdate( 'Y' ) ); $retention = gmmktime( 0, 0, 0, (int) $matches[2], (int) $matches[3], (int) $matches[1] ); return $retention >= $today + ( 89 * self::DAY_SECONDS ) && $retention <= $today + ( 91 * self::DAY_SECONDS ); } /** * @param array $value Value. * @return list */ private function sorted_keys( array $value ): array { $keys = array_keys( $value ); sort( $keys ); return $keys; } }