initial
This commit is contained in:
@@ -0,0 +1,26 @@
|
||||
<?php
|
||||
|
||||
require_once __DIR__ . '/http-header.php';
|
||||
|
||||
/**
|
||||
* Check that a cookie value exists
|
||||
*/
|
||||
class Cookie_Match extends Header_Match {
|
||||
public function name() {
|
||||
return __( 'URL and cookie', 'redirection' );
|
||||
}
|
||||
|
||||
public function is_match( $url ) {
|
||||
if ( $this->regex ) {
|
||||
$regex = new Red_Regex( $this->value, true );
|
||||
$cookie = Redirection_Request::get_cookie( $this->name );
|
||||
if ( $cookie === false ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return $regex->is_match( $cookie );
|
||||
}
|
||||
|
||||
return Redirection_Request::get_cookie( $this->name ) === $this->value;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,111 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* @phpstan-type CustomFilterMap array{
|
||||
* filter?: string,
|
||||
* url_from?: string,
|
||||
* url_notfrom?: string
|
||||
* }
|
||||
* @phpstan-type CustomFilterResult array{
|
||||
* filter: string,
|
||||
* url_from?: string,
|
||||
* url_notfrom?: string
|
||||
* }
|
||||
* @phpstan-type CustomFilterData array{
|
||||
* filter: string,
|
||||
* url_from: string,
|
||||
* url_notfrom: string
|
||||
* }
|
||||
* @phpstan-extends Red_Match<CustomFilterMap, CustomFilterResult>
|
||||
*
|
||||
* Perform a check against the results of a custom filter
|
||||
*
|
||||
*/
|
||||
class Custom_Match extends Red_Match {
|
||||
use FromNotFrom_Match;
|
||||
|
||||
/**
|
||||
* Filter name
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
public $filter = '';
|
||||
|
||||
/**
|
||||
* Name of this match used in UI.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function name() {
|
||||
return __( 'URL and custom filter', 'redirection' );
|
||||
}
|
||||
|
||||
/**
|
||||
* Save data to an array, ready for serializing.
|
||||
*
|
||||
* @param CustomFilterMap $details New match data.
|
||||
* @param boolean $no_target_url Does the action have a target URL.
|
||||
* @return CustomFilterResult
|
||||
*/
|
||||
public function save( array $details, $no_target_url = false ) {
|
||||
$data = [
|
||||
'filter' => isset( $details['filter'] ) ? $this->sanitize_filter( $details['filter'] ) : '',
|
||||
];
|
||||
|
||||
/** @var CustomFilterResult $result */
|
||||
$result = $this->save_data( $details, $no_target_url, $data );
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sanitize filter name to allow only alphanumeric, dash and underscore.
|
||||
*
|
||||
* @param string $name Filter name.
|
||||
* @return string
|
||||
*/
|
||||
public function sanitize_filter( $name ) {
|
||||
$name = (string) preg_replace( '/[^A-Za-z0-9\-_]/', '', sanitize_text_field( $name ) );
|
||||
|
||||
return trim( $name );
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine if the current request matches using the custom filter.
|
||||
*
|
||||
* @param string $url Requested URL.
|
||||
* @return boolean
|
||||
*/
|
||||
public function is_match( $url ) {
|
||||
if ( $this->filter === '' ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return apply_filters( $this->filter, false, $url );
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the match data for persistence.
|
||||
*
|
||||
* @return CustomFilterData
|
||||
*/
|
||||
public function get_data() {
|
||||
return array_merge(
|
||||
[
|
||||
'filter' => $this->filter,
|
||||
],
|
||||
$this->get_from_data()
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Load the match data into this instance.
|
||||
*
|
||||
* @param string|CustomFilterMap $values Match values from database (serialized PHP or parsed array).
|
||||
* @return void
|
||||
*/
|
||||
public function load( $values ) {
|
||||
$values = $this->load_data( $values );
|
||||
/** @var CustomFilterMap $values */
|
||||
$this->filter = isset( $values['filter'] ) ? $values['filter'] : '';
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,128 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* @phpstan-type FromNotFromMap (array{
|
||||
* url_from?: string,
|
||||
* url_notfrom?: string
|
||||
* } & array<string, mixed>)
|
||||
* @phpstan-type FromNotFromData array{
|
||||
* url_from: string,
|
||||
* url_notfrom: string
|
||||
* }
|
||||
*
|
||||
* Trait to add redirect matching that adds a matched target
|
||||
*/
|
||||
trait FromNotFrom_Match {
|
||||
/**
|
||||
* Target URL if matched
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
public $url_from = '';
|
||||
|
||||
/**
|
||||
* Target URL if not matched
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
public $url_notfrom = '';
|
||||
|
||||
/**
|
||||
* Save data to an array, ready for serializing.
|
||||
*
|
||||
* @phpstan-template TData of array<string, mixed>
|
||||
* @param FromNotFromMap $details New match data.
|
||||
* @param bool $no_target_url Does the action have a target URL.
|
||||
* @phpstan-param TData $data Existing match data.
|
||||
* @param array<string, mixed> $data Existing match data.
|
||||
* @phpstan-return TData&FromNotFromMap
|
||||
* @return array<string, mixed>
|
||||
*/
|
||||
private function save_data( array $details, $no_target_url, array $data ) {
|
||||
if ( $no_target_url === false ) {
|
||||
return array_merge(
|
||||
array(
|
||||
'url_from' => isset( $details['url_from'] ) ? $this->sanitize_url( $details['url_from'] ) : '',
|
||||
'url_notfrom' => isset( $details['url_notfrom'] ) ? $this->sanitize_url( $details['url_notfrom'] ) : '',
|
||||
),
|
||||
$data
|
||||
);
|
||||
}
|
||||
|
||||
return $data;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get target URL for this match, depending on whether we match or not
|
||||
*
|
||||
* @param string $requested_url Request URL.
|
||||
* @param string $source_url Redirect source URL.
|
||||
* @param Red_Source_Flags $flags Redirect flags.
|
||||
* @param boolean $matched Has the source been matched.
|
||||
* @return string|false
|
||||
*/
|
||||
public function get_target_url( $requested_url, $source_url, Red_Source_Flags $flags, $matched ) {
|
||||
// Action needs a target URL based on whether we matched or not
|
||||
$target = $this->get_matched_target( $matched );
|
||||
|
||||
if ( $flags->is_regex() && $target !== false ) {
|
||||
return $this->get_target_regex_url( $source_url, $target, $requested_url, $flags );
|
||||
}
|
||||
|
||||
return $target;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the matched target if we have matched and one exists, or return the unmatched target if not matched.
|
||||
*
|
||||
* @param boolean $matched Is it matched.
|
||||
* @return false|string
|
||||
*/
|
||||
private function get_matched_target( $matched ) {
|
||||
if ( $this->url_from !== '' && $matched ) {
|
||||
return $this->url_from;
|
||||
}
|
||||
|
||||
if ( $this->url_notfrom !== '' && ! $matched ) {
|
||||
return $this->url_notfrom;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Load the data into the instance.
|
||||
*
|
||||
* @phpstan-template TValues of array<string, mixed>
|
||||
* @param string|TValues $values Serialized PHP data or parsed array.
|
||||
* @phpstan-return TValues&FromNotFromMap
|
||||
* @return array<string, mixed>&FromNotFromMap
|
||||
*/
|
||||
private function load_data( $values ) {
|
||||
if ( is_string( $values ) ) {
|
||||
$values = @unserialize( $values ); // phpcs:ignore
|
||||
}
|
||||
|
||||
if ( isset( $values['url_from'] ) ) {
|
||||
$this->url_from = $values['url_from'];
|
||||
}
|
||||
|
||||
if ( isset( $values['url_notfrom'] ) ) {
|
||||
$this->url_notfrom = $values['url_notfrom'];
|
||||
}
|
||||
|
||||
return is_array( $values ) ? $values : [];
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the match data
|
||||
*
|
||||
* @return FromNotFromData
|
||||
*/
|
||||
private function get_from_data(): array {
|
||||
return [
|
||||
'url_from' => $this->url_from,
|
||||
'url_notfrom' => $this->url_notfrom,
|
||||
];
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,108 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* @phpstan-type FromUrlMap (array{
|
||||
* url?: string
|
||||
* } & array<string, mixed>)
|
||||
* @phpstan-type FromUrlData array{
|
||||
* url: string
|
||||
* }
|
||||
*
|
||||
* Trait to add redirect matching that adds a matched target
|
||||
*/
|
||||
trait FromUrl_Match {
|
||||
/**
|
||||
* URL to match against
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
public $url = '';
|
||||
|
||||
/**
|
||||
* Save data to an array, ready for serializing.
|
||||
*
|
||||
* @phpstan-template TData of array<string, mixed>
|
||||
* @param FromUrlMap $details New match data.
|
||||
* @param bool $no_target_url Does the action have a target URL.
|
||||
* @phpstan-param TData $data Existing match data.
|
||||
* @param array<string, mixed> $data Existing match data.
|
||||
* @phpstan-return TData&FromUrlMap
|
||||
* @return array<string, mixed>
|
||||
*/
|
||||
private function save_data( array $details, $no_target_url, array $data ) {
|
||||
if ( $no_target_url === false ) {
|
||||
return array_merge(
|
||||
[
|
||||
'url' => isset( $details['url'] ) ? $this->sanitize_url( $details['url'] ) : '',
|
||||
],
|
||||
$data
|
||||
);
|
||||
}
|
||||
|
||||
return $data;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get target URL for this match, depending on whether we match or not
|
||||
*
|
||||
* @param string $requested_url Request URL.
|
||||
* @param string $source_url Redirect source URL.
|
||||
* @param Red_Source_Flags $flags Redirect flags.
|
||||
* @param boolean $matched Is the URL matched.
|
||||
* @return string|false
|
||||
*/
|
||||
public function get_target_url( $requested_url, $source_url, Red_Source_Flags $flags, $matched ) {
|
||||
$target = $this->get_matched_target( $matched );
|
||||
|
||||
if ( $flags->is_regex() && $target !== false ) {
|
||||
return $this->get_target_regex_url( $source_url, $target, $requested_url, $flags );
|
||||
}
|
||||
|
||||
return $target;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the matched target, if one exists.
|
||||
*
|
||||
* @param boolean $matched Is it matched.
|
||||
* @return false|string
|
||||
*/
|
||||
private function get_matched_target( $matched ) {
|
||||
if ( $matched ) {
|
||||
return $this->url;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Load the data into the instance.
|
||||
*
|
||||
* @phpstan-template TValues of array<string, mixed>
|
||||
* @param string|TValues $values Serialized PHP or parsed array.
|
||||
* @phpstan-return TValues&FromUrlMap
|
||||
* @return array<string, mixed>&FromUrlMap
|
||||
*/
|
||||
private function load_data( $values ) {
|
||||
if ( is_string( $values ) ) {
|
||||
$values = unserialize( $values ); // phpcs:ignore
|
||||
}
|
||||
|
||||
if ( isset( $values['url'] ) ) {
|
||||
$this->url = $values['url'];
|
||||
}
|
||||
|
||||
return is_array( $values ) ? $values : [];
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the loaded data as an array.
|
||||
*
|
||||
* @return FromUrlData
|
||||
*/
|
||||
private function get_from_data(): array {
|
||||
return [
|
||||
'url' => $this->url,
|
||||
];
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,142 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* @phpstan-type HeaderMap array{
|
||||
* name?: string,
|
||||
* value?: string,
|
||||
* regex?: bool,
|
||||
* url_from?: string,
|
||||
* url_notfrom?: string
|
||||
* }
|
||||
* @phpstan-type HeaderResult array{
|
||||
* name: string,
|
||||
* value: string,
|
||||
* regex: bool,
|
||||
* url_from?: string,
|
||||
* url_notfrom?: string
|
||||
* }
|
||||
* @phpstan-type HeaderData array{
|
||||
* name: string,
|
||||
* value: string,
|
||||
* regex: bool,
|
||||
* url_from: string,
|
||||
* url_notfrom: string
|
||||
* }
|
||||
*
|
||||
* Check a HTTP request header
|
||||
*
|
||||
* @phpstan-extends Red_Match<HeaderMap, HeaderResult>
|
||||
*/
|
||||
class Header_Match extends Red_Match {
|
||||
use FromNotFrom_Match;
|
||||
|
||||
/**
|
||||
* HTTP header name
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
public $name = '';
|
||||
|
||||
/**
|
||||
* HTTP header value
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
public $value = '';
|
||||
|
||||
/**
|
||||
* Is this a regex?
|
||||
*
|
||||
* @var boolean
|
||||
*/
|
||||
public $regex = false;
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function name() {
|
||||
return __( 'URL and HTTP header', 'redirection' );
|
||||
}
|
||||
|
||||
/**
|
||||
* @param HeaderMap $details
|
||||
* @param bool $no_target_url
|
||||
* @return HeaderResult
|
||||
*/
|
||||
public function save( array $details, $no_target_url = false ) {
|
||||
$data = array(
|
||||
'regex' => isset( $details['regex'] ) && $details['regex'] ? true : false,
|
||||
'name' => isset( $details['name'] ) ? $this->sanitize_name( $details['name'] ) : '',
|
||||
'value' => isset( $details['value'] ) ? $this->sanitize_value( $details['value'] ) : '',
|
||||
);
|
||||
|
||||
$result = $this->save_data( $details, $no_target_url, $data );
|
||||
return $result; // @phpstan-ignore-line
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $name
|
||||
* @return string
|
||||
*/
|
||||
public function sanitize_name( $name ) {
|
||||
$name = $this->sanitize_url( sanitize_text_field( $name ) );
|
||||
$name = str_replace( ' ', '', $name );
|
||||
$name = (string) preg_replace( '/[^A-Za-z0-9\-_]/', '', $name );
|
||||
|
||||
return trim( trim( $name, ':' ) );
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $value
|
||||
* @return string
|
||||
*/
|
||||
public function sanitize_value( $value ) {
|
||||
return $this->sanitize_url( sanitize_text_field( $value ) );
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $url
|
||||
* @return boolean
|
||||
*/
|
||||
public function is_match( $url ) {
|
||||
if ( $this->regex ) {
|
||||
$regex = new Red_Regex( $this->value, true );
|
||||
$header = Redirection_Request::get_header( $this->name );
|
||||
|
||||
if ( ! is_string( $header ) ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return $regex->is_match( $header );
|
||||
}
|
||||
|
||||
return Redirection_Request::get_header( $this->name ) === $this->value;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return HeaderData
|
||||
*/
|
||||
public function get_data() {
|
||||
return array_merge(
|
||||
array(
|
||||
'regex' => $this->regex,
|
||||
'name' => $this->name,
|
||||
'value' => $this->value,
|
||||
),
|
||||
$this->get_from_data()
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Load the match data into this instance.
|
||||
*
|
||||
* @param string|array<string, mixed> $values Match values, as read from the database (plain text, serialized PHP, or parsed array).
|
||||
* @return void
|
||||
*/
|
||||
public function load( $values ) {
|
||||
$data = $this->load_data( $values );
|
||||
$this->regex = isset( $data['regex'] ) ? (bool) $data['regex'] : false; // @phpstan-ignore-line
|
||||
$this->name = isset( $data['name'] ) ? (string) $data['name'] : ''; // @phpstan-ignore-line
|
||||
$this->value = isset( $data['value'] ) ? (string) $data['value'] : ''; // @phpstan-ignore-line
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,120 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* @phpstan-type IpMap array{
|
||||
* ip?: string[],
|
||||
* url_from?: string,
|
||||
* url_notfrom?: string
|
||||
* }
|
||||
* @phpstan-type IpResult array{
|
||||
* ip: string[],
|
||||
* url_from?: string,
|
||||
* url_notfrom?: string
|
||||
* }
|
||||
* @phpstan-type IpData array{
|
||||
* ip: string[],
|
||||
* url_from: string,
|
||||
* url_notfrom: string
|
||||
* }
|
||||
*
|
||||
* Check the request IP
|
||||
*
|
||||
* @phpstan-extends Red_Match<IpMap, IpResult>
|
||||
*/
|
||||
class IP_Match extends Red_Match {
|
||||
use FromNotFrom_Match;
|
||||
|
||||
/**
|
||||
* Array of IP addresses
|
||||
*
|
||||
* @var string[]
|
||||
*/
|
||||
public $ip = [];
|
||||
|
||||
public function name() {
|
||||
return __( 'URL and IP', 'redirection' );
|
||||
}
|
||||
|
||||
/**
|
||||
* @param IpMap $details
|
||||
* @return IpResult
|
||||
*/
|
||||
public function save( array $details, $no_target_url = false ) {
|
||||
$data = array( 'ip' => isset( $details['ip'] ) && is_array( $details['ip'] ) ? $this->sanitize_ips( $details['ip'] ) : [] ); // @phpstan-ignore-line
|
||||
|
||||
$result = $this->save_data( $details, $no_target_url, $data );
|
||||
return $result; // @phpstan-ignore-line
|
||||
}
|
||||
|
||||
/**
|
||||
* Sanitize a single IP
|
||||
*
|
||||
* @param string $ip IP.
|
||||
* @return string|false
|
||||
*/
|
||||
private function sanitize_single_ip( $ip ) {
|
||||
$ip = @inet_pton( trim( sanitize_text_field( $ip ) ) );
|
||||
if ( $ip !== false ) {
|
||||
return @inet_ntop( $ip ); // Convert back to string
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sanitize a list of IPs
|
||||
*
|
||||
* @param string[] $ips List of IPs.
|
||||
* @return string[]
|
||||
*/
|
||||
private function sanitize_ips( array $ips ) {
|
||||
$ips = array_map( array( $this, 'sanitize_single_ip' ), $ips );
|
||||
return array_values( array_filter( array_unique( $ips ) ) );
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a list of IPs that match.
|
||||
*
|
||||
* @param string $match_ip IP to match.
|
||||
* @return string[]
|
||||
*/
|
||||
private function get_matching_ips( $match_ip ) {
|
||||
$current_ip = @inet_pton( $match_ip );
|
||||
|
||||
return array_filter(
|
||||
$this->ip,
|
||||
function ( $ip ) use ( $current_ip ) {
|
||||
return @inet_pton( $ip ) === $current_ip;
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
public function is_match( $url ) {
|
||||
$matched = $this->get_matching_ips( Redirection_Request::get_ip() );
|
||||
|
||||
return count( $matched ) > 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return IpData
|
||||
*/
|
||||
public function get_data() {
|
||||
return array_merge(
|
||||
array(
|
||||
'ip' => $this->ip,
|
||||
),
|
||||
$this->get_from_data()
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Load the match data into this instance.
|
||||
*
|
||||
* @param string|IpMap $values Match values, as read from the database (plain text, serialized PHP, or parsed array).
|
||||
* @return void
|
||||
*/
|
||||
public function load( $values ) {
|
||||
$data = $this->load_data( $values );
|
||||
$this->ip = isset( $data['ip'] ) ? $data['ip'] : []; // @phpstan-ignore-line
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,95 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* @phpstan-type LanguageMap array{
|
||||
* language?: string,
|
||||
* url_from?: string,
|
||||
* url_notfrom?: string
|
||||
* }
|
||||
* @phpstan-type LanguageResult array{
|
||||
* language: string,
|
||||
* url_from?: string,
|
||||
* url_notfrom?: string
|
||||
* }
|
||||
* @phpstan-type LanguageData array{
|
||||
* language: string,
|
||||
* url_from: string,
|
||||
* url_notfrom: string
|
||||
* }
|
||||
*
|
||||
* Check the client language
|
||||
*
|
||||
* @phpstan-extends Red_Match<LanguageMap, LanguageResult>
|
||||
*/
|
||||
class Language_Match extends Red_Match {
|
||||
use FromNotFrom_Match;
|
||||
|
||||
/**
|
||||
* Language to check.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
public $language = '';
|
||||
|
||||
public function name() {
|
||||
return __( 'URL and language', 'redirection' );
|
||||
}
|
||||
|
||||
/**
|
||||
* @param LanguageMap $details
|
||||
* @return LanguageResult
|
||||
*/
|
||||
public function save( array $details, $no_target_url = false ) {
|
||||
$data = array( 'language' => isset( $details['language'] ) ? $this->sanitize_language( $details['language'] ) : '' );
|
||||
|
||||
$result = $this->save_data( $details, $no_target_url, $data );
|
||||
return $result; // @phpstan-ignore-line
|
||||
}
|
||||
|
||||
/**
|
||||
* Sanitize the language value to a CSV string
|
||||
*
|
||||
* @param string $language User supplied language strings.
|
||||
* @return string
|
||||
*/
|
||||
private function sanitize_language( $language ) {
|
||||
$parts = explode( ',', str_replace( ' ', '', sanitize_text_field( $language ) ) );
|
||||
return implode( ',', $parts );
|
||||
}
|
||||
|
||||
public function is_match( $url ) {
|
||||
$matches = explode( ',', $this->language );
|
||||
$requested = Redirection_Request::get_accept_language();
|
||||
|
||||
foreach ( $matches as $match ) {
|
||||
if ( in_array( $match, $requested, true ) ) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return LanguageData
|
||||
*/
|
||||
public function get_data() {
|
||||
return array_merge(
|
||||
array(
|
||||
'language' => $this->language,
|
||||
),
|
||||
$this->get_from_data()
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Load the match data into this instance.
|
||||
*
|
||||
* @param string|LanguageMap $values Match values, as read from the database (plain text, serialized PHP, or parsed array).
|
||||
* @return void
|
||||
*/
|
||||
public function load( $values ) {
|
||||
$data = $this->load_data( $values );
|
||||
$this->language = isset( $data['language'] ) ? $data['language'] : ''; // @phpstan-ignore-line
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,101 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* @phpstan-type LoginMap array{
|
||||
* logged_in?: string,
|
||||
* logged_out?: string
|
||||
* }
|
||||
* @phpstan-type LoginResult array{
|
||||
* logged_in: string,
|
||||
* logged_out: string
|
||||
* }
|
||||
* @phpstan-type LoginData array{
|
||||
* logged_in: string,
|
||||
* logged_out: string
|
||||
* }
|
||||
*
|
||||
* Check whether the user is logged in or out
|
||||
*
|
||||
* @phpstan-extends Red_Match<LoginMap, LoginResult>
|
||||
*/
|
||||
class Login_Match extends Red_Match {
|
||||
/**
|
||||
* Target URL when logged in.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
public $logged_in = '';
|
||||
|
||||
/**
|
||||
* Target URL when logged out.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
public $logged_out = '';
|
||||
|
||||
public function name() {
|
||||
return __( 'URL and login status', 'redirection' );
|
||||
}
|
||||
|
||||
/**
|
||||
* @param LoginMap $details
|
||||
* @return LoginResult|null
|
||||
*/
|
||||
public function save( array $details, $no_target_url = false ) {
|
||||
if ( $no_target_url ) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return [
|
||||
'logged_in' => isset( $details['logged_in'] ) ? $this->sanitize_url( $details['logged_in'] ) : '',
|
||||
'logged_out' => isset( $details['logged_out'] ) ? $this->sanitize_url( $details['logged_out'] ) : '',
|
||||
];
|
||||
}
|
||||
|
||||
public function is_match( $url ) {
|
||||
return is_user_logged_in();
|
||||
}
|
||||
|
||||
public function get_target_url( $requested_url, $source_url, Red_Source_Flags $flags, $match ) {
|
||||
$target = false;
|
||||
|
||||
if ( $match && $this->logged_in !== '' ) {
|
||||
$target = $this->logged_in;
|
||||
} elseif ( ! $match && $this->logged_out !== '' ) {
|
||||
$target = $this->logged_out;
|
||||
}
|
||||
|
||||
if ( $flags->is_regex() && $target !== false ) {
|
||||
$target = $this->get_target_regex_url( $source_url, $target, $requested_url, $flags );
|
||||
}
|
||||
|
||||
return $target;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return LoginData
|
||||
*/
|
||||
public function get_data() {
|
||||
return [
|
||||
'logged_in' => $this->logged_in,
|
||||
'logged_out' => $this->logged_out,
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Load the match data into this instance.
|
||||
*
|
||||
* @param string|LoginMap $values Match values, as read from the database (plain text, serialized PHP, or parsed array).
|
||||
* @return void
|
||||
*/
|
||||
public function load( $values ) {
|
||||
if ( is_string( $values ) ) {
|
||||
$values = @unserialize( $values );
|
||||
}
|
||||
|
||||
if ( is_array( $values ) ) {
|
||||
$this->logged_in = isset( $values['logged_in'] ) ? $values['logged_in'] : '';
|
||||
$this->logged_out = isset( $values['logged_out'] ) ? $values['logged_out'] : '';
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,85 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* @phpstan-type PageMap array{
|
||||
* page?: string,
|
||||
* url?: string
|
||||
* }
|
||||
* @phpstan-type PageResult array{
|
||||
* page: string,
|
||||
* url?: string
|
||||
* }
|
||||
* @phpstan-type PageData array{
|
||||
* page: string,
|
||||
* url: string
|
||||
* }
|
||||
*
|
||||
* Match the WordPress page type
|
||||
*
|
||||
* @phpstan-extends Red_Match<PageMap, PageResult>
|
||||
*/
|
||||
class Page_Match extends Red_Match {
|
||||
use FromUrl_Match;
|
||||
|
||||
/**
|
||||
* Page type
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
public $page = '404';
|
||||
|
||||
public function name() {
|
||||
return __( 'URL and WordPress page type', 'redirection' );
|
||||
}
|
||||
|
||||
/**
|
||||
* Save data to an array, ready for serializing.
|
||||
*
|
||||
* @param PageMap $details New match data.
|
||||
* @param bool $no_target_url Does the action have a target URL.
|
||||
* @return PageResult
|
||||
*/
|
||||
public function save( array $details, $no_target_url = false ) {
|
||||
$data = array( 'page' => isset( $details['page'] ) ? $this->sanitize_page( $details['page'] ) : '404' );
|
||||
|
||||
$result = $this->save_data( $details, $no_target_url, $data );
|
||||
return $result; // @phpstan-ignore-line
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $page
|
||||
* @return string
|
||||
*/
|
||||
private function sanitize_page( $page ) {
|
||||
return '404';
|
||||
}
|
||||
|
||||
public function is_match( $url ) {
|
||||
return is_404();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the match data for persistence.
|
||||
*
|
||||
* @return PageData
|
||||
*/
|
||||
public function get_data() {
|
||||
return array_merge(
|
||||
array(
|
||||
'page' => $this->page,
|
||||
),
|
||||
$this->get_from_data()
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Load the match data into this instance.
|
||||
*
|
||||
* @param string|PageMap $values Match values, as read from the database (plain text, serialized PHP, or parsed array).
|
||||
* @return void
|
||||
*/
|
||||
public function load( $values ) {
|
||||
$data = $this->load_data( $values );
|
||||
$this->page = isset( $data['page'] ) ? $data['page'] : '404'; // @phpstan-ignore-line
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,103 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* @phpstan-type ReferrerMap array{
|
||||
* regex?: bool,
|
||||
* referrer?: string,
|
||||
* url_from?: string,
|
||||
* url_notfrom?: string
|
||||
* }
|
||||
* @phpstan-type ReferrerResult array{
|
||||
* regex: bool,
|
||||
* referrer: string,
|
||||
* url_from?: string,
|
||||
* url_notfrom?: string
|
||||
* }
|
||||
* @phpstan-type ReferrerData array{
|
||||
* regex: bool,
|
||||
* referrer: string,
|
||||
* url_from: string,
|
||||
* url_notfrom: string
|
||||
* }
|
||||
*
|
||||
* Match the referrer
|
||||
*
|
||||
* @phpstan-extends Red_Match<ReferrerMap, ReferrerResult>
|
||||
*/
|
||||
class Referrer_Match extends Red_Match {
|
||||
use FromNotFrom_Match;
|
||||
|
||||
/**
|
||||
* Referrer
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
public $referrer = '';
|
||||
|
||||
/**
|
||||
* Regex match?
|
||||
*
|
||||
* @var boolean
|
||||
*/
|
||||
public $regex = false;
|
||||
|
||||
public function name() {
|
||||
return __( 'URL and referrer', 'redirection' );
|
||||
}
|
||||
|
||||
/**
|
||||
* @param ReferrerMap $details
|
||||
* @return ReferrerResult
|
||||
*/
|
||||
public function save( array $details, $no_target_url = false ) {
|
||||
$data = array(
|
||||
'regex' => isset( $details['regex'] ) && $details['regex'] ? true : false,
|
||||
'referrer' => isset( $details['referrer'] ) ? $this->sanitize_referrer( $details['referrer'] ) : '',
|
||||
);
|
||||
|
||||
$result = $this->save_data( $details, $no_target_url, $data );
|
||||
return $result; // @phpstan-ignore-line
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $agent
|
||||
* @return string
|
||||
*/
|
||||
public function sanitize_referrer( $agent ) {
|
||||
return $this->sanitize_url( $agent );
|
||||
}
|
||||
|
||||
public function is_match( $url ) {
|
||||
if ( $this->regex ) {
|
||||
$regex = new Red_Regex( $this->referrer, true );
|
||||
return $regex->is_match( Redirection_Request::get_referrer() );
|
||||
}
|
||||
|
||||
return Redirection_Request::get_referrer() === $this->referrer;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return ReferrerData
|
||||
*/
|
||||
public function get_data() {
|
||||
return array_merge(
|
||||
array(
|
||||
'regex' => $this->regex,
|
||||
'referrer' => $this->referrer,
|
||||
),
|
||||
$this->get_from_data()
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Load the match data into this instance.
|
||||
*
|
||||
* @param string|ReferrerMap $values Match values, as read from the database (plain text, serialized PHP, or parsed array).
|
||||
* @return void
|
||||
*/
|
||||
public function load( $values ) {
|
||||
$data = $this->load_data( $values );
|
||||
$this->regex = isset( $data['regex'] ) ? $data['regex'] : false; // @phpstan-ignore-line
|
||||
$this->referrer = isset( $data['referrer'] ) ? $data['referrer'] : ''; // @phpstan-ignore-line
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,103 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* @phpstan-type ServerMap array{
|
||||
* server?: string,
|
||||
* url_from?: string,
|
||||
* url_notfrom?: string
|
||||
* }
|
||||
* @phpstan-type ServerResult array{
|
||||
* server: string,
|
||||
* url_from?: string,
|
||||
* url_notfrom?: string
|
||||
* }
|
||||
* @phpstan-type ServerData array{
|
||||
* server: string,
|
||||
* url_from: string,
|
||||
* url_notfrom: string
|
||||
* }
|
||||
*
|
||||
* Match the server URL. Used to match requests for another domain.
|
||||
*
|
||||
* @phpstan-extends Red_Match<ServerMap, ServerResult>
|
||||
*/
|
||||
class Server_Match extends Red_Match {
|
||||
use FromNotFrom_Match;
|
||||
|
||||
/**
|
||||
* Server URL.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
public $server = '';
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function name() {
|
||||
return __( 'URL and server', 'redirection' );
|
||||
}
|
||||
|
||||
/**
|
||||
* @param ServerMap $details
|
||||
* @param bool $no_target_url
|
||||
* @return ServerResult
|
||||
*/
|
||||
public function save( array $details, $no_target_url = false ) {
|
||||
$data = array( 'server' => isset( $details['server'] ) ? $this->sanitize_server( $details['server'] ) : '' );
|
||||
|
||||
$result = $this->save_data( $details, $no_target_url, $data );
|
||||
return $result; // @phpstan-ignore-line
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $server
|
||||
* @return string
|
||||
*/
|
||||
private function sanitize_server( $server ) {
|
||||
if ( strpos( $server, 'http' ) === false ) {
|
||||
$server = ( is_ssl() ? 'https://' : 'http://' ) . $server;
|
||||
}
|
||||
|
||||
$parts = wp_parse_url( $server );
|
||||
|
||||
if ( isset( $parts['host'] ) && isset( $parts['scheme'] ) ) {
|
||||
return $parts['scheme'] . '://' . $parts['host'];
|
||||
}
|
||||
|
||||
return '';
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $url
|
||||
* @return boolean
|
||||
*/
|
||||
public function is_match( $url ) {
|
||||
$server = wp_parse_url( $this->server, PHP_URL_HOST );
|
||||
|
||||
return $server === Redirection_Request::get_server_name();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return ServerData
|
||||
*/
|
||||
public function get_data() {
|
||||
return array_merge(
|
||||
array(
|
||||
'server' => $this->server,
|
||||
),
|
||||
$this->get_from_data()
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Load the match data into this instance.
|
||||
*
|
||||
* @param string|ServerMap $values Match values, as read from the database (plain text, serialized PHP, or parsed array).
|
||||
* @return void
|
||||
*/
|
||||
public function load( $values ) {
|
||||
$data = $this->load_data( $values );
|
||||
$this->server = isset( $data['server'] ) ? $data['server'] : ''; // @phpstan-ignore-line
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,86 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* @phpstan-type UrlMap array{
|
||||
* url?: string
|
||||
* }
|
||||
* @phpstan-type UrlData array{
|
||||
* url: string
|
||||
* }
|
||||
*
|
||||
* Match the URL only.
|
||||
*
|
||||
* @phpstan-extends Red_Match<UrlMap, string>
|
||||
*/
|
||||
class URL_Match extends Red_Match {
|
||||
/**
|
||||
* URL
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
public $url = '';
|
||||
|
||||
public function name() {
|
||||
return __( 'URL only', 'redirection' );
|
||||
}
|
||||
|
||||
/**
|
||||
* @param UrlMap $details
|
||||
* @return string|null
|
||||
*/
|
||||
public function save( array $details, $no_target_url = false ) {
|
||||
$data = isset( $details['url'] ) ? $details['url'] : '';
|
||||
|
||||
if ( strlen( $data ) === 0 ) {
|
||||
$data = '/';
|
||||
}
|
||||
|
||||
if ( $no_target_url ) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return $this->sanitize_url( $data );
|
||||
}
|
||||
|
||||
public function is_match( $url ) {
|
||||
return true;
|
||||
}
|
||||
|
||||
public function get_target_url( $original_url, $matched_url, Red_Source_Flags $flag, $is_matched ) {
|
||||
$target = $this->url;
|
||||
|
||||
if ( $flag->is_regex() ) {
|
||||
$target = $this->get_target_regex_url( $matched_url, $target, $original_url, $flag );
|
||||
}
|
||||
|
||||
return $target;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return UrlData|null
|
||||
*/
|
||||
public function get_data() {
|
||||
if ( $this->url !== '' ) {
|
||||
return [
|
||||
'url' => $this->url,
|
||||
];
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Load the match data into this instance.
|
||||
*
|
||||
* @param string|UrlMap $values Match values, as read from the database (plain text, serialized PHP, or parsed array).
|
||||
* @return void
|
||||
*/
|
||||
public function load( $values ) {
|
||||
if ( is_array( $values ) ) {
|
||||
$this->url = isset( $values['url'] ) ? $values['url'] : '';
|
||||
return;
|
||||
}
|
||||
|
||||
$this->url = $values;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,103 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* @phpstan-type AgentMap array{
|
||||
* regex?: bool,
|
||||
* agent?: string,
|
||||
* url_from?: string,
|
||||
* url_notfrom?: string
|
||||
* }
|
||||
* @phpstan-type AgentResult array{
|
||||
* regex: bool,
|
||||
* agent: string,
|
||||
* url_from?: string,
|
||||
* url_notfrom?: string
|
||||
* }
|
||||
* @phpstan-type AgentData array{
|
||||
* regex: bool,
|
||||
* agent: string,
|
||||
* url_from: string,
|
||||
* url_notfrom: string
|
||||
* }
|
||||
*
|
||||
* Match the user agent
|
||||
*
|
||||
* @phpstan-extends Red_Match<AgentMap, AgentResult>
|
||||
*/
|
||||
class Agent_Match extends Red_Match {
|
||||
use FromNotFrom_Match;
|
||||
|
||||
/**
|
||||
* User agent.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
public $agent = '';
|
||||
|
||||
/**
|
||||
* Is this a regex match?
|
||||
*
|
||||
* @var boolean
|
||||
*/
|
||||
public $regex = false;
|
||||
|
||||
public function name() {
|
||||
return __( 'URL and user agent', 'redirection' );
|
||||
}
|
||||
|
||||
/**
|
||||
* @param AgentMap $details
|
||||
* @return AgentResult
|
||||
*/
|
||||
public function save( array $details, $no_target_url = false ) {
|
||||
$data = array(
|
||||
'regex' => isset( $details['regex'] ) && $details['regex'] ? true : false,
|
||||
'agent' => isset( $details['agent'] ) ? $this->sanitize_agent( $details['agent'] ) : '',
|
||||
);
|
||||
|
||||
$result = $this->save_data( $details, $no_target_url, $data );
|
||||
return $result; // @phpstan-ignore-line
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $agent User agent string.
|
||||
* @return string
|
||||
*/
|
||||
private function sanitize_agent( $agent ) {
|
||||
return $this->sanitize_url( $agent );
|
||||
}
|
||||
|
||||
public function is_match( $url ) {
|
||||
if ( $this->regex ) {
|
||||
$regex = new Red_Regex( $this->agent, true );
|
||||
return $regex->is_match( Redirection_Request::get_user_agent() );
|
||||
}
|
||||
|
||||
return $this->agent === Redirection_Request::get_user_agent();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return AgentData
|
||||
*/
|
||||
public function get_data() {
|
||||
return array_merge(
|
||||
array(
|
||||
'regex' => $this->regex,
|
||||
'agent' => $this->agent,
|
||||
),
|
||||
$this->get_from_data()
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Load the match data into this instance.
|
||||
*
|
||||
* @param string|AgentMap $values Match values, as read from the database (plain text, serialized PHP, or parsed array).
|
||||
* @return void
|
||||
*/
|
||||
public function load( $values ) {
|
||||
$data = $this->load_data( $values );
|
||||
$this->regex = isset( $data['regex'] ) ? $data['regex'] : false; // @phpstan-ignore-line
|
||||
$this->agent = isset( $data['agent'] ) ? $data['agent'] : ''; // @phpstan-ignore-line
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,77 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* @phpstan-type RoleMap array{
|
||||
* role?: string,
|
||||
* url_from?: string,
|
||||
* url_notfrom?: string
|
||||
* }
|
||||
* @phpstan-type RoleResult array{
|
||||
* role: string,
|
||||
* url_from?: string,
|
||||
* url_notfrom?: string
|
||||
* }
|
||||
* @phpstan-type RoleData array{
|
||||
* role: string,
|
||||
* url_from: string,
|
||||
* url_notfrom: string
|
||||
* }
|
||||
*
|
||||
* Match a particular role or capability
|
||||
*
|
||||
* @phpstan-extends Red_Match<RoleMap, RoleResult>
|
||||
*/
|
||||
class Role_Match extends Red_Match {
|
||||
use FromNotFrom_Match;
|
||||
|
||||
/**
|
||||
* WordPress role or capability
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
public $role = '';
|
||||
|
||||
public function name() {
|
||||
return __( 'URL and role/capability', 'redirection' );
|
||||
}
|
||||
|
||||
/**
|
||||
* @param RoleMap $details
|
||||
* @return RoleResult
|
||||
*/
|
||||
public function save( array $details, $no_target_url = false ) {
|
||||
$data = array( 'role' => isset( $details['role'] ) ? $details['role'] : '' );
|
||||
|
||||
/** @var RoleResult $result */
|
||||
$result = $this->save_data( $details, $no_target_url, $data );
|
||||
return $result;
|
||||
}
|
||||
|
||||
public function is_match( $url ) {
|
||||
return current_user_can( $this->role );
|
||||
}
|
||||
|
||||
/**
|
||||
* @return RoleData
|
||||
*/
|
||||
public function get_data() {
|
||||
return array_merge(
|
||||
array(
|
||||
'role' => $this->role,
|
||||
),
|
||||
$this->get_from_data()
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Load the match data into this instance.
|
||||
*
|
||||
* @param string|RoleMap $values Match values, as read from the database (plain text, serialized PHP, or parsed array).
|
||||
* @return void
|
||||
*/
|
||||
public function load( $values ) {
|
||||
$values = $this->load_data( $values );
|
||||
/** @var RoleMap $values */
|
||||
$this->role = isset( $values['role'] ) ? $values['role'] : '';
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user