$sql; } $results = $this->wpdb->get_results( $prepared, ARRAY_A ); if ( $this->wpdb->last_error ) { return Result::error( new \WP_Error( 'itsec.site-scanner.vulnerabilities.db-error', __( 'Could not fetch vulnerabilities.', 'it-l10n-ithemes-security-pro' ), [ 'error' => $this->wpdb->last_error, ] ) ); } return Result::success( array_filter( array_map( [ $this, 'try_hydrate' ], $results ) ) ); } /** * Count vulnerabilities from the DB. * * @param Vulnerabilities_Options $options * * @return Result */ public function count_vulnerabilities( Vulnerabilities_Options $options ): Result { $sql = "SELECT count(*) as c FROM {$this->wpdb->base_prefix}itsec_vulnerabilities"; [ $where, $prepare ] = $this->build_where_clause( $options ); $sql .= $where; if ( $prepare ) { $prepared = $this->wpdb->prepare( $sql, $prepare ); } else { $prepared = $sql; } $count = $this->wpdb->get_var( $prepared ); if ( $this->wpdb->last_error ) { return Result::error( new \WP_Error( 'itsec.site-scanner.vulnerabilities.db-error', __( 'Could not fetch vulnerabilities.', 'it-l10n-ithemes-security-pro' ), [ 'error' => $this->wpdb->last_error, ] ) ); } return Result::success( $count ); } private function build_where_clause( Vulnerabilities_Options $options ): array { $wheres = []; $prepare = []; if ( $types = $options->get_types() ) { $wheres[] = sprintf( '`software_type` IN (%s)', implode( ', ', array_fill( 0, count( $types ), '%s' ) ) ); $prepare = array_merge( $prepare, $types ); } if ( $resolutions = $options->get_resolutions() ) { $wheres[] = sprintf( '`resolution` IN (%s)', implode( ', ', array_fill( 0, count( $resolutions ), '%s' ) ) ); $prepare = array_merge( $prepare, $resolutions ); } if ( $software = $options->get_software() ) { $wheres[] = sprintf( '(%s)', implode( ' OR ', array_map( function ( array $software ) use ( &$prepare ) { $prepare[] = $software['type']; if ( $software['slug'] ) { $prepare[] = $software['slug']; return '(`software_type` = %s AND `software_slug` = %s)'; } return '(`software_type` = %s)'; }, $software ) ) ); } if ( $first_seen_after = $options->get_first_seen_after() ) { $wheres[] = '`first_seen` > %s'; $prepare[] = $first_seen_after->format( 'Y-m-d H:i:s' ); } if ( $first_seen_before = $options->get_first_seen_before() ) { $wheres[] = '`first_seen` < %s'; $prepare[] = $first_seen_before->format( 'Y-m-d H:i:s' ); } if ( $last_seen_after = $options->get_last_seen_after() ) { $wheres[] = '`last_seen` > %s'; $prepare[] = $last_seen_after->format( 'Y-m-d H:i:s' ); } if ( $last_seen_before = $options->get_last_seen_before() ) { $wheres[] = '`last_seen` < %s'; $prepare[] = $last_seen_before->format( 'Y-m-d H:i:s' ); } if ( ! $wheres ) { return [ '', [] ]; } return [ ' WHERE ' . implode( ' AND ', $wheres ), $prepare ]; } private function try_hydrate( array $data ): ?Vulnerability { try { return $this->hydrate( $data ); } catch ( \Exception $e ) { return null; } } private function hydrate( array $data ): Vulnerability { return new Vulnerability( $data['id'], $data['software_type'], $data['software_slug'], json_decode( $data['details'], true ), new \DateTimeImmutable( $data['first_seen'], new \DateTimeZone( 'UTC' ) ), new \DateTimeImmutable( $data['last_seen'], new \DateTimeZone( 'UTC' ) ), $data['resolved_at'] ? new \DateTimeImmutable( $data['resolved_at'], new \DateTimeZone( 'UTC' ) ) : null, $data['resolved_by'] ? ( get_userdata( $data['resolved_by'] ) ?: null ) : null, $data['resolution'] ); } }