v1.5.0
This commit is contained in:
parent
672d0f295f
commit
83d629568a
20 changed files with 1321 additions and 15 deletions
156
includes/External/PicDefenseProvider.php
vendored
Normal file
156
includes/External/PicDefenseProvider.php
vendored
Normal file
|
|
@ -0,0 +1,156 @@
|
|||
<?php
|
||||
/**
|
||||
* PicDefense copyright risk analysis provider.
|
||||
*
|
||||
* @package MediaRightsAudit\External
|
||||
*/
|
||||
|
||||
namespace MediaRightsAudit\External;
|
||||
|
||||
use MediaRightsAudit\Admin\Settings;
|
||||
|
||||
/**
|
||||
* Submits images to the PicDefense API and normalises the response
|
||||
* into a ScanResult.
|
||||
*
|
||||
* Uses POST-based image URL submission with X-API-TOKEN header authentication.
|
||||
* Reads credentials (picdefense_user_id and picdefense_api_key) from plugin settings.
|
||||
* Match count reflects backlink_count from the API response; top domains are
|
||||
* extracted from the found_at array.
|
||||
*/
|
||||
class PicDefenseProvider extends AbstractProvider {
|
||||
|
||||
/**
|
||||
* PicDefense API endpoint.
|
||||
*/
|
||||
const ENDPOINT = 'https://app.picdefense.io/apiRouterv2/checkImageRisk';
|
||||
|
||||
/**
|
||||
* Returns the machine-readable provider identifier.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function provider_slug(): string {
|
||||
return 'picdefense';
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the human-readable provider display name.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function provider_name(): string {
|
||||
return 'PicDefense';
|
||||
}
|
||||
|
||||
/**
|
||||
* Submits the image URL to PicDefense and returns a ScanResult.
|
||||
*
|
||||
* @param int $attachment_id WordPress attachment ID.
|
||||
* @param string $file_url Public URL of the image.
|
||||
*
|
||||
* @return ScanResult
|
||||
*
|
||||
* @throws \RuntimeException On configuration, HTTP, or parse errors.
|
||||
*/
|
||||
protected function do_scan( int $attachment_id, string $file_url ): ScanResult {
|
||||
list( $user_id, $api_key ) = $this->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<mixed, mixed> $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 );
|
||||
}
|
||||
}
|
||||
Loading…
Reference in a new issue