| @@ -286,8 +286,105 @@ | ||
| 286 | 286 | update_option( 'dfrapi_transient_whitelist', array_unique( $whitelist ) ); |
| 287 | 287 | } |
| 288 | 288 | |
| 289 | 289 | /** |
| 290 | + * Sanitizes a single-line setting value such as an API key, affiliate ID or tracking ID. | |
| 291 | + * | |
| 292 | + * Unlike sanitize_text_field(), this does not remove percent-encoded octets (ie. "%2F"), | |
| 293 | + * which can legitimately appear in keys and tracking IDs. | |
| 294 | + * | |
| 295 | + * @since 1.4.3 | |
| 296 | + * | |
| 297 | + * @param mixed $value | |
| 298 | + * | |
| 299 | + * @return string | |
| 300 | + */ | |
| 301 | +function dfrapi_sanitize_setting_text( $value ): string { | |
| 302 | + if ( ! is_scalar( $value ) ) { | |
| 303 | + return ''; | |
| 304 | + } | |
| 305 | + | |
| 306 | + $value = wp_strip_all_tags( (string) $value ); | |
| 307 | + $value = preg_replace( '/[\x00-\x1F\x7F]/', '', $value ); | |
| 308 | + | |
| 309 | + return trim( $value ); | |
| 310 | +} | |
| 311 | + | |
| 312 | +/** | |
| 313 | + * Sanitizes the "dfrapi_networks" option. Only the expected structure is kept: | |
| 314 | + * | |
| 315 | + * [ 'ids' => [ (int) network_id => [ 'nid' => '123', 'aid' => '...', 'tid' => '...' ] ] ] | |
| 316 | + * | |
| 317 | + * Networks without a "nid" (ie. unchecked networks) are removed. | |
| 318 | + * | |
| 319 | + * @since 1.4.3 | |
| 320 | + * | |
| 321 | + * @param mixed $input | |
| 322 | + * | |
| 323 | + * @return array | |
| 324 | + */ | |
| 325 | +function dfrapi_sanitize_networks_option( $input ): array { | |
| 326 | + | |
| 327 | + $clean = [ 'ids' => [] ]; | |
| 328 | + | |
| 329 | + if ( ! is_array( $input ) || empty( $input['ids'] ) || ! is_array( $input['ids'] ) ) { | |
| 330 | + return $clean; | |
| 331 | + } | |
| 332 | + | |
| 333 | + foreach ( $input['ids'] as $network_id => $network ) { | |
| 334 | + | |
| 335 | + $network_id = absint( $network_id ); | |
| 336 | + | |
| 337 | + if ( $network_id === 0 || ! is_array( $network ) || empty( $network['nid'] ) || ! is_scalar( $network['nid'] ) ) { | |
| 338 | + continue; | |
| 339 | + } | |
| 340 | + | |
| 341 | + $entry = [ 'nid' => (string) absint( $network['nid'] ) ]; | |
| 342 | + | |
| 343 | + foreach ( [ 'aid', 'tid' ] as $field ) { | |
| 344 | + if ( isset( $network[ $field ] ) ) { | |
| 345 | + $entry[ $field ] = dfrapi_sanitize_setting_text( $network[ $field ] ); | |
| 346 | + } | |
| 347 | + } | |
| 348 | + | |
| 349 | + $clean['ids'][ $network_id ] = $entry; | |
| 350 | + } | |
| 351 | + | |
| 352 | + return $clean; | |
| 353 | +} | |
| 354 | + | |
| 355 | +/** | |
| 356 | + * Sanitizes the "dfrapi_merchants" option. Accepts an array of IDs or a comma-separated | |
| 357 | + * string of IDs. IDs are stored as numeric strings to match the existing stored format. | |
| 358 | + * | |
| 359 | + * @since 1.4.3 | |
| 360 | + * | |
| 361 | + * @param mixed $input | |
| 362 | + * | |
| 363 | + * @return array | |
| 364 | + */ | |
| 365 | +function dfrapi_sanitize_merchants_option( $input ): array { | |
| 366 | + | |
| 367 | + $ids = $input['ids'] ?? []; | |
| 368 | + | |
| 369 | + if ( is_string( $ids ) ) { | |
| 370 | + $ids = explode( ',', $ids ); | |
| 371 | + } | |
| 372 | + | |
| 373 | + if ( ! is_array( $ids ) ) { | |
| 374 | + return [ 'ids' => [] ]; | |
| 375 | + } | |
| 376 | + | |
| 377 | + $ids = array_filter( array_map( static function ( $id ) { | |
| 378 | + $id = is_scalar( $id ) ? trim( (string) $id ) : ''; | |
| 379 | + | |
| 380 | + return ctype_digit( $id ) ? absint( $id ) : 0; | |
| 381 | + }, $ids ) ); | |
| 382 | + | |
| 383 | + return [ 'ids' => array_values( array_map( 'strval', array_unique( $ids ) ) ) ]; | |
| 384 | +} | |
| 385 | + | |
| 386 | +/** | |
| 290 | 387 | * Add affiliate ID and tracking ID to an affiliate link. |
| 291 | 388 | * |
| 292 | 389 | * @param array $product An array of a single Datafeedr $product. |
| 293 | 390 | * |
| @@ -409,14 +506,14 @@ | ||
| 409 | 506 | ?> |
| 410 | 507 | <div class="dfrapi_api_error"> |
| 411 | 508 | <div class="dfrapi_head"><?php _e( 'Datafeedr API Error', 'datafeedr-api' ); ?></div> |
| 412 | 509 | <div class="dfrapi_msg"> |
| 413 | - <strong><?php _e( 'Message:', 'datafeedr-api' ); ?></strong> <?php echo $error['msg']; ?> | |
| 510 | + <strong><?php _e( 'Message:', 'datafeedr-api' ); ?></strong> <?php echo esc_html( $error['msg'] ); ?> | |
| 414 | 511 | </div> |
| 415 | - <div class="dfrapi_code"><strong><?php _e( 'Code:', 'datafeedr-api' ); ?></strong> <?php echo $error['code']; ?> | |
| 512 | + <div class="dfrapi_code"><strong><?php _e( 'Code:', 'datafeedr-api' ); ?></strong> <?php echo esc_html( $error['code'] ); ?> | |
| 416 | 513 | </div> |
| 417 | 514 | <div class="dfrapi_class"> |
| 418 | - <strong><?php _e( 'Class:', 'datafeedr-api' ); ?></strong> <?php echo $error['class']; ?></div> | |
| 515 | + <strong><?php _e( 'Class:', 'datafeedr-api' ); ?></strong> <?php echo esc_html( $error['class'] ); ?></div> | |
| 419 | 516 | <?php if ( is_array( $params ) ) : ?> |
| 420 | 517 | <div class="dfrps_query"><strong><?php _e( 'Query:', 'datafeedr-api' ); ?></strong> |
| 421 | 518 | <span><?php echo dfrapi_display_api_request( $params ); ?></span></div> |
| 422 | 519 | <?php endif; ?> |
| @@ -485,9 +582,9 @@ | ||
| 485 | 582 | foreach ( $v as $query ) { |
| 486 | 583 | if ( substr( $query, 0, 9 ) !== 'source_id' || substr( $query, 0, 11 ) !== 'merchant_id' ) { |
| 487 | 584 | $query = str_replace( ",", ", ", $query ); |
| 488 | 585 | } |
| 489 | - $html .= '$search->addFilter( \'' . ( $query ) . '\' );<br />'; | |
| 586 | + $html .= '$search->addFilter( \'' . esc_html( $query ) . '\' );<br />'; | |
| 490 | 587 | } |
| 491 | 588 | } |
| 492 | 589 | |
| 493 | 590 | // Handle sort. |
| @@ -492,15 +589,15 @@ | ||
| 492 | 589 | |
| 493 | 590 | // Handle sort. |
| 494 | 591 | if ( $k === 'sort' ) { |
| 495 | 592 | foreach ( $v as $sort ) { |
| 496 | - $html .= '$search->addSort( \'' . stripslashes( $sort ) . '\' );<br />'; | |
| 593 | + $html .= '$search->addSort( \'' . esc_html( stripslashes( $sort ) ) . '\' );<br />'; | |
| 497 | 594 | } |
| 498 | 595 | } |
| 499 | 596 | |
| 500 | 597 | // Handle limit. |
| 501 | 598 | if ( $k === 'limit' ) { |
| 502 | - $html .= '$search->setLimit( \'' . stripslashes( $v ) . '\' );<br />'; | |
| 599 | + $html .= '$search->setLimit( \'' . esc_html( stripslashes( $v ) ) . '\' );<br />'; | |
| 503 | 600 | } |
| 504 | 601 | |
| 505 | 602 | // Handle merchant_limit. |
| 506 | 603 | if ( $k === 'merchant_limit' ) { |
| @@ -508,14 +605,14 @@ | ||
| 508 | 605 | } |
| 509 | 606 | |
| 510 | 607 | // Handle Offset. |
| 511 | 608 | if ( $k === 'offset' ) { |
| 512 | - $html .= '$search->setOffset( \'' . stripslashes( $v ) . '\' );<br />'; | |
| 609 | + $html .= '$search->setOffset( \'' . esc_html( stripslashes( $v ) ) . '\' );<br />'; | |
| 513 | 610 | } |
| 514 | 611 | |
| 515 | 612 | // Handle Exclude duplicates. |
| 516 | 613 | if ( $k === 'exclude_duplicates' ) { |
| 517 | - $html .= '$search->excludeDuplicates( \'' . $v . '\' );<br />'; | |
| 614 | + $html .= '$search->excludeDuplicates( \'' . esc_html( $v ) . '\' );<br />'; | |
| 518 | 615 | } |
| 519 | 616 | } |
| 520 | 617 | |
| 521 | 618 | $html .= '$products = $search->execute();'; |
| @@ -604,17 +701,17 @@ | ||
| 604 | 701 | ?> |
| 605 | 702 | <div class="dfrapi_api_error"> |
| 606 | 703 | <div class="dfrapi_head"><?php _e( 'Datafeedr API Error', 'datafeedr-api' ); ?></div> |
| 607 | 704 | <div class="dfrapi_msg"> |
| 608 | - <strong><?php _e( 'Message:', 'datafeedr-api' ); ?></strong> <?php echo $error['msg']; ?> | |
| 705 | + <strong><?php _e( 'Message:', 'datafeedr-api' ); ?></strong> <?php echo esc_html( $error['msg'] ); ?> | |
| 609 | 706 | </div> |
| 610 | - <div class="dfrapi_code"><strong><?php _e( 'Code:', 'datafeedr-api' ); ?></strong> <?php echo $error['code']; ?> | |
| 707 | + <div class="dfrapi_code"><strong><?php _e( 'Code:', 'datafeedr-api' ); ?></strong> <?php echo esc_html( $error['code'] ); ?> | |
| 611 | 708 | </div> |
| 612 | 709 | <div class="dfrapi_class"> |
| 613 | - <strong><?php _e( 'Class:', 'datafeedr-api' ); ?></strong> <?php echo $error['class']; ?></div> | |
| 710 | + <strong><?php _e( 'Class:', 'datafeedr-api' ); ?></strong> <?php echo esc_html( $error['class'] ); ?></div> | |
| 614 | 711 | <?php if ( is_array( $params ) ) : ?> |
| 615 | 712 | <div class="dfrapi_query"><strong><?php _e( 'Query:', 'datafeedr-api' ); ?></strong> |
| 616 | - <span><?php echo dfrapi_helper_display_api_request( $params ); ?></span></div> | |
| 713 | + <span><?php echo dfrapi_display_api_request( $params ); ?></span></div> | |
| 617 | 714 | <?php endif; ?> |
| 618 | 715 | </div> |
| 619 | 716 | <?php |
| 620 | 717 | } |
| @@ -958,8 +1055,12 @@ | ||
| 958 | 1055 | } |
| 959 | 1056 | |
| 960 | 1057 | $xml = simplexml_load_string( $body, null, LIBXML_NOCDATA ); |
| 961 | 1058 | |
| 1059 | + if ( $xml === false ) { | |
| 1060 | + return new WP_Error( 'invalid_xml', esc_html__( 'Invalid XML response', 'datafeedr-api' ) ); | |
| 1061 | + } | |
| 1062 | + | |
| 962 | 1063 | if ( $xml->getName() === 'error' ) { |
| 963 | 1064 | return new WP_Error( $code, esc_html( strval( $xml->message ) ) ); |
| 964 | 1065 | } |
| 965 | 1066 | |
| @@ -1799,8 +1900,11 @@ | ||
| 1799 | 1900 | ]; |
| 1800 | 1901 | |
| 1801 | 1902 | $options = apply_filters( 'dfrapi_api_options', $options ); |
| 1802 | 1903 | |
| 1904 | + // Always connect over HTTPS. Set after the filter so it can't be downgraded to HTTP. | |
| 1905 | + $options['https'] = true; | |
| 1906 | + | |
| 1803 | 1907 | $options['domain'] = parse_url( get_site_url(), PHP_URL_HOST ); |
| 1804 | 1908 | |
| 1805 | 1909 | return new DatafeedrApi( $access_id, $secret_key, $options ); |
| 1806 | 1910 | |
| @@ -2449,9 +2553,9 @@ | ||
| 2449 | 2553 | * |
| 2450 | 2554 | * @return string |
| 2451 | 2555 | */ |
| 2452 | 2556 | function dfrapi_get_effiliation_product_feeds_url( string $api_key ): string { |
| 2453 | - return sprintf( 'http://apiv2.effiliation.com/apiv2/productfeeds.xml?key=%s&filter=mines&type=33&fields=0001010000110001', $api_key ); | |
| 2557 | + return sprintf( 'https://apiv2.effiliation.com/apiv2/productfeeds.xml?key=%s&filter=mines&type=33&fields=0001010000110001', $api_key ); | |
| 2454 | 2558 | } |
| 2455 | 2559 | |
| 2456 | 2560 | /** |
| 2457 | 2561 | * Get affiliate IDs from Effiliation. |