$code, 'resetAt' => sanitize_text_field( (string) ( $data['resetAt'] ?? '' ) ), 'retryAfter' => absint( $data['retryAfter'] ?? 0 ), ) ); } return new WP_Error( 'engine_error', $fallback_message, array( 'http_status' => $code ) ); } /** * Start a new scan. El nivel free/Pro lo decide el motor a partir de la licencia. * * @param string $url URL to scan. * @param string $mode "single", "sitemap" or "crawl". * @param string $license_key Clave de licencia Freemius (o '' si free). * @return array{jobId:string,status:string,pageLimit:int}|WP_Error */ public function start_scan( string $url, string $mode, string $license_key = '' ): array|WP_Error { $endpoint = $this->base_url() . '/scan'; $body = wp_json_encode( array( 'url' => $url, 'siteUrl' => home_url( '/' ), 'mode' => $mode, 'licenseKey' => $license_key, ) ); if ( false === $body ) { return new WP_Error( 'json_encode', __( 'Error encoding the JSON request.', 'accesslens' ) ); } $response = wp_remote_post( $endpoint, array( 'timeout' => self::TIMEOUT_START, 'headers' => array( 'Content-Type' => 'application/json' ), 'body' => $body, 'data_format' => 'body', ) ); if ( is_wp_error( $response ) ) { return $response; } $code = wp_remote_retrieve_response_code( $response ); if ( 202 !== (int) $code ) { return $this->build_error_from_response( $response, sprintf( /* translators: %d: HTTP status code */ __( 'The engine returned HTTP %d when starting the scan.', 'accesslens' ), $code ) ); } $data = json_decode( wp_remote_retrieve_body( $response ), true ); if ( ! is_array( $data ) || empty( $data['jobId'] ) ) { return new WP_Error( 'invalid_response', __( 'Invalid response from the engine (start).', 'accesslens' ) ); } return $data; } /** * Poll the status of an existing scan job. * * @param string $job_id Job identifier. * @return array|WP_Error Decoded JSON body or WP_Error. */ public function get_status( string $job_id ): array|WP_Error { $endpoint = $this->base_url() . '/scan/' . rawurlencode( $job_id ); $response = wp_remote_get( $endpoint, array( 'timeout' => self::TIMEOUT_POLL ) ); if ( is_wp_error( $response ) ) { return $response; } $code = wp_remote_retrieve_response_code( $response ); if ( 200 !== (int) $code ) { return $this->build_error_from_response( $response, sprintf( /* translators: %d: HTTP status code */ __( 'The engine returned HTTP %d when checking status.', 'accesslens' ), $code ) ); } $data = json_decode( wp_remote_retrieve_body( $response ), true ); if ( ! is_array( $data ) ) { return new WP_Error( 'invalid_response', __( 'Invalid response from the engine (poll).', 'accesslens' ) ); } return $data; } /** * Request the compliance report and return raw binary body + content-type. * * @param string $job_id Job identifier. * @param array $report_meta Report metadata (siteName, siteUrl, entityType, etc.). * @param string $format "pdf" or "html". * @param string $license_key Clave de licencia Freemius (o '' si free). * @return array{body:string,content_type:string}|WP_Error */ public function get_report( string $job_id, array $report_meta, string $format = 'pdf', string $license_key = '' ): array|WP_Error { $endpoint = $this->base_url() . '/scan/' . rawurlencode( $job_id ) . '/report'; // siteUrl siempre es home_url('/'): el motor lo usa para restringir el target al // propio dominio del sitio, no es un campo editable por el usuario. $payload = array_merge( $report_meta, array( 'siteUrl' => home_url( '/' ), 'format' => in_array( $format, array( 'pdf', 'html' ), true ) ? $format : 'pdf', 'licenseKey' => $license_key, ) ); $body = wp_json_encode( $payload ); if ( false === $body ) { return new WP_Error( 'json_encode', __( 'Error encoding the report metadata.', 'accesslens' ) ); } $response = wp_remote_post( $endpoint, array( 'timeout' => self::TIMEOUT_REPORT, 'headers' => array( 'Content-Type' => 'application/json' ), 'body' => $body, 'data_format' => 'body', ) ); if ( is_wp_error( $response ) ) { return $response; } $code = wp_remote_retrieve_response_code( $response ); if ( 200 !== (int) $code ) { return $this->build_error_from_response( $response, sprintf( /* translators: %d: HTTP status code */ __( 'The engine returned HTTP %d when generating the report.', 'accesslens' ), $code ) ); } return array( 'body' => wp_remote_retrieve_body( $response ), 'content_type' => wp_remote_retrieve_header( $response, 'content-type' ), ); } }