get_credentials(); if ( '' === $user_id || '' === $api_key ) { throw new \RuntimeException( 'PicDefense credentials are not configured.' ); } $body = wp_json_encode( array( 'url' => $file_url ) ); if ( false === $body ) { throw new \RuntimeException( 'Failed to encode PicDefense request body.' ); } $response = wp_remote_post( self::ENDPOINT, array( 'headers' => array( 'Content-Type' => 'application/json; charset=utf-8', 'X-API-TOKEN' => $user_id . ':' . $api_key, ), 'body' => $body, 'timeout' => 60, ) ); if ( is_wp_error( $response ) ) { throw new \RuntimeException( $response->get_error_message() ); // phpcs:ignore WordPress.Security.EscapeOutput.ExceptionNotEscaped } $http_code = (int) wp_remote_retrieve_response_code( $response ); if ( 200 !== $http_code ) { throw new \RuntimeException( sprintf( 'PicDefense API returned HTTP %d.', $http_code ) // phpcs:ignore WordPress.Security.EscapeOutput.ExceptionNotEscaped ); } $raw_body = wp_remote_retrieve_body( $response ); $decoded = json_decode( $raw_body, true ); if ( ! is_array( $decoded ) ) { throw new \RuntimeException( 'Failed to parse PicDefense API response.' ); } return $this->parse_response( $decoded ); } // ------------------------------------------------------------------------- // Private helpers // ------------------------------------------------------------------------- /** * Reads PicDefense credentials from plugin settings. * * @return array{string, string} [user_id, api_key] — empty strings if not configured. */ private function get_credentials(): array { $raw = get_option( Settings::OPTION_NAME, array() ); $opts = is_array( $raw ) ? $raw : array(); $uid_val = $opts['picdefense_user_id'] ?? null; $key_val = $opts['picdefense_api_key'] ?? null; $user_id = is_string( $uid_val ) ? trim( $uid_val ) : ''; $api_key = is_string( $key_val ) ? trim( $key_val ) : ''; return array( $user_id, $api_key ); } /** * Parses a decoded PicDefense API response into a ScanResult. * * @param array $decoded json_decode()'d API response. * * @return ScanResult * * @throws \RuntimeException When the API response indicates failure. */ private function parse_response( array $decoded ): ScanResult { $status_val = $decoded['status'] ?? null; $status = is_numeric( $status_val ) ? (int) $status_val : 0; if ( 1 !== $status ) { throw new \RuntimeException( 'PicDefense API returned non-success status.' ); } $data_raw = $decoded['data'] ?? null; $data_arr = is_array( $data_raw ) ? $data_raw : array(); $data = isset( $data_arr[0] ) && is_array( $data_arr[0] ) ? $data_arr[0] : array(); $bc_val = $data['backlink_count'] ?? null; $match_count = is_numeric( $bc_val ) ? (int) $bc_val : 0; $found_at_raw = $data['found_at'] ?? null; $found_at = is_array( $found_at_raw ) ? $found_at_raw : array(); $found_at = array_slice( $found_at, 0, 10 ); $top_domains = array(); foreach ( $found_at as $domain ) { if ( is_string( $domain ) && '' !== $domain ) { $top_domains[ $domain ] = 1; } } return new ScanResult( $match_count, $top_domains, $decoded ); } }