initial
This commit is contained in:
@@ -0,0 +1,234 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* @phpstan-import-type GroupJson from Red_Group
|
||||
*/
|
||||
|
||||
class Red_Apache_File extends Red_FileIO {
|
||||
public function force_download() {
|
||||
parent::force_download();
|
||||
|
||||
header( 'Content-Type: application/octet-stream' );
|
||||
header( 'Content-Disposition: attachment; filename="' . $this->export_filename( 'htaccess' ) . '"' );
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array<Red_Item> $items
|
||||
* @param array<GroupJson> $groups
|
||||
* @return string
|
||||
*/
|
||||
public function get_data( array $items, array $groups ) {
|
||||
include_once dirname( __DIR__ ) . '/models/htaccess.php';
|
||||
|
||||
$htaccess = new Red_Htaccess();
|
||||
|
||||
foreach ( $items as $item ) {
|
||||
$htaccess->add( $item );
|
||||
}
|
||||
|
||||
return $htaccess->get() . PHP_EOL;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $group Group ID to import into.
|
||||
* @param string $filename Path to the file to import.
|
||||
* @param string|false $data File contents (or false if not pre-loaded).
|
||||
* @return int
|
||||
*/
|
||||
public function load( $group, $filename, $data ) {
|
||||
if ( $data === false ) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Remove any comments
|
||||
$data = str_replace( "\n", "\r", $data );
|
||||
|
||||
// Split it into lines
|
||||
$lines = array_filter( explode( "\r", $data ) );
|
||||
$count = 0;
|
||||
|
||||
foreach ( $lines as $line ) {
|
||||
$item = $this->get_as_item( $line );
|
||||
|
||||
if ( $item !== false ) {
|
||||
$item['group_id'] = $group;
|
||||
$redirect = Red_Item::create( $item );
|
||||
|
||||
if ( ! is_wp_error( $redirect ) ) {
|
||||
$count++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $count;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $line
|
||||
* @return array<string, mixed>|false
|
||||
*/
|
||||
public function get_as_item( $line ) {
|
||||
$item = false;
|
||||
|
||||
if ( preg_match( '@rewriterule\s+(.*?)\s+(.*?)\s+(\[.*\])*@i', $line, $matches ) > 0 ) {
|
||||
$item = array(
|
||||
'url' => $this->regex_url( $matches[1] ),
|
||||
'match_type' => 'url',
|
||||
'action_type' => 'url',
|
||||
'action_data' => array( 'url' => $this->decode_url( $matches[2] ) ),
|
||||
'action_code' => $this->get_code( isset( $matches[3] ) ? $matches[3] : '' ),
|
||||
'regex' => $this->is_regex( $matches[1] ),
|
||||
);
|
||||
} elseif ( preg_match( '@Redirect\s+(.*?)\s+"(.*?)"\s+(.*)@i', $line, $matches ) > 0 || preg_match( '@Redirect\s+(.*?)\s+(.*?)\s+(.*)@i', $line, $matches ) > 0 ) {
|
||||
$item = array(
|
||||
'url' => $this->decode_url( $matches[2] ),
|
||||
'match_type' => 'url',
|
||||
'action_type' => 'url',
|
||||
'action_data' => array( 'url' => $this->decode_url( $matches[3] ) ),
|
||||
'action_code' => $this->get_code( $matches[1] ),
|
||||
);
|
||||
} elseif ( preg_match( '@Redirect\s+"(.*?)"\s+(.*)@i', $line, $matches ) > 0 || preg_match( '@Redirect\s+(.*?)\s+(.*)@i', $line, $matches ) > 0 ) {
|
||||
$item = array(
|
||||
'url' => $this->decode_url( $matches[1] ),
|
||||
'match_type' => 'url',
|
||||
'action_type' => 'url',
|
||||
'action_data' => array( 'url' => $this->decode_url( $matches[2] ) ),
|
||||
'action_code' => 302,
|
||||
);
|
||||
} elseif ( preg_match( '@Redirectmatch\s+(.*?)\s+(.*?)\s+(.*)@i', $line, $matches ) > 0 ) {
|
||||
$item = array(
|
||||
'url' => $this->decode_url( $matches[2] ),
|
||||
'match_type' => 'url',
|
||||
'action_type' => 'url',
|
||||
'action_data' => array( 'url' => $this->decode_url( $matches[3] ) ),
|
||||
'action_code' => $this->get_code( $matches[1] ),
|
||||
'regex' => true,
|
||||
);
|
||||
} elseif ( preg_match( '@Redirectmatch\s+(.*?)\s+(.*)@i', $line, $matches ) > 0 ) {
|
||||
$item = array(
|
||||
'url' => $this->decode_url( $matches[1] ),
|
||||
'match_type' => 'url',
|
||||
'action_type' => 'url',
|
||||
'action_data' => array( 'url' => $this->decode_url( $matches[2] ) ),
|
||||
'action_code' => 302,
|
||||
'regex' => true,
|
||||
);
|
||||
}
|
||||
|
||||
if ( $item !== false ) {
|
||||
$item['action_type'] = 'url';
|
||||
$item['match_type'] = 'url';
|
||||
|
||||
if ( $item['action_code'] === 0 ) {
|
||||
$item['action_type'] = 'pass';
|
||||
}
|
||||
|
||||
return $item;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $url
|
||||
* @return string
|
||||
*/
|
||||
private function decode_url( $url ) {
|
||||
$url = rawurldecode( $url );
|
||||
|
||||
// Replace quoted slashes
|
||||
$url = (string) preg_replace( '@\\\/@', '/', $url );
|
||||
|
||||
// Ensure escaped '.' is still escaped
|
||||
$url = (string) preg_replace( '@\\\\.@', '\\\\.', $url );
|
||||
return $url;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $url
|
||||
* @return bool
|
||||
*/
|
||||
private function is_str_regex( $url ) {
|
||||
$regex = '()[]$^?+.';
|
||||
$len = strlen( $url );
|
||||
|
||||
for ( $x = 0; $x < $len; $x++ ) {
|
||||
$escape = false;
|
||||
$char = substr( $url, $x, 1 );
|
||||
|
||||
if ( $char === '\\' ) {
|
||||
$escape = true;
|
||||
} elseif ( strpos( $regex, $char ) !== false ) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $url
|
||||
* @return bool
|
||||
*/
|
||||
private function is_regex( $url ) {
|
||||
if ( $this->is_str_regex( $url ) ) {
|
||||
$tmp = ltrim( $url, '^' );
|
||||
$tmp = rtrim( $tmp, '$' );
|
||||
|
||||
if ( $this->is_str_regex( $tmp ) ) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $url
|
||||
* @return string
|
||||
*/
|
||||
private function regex_url( $url ) {
|
||||
$url = $this->decode_url( $url );
|
||||
|
||||
if ( $this->is_str_regex( $url ) ) {
|
||||
$tmp = ltrim( $url, '^' );
|
||||
$tmp = rtrim( $tmp, '$' );
|
||||
|
||||
if ( $this->is_str_regex( $tmp ) ) {
|
||||
return '^/' . ltrim( $tmp, '/' );
|
||||
}
|
||||
|
||||
return '/' . ltrim( $tmp, '/' );
|
||||
}
|
||||
|
||||
return $this->decode_url( $url );
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $code
|
||||
* @return int
|
||||
*/
|
||||
private function get_code( $code ) {
|
||||
if ( strpos( $code, '301' ) !== false || stripos( $code, 'permanent' ) !== false ) {
|
||||
return 301;
|
||||
}
|
||||
|
||||
if ( strpos( $code, '302' ) !== false ) {
|
||||
return 302;
|
||||
}
|
||||
|
||||
if ( strpos( $code, '307' ) !== false || stripos( $code, 'seeother' ) !== false ) {
|
||||
return 307;
|
||||
}
|
||||
|
||||
if ( strpos( $code, '404' ) !== false || stripos( $code, 'forbidden' ) !== false || strpos( $code, 'F' ) !== false ) {
|
||||
return 404;
|
||||
}
|
||||
|
||||
if ( strpos( $code, '410' ) !== false || stripos( $code, 'gone' ) !== false || strpos( $code, 'G' ) !== false ) {
|
||||
return 410;
|
||||
}
|
||||
|
||||
return 302;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,254 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* CSV import/export handler
|
||||
*
|
||||
* @phpstan-type CsvItem array{
|
||||
* url: string,
|
||||
* action_data: array{url: string},
|
||||
* regex: bool,
|
||||
* group_id: int,
|
||||
* match_type: 'url',
|
||||
* action_type: 'url'|'error',
|
||||
* action_code: int,
|
||||
* status?: 'enabled'|'disabled'
|
||||
* }
|
||||
* @phpstan-import-type GroupJson from Red_Group
|
||||
*/
|
||||
class Red_Csv_File extends Red_FileIO {
|
||||
const CSV_SOURCE = 0;
|
||||
const CSV_TARGET = 1;
|
||||
const CSV_REGEX = 2;
|
||||
const CSV_CODE = 3;
|
||||
|
||||
public function force_download() {
|
||||
parent::force_download();
|
||||
|
||||
header( 'Content-Type: text/csv' );
|
||||
header( 'Content-Disposition: attachment; filename="' . $this->export_filename( 'csv' ) . '"' );
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array<Red_Item> $items
|
||||
* @param array<GroupJson> $groups
|
||||
* @return string
|
||||
*/
|
||||
public function get_data( array $items, array $groups ) {
|
||||
$lines = [ implode( ',', array( 'source', 'target', 'regex', 'code', 'type', 'hits', 'title', 'status' ) ) ];
|
||||
|
||||
foreach ( $items as $line ) {
|
||||
$lines[] = $this->item_as_csv( $line );
|
||||
}
|
||||
|
||||
return implode( PHP_EOL, $lines ) . PHP_EOL;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Red_Item $item
|
||||
* @return string
|
||||
*/
|
||||
public function item_as_csv( $item ) {
|
||||
$data = [];
|
||||
|
||||
if ( $item->match !== null ) {
|
||||
$data = $item->match->get_data();
|
||||
}
|
||||
|
||||
if ( isset( $data['url'] ) ) {
|
||||
$data = $data['url'];
|
||||
} else {
|
||||
$data = '/unknown';
|
||||
}
|
||||
|
||||
if ( $item->get_action_code() > 400 && $item->get_action_code() < 500 ) {
|
||||
$data = '';
|
||||
}
|
||||
|
||||
$csv = array(
|
||||
$item->get_url(),
|
||||
$data,
|
||||
$item->is_regex() ? 1 : 0,
|
||||
$item->get_action_code(),
|
||||
$item->get_action_type(),
|
||||
$item->get_hits(),
|
||||
$item->get_title(),
|
||||
$item->is_enabled() ? 'active' : 'disabled',
|
||||
);
|
||||
|
||||
$csv = array_map( array( $this, 'escape_csv' ), $csv );
|
||||
return implode( ',', $csv );
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string|int|float $item
|
||||
* @return string|int|float
|
||||
*/
|
||||
public function escape_csv( $item ) {
|
||||
if ( is_numeric( $item ) ) {
|
||||
return $item;
|
||||
}
|
||||
|
||||
return '"' . str_replace( '"', '""', $item ) . '"';
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $group Group ID to import into.
|
||||
* @param string $filename Path to the file to import.
|
||||
* @param string|false $data File contents (or false if not pre-loaded).
|
||||
* @return int
|
||||
*/
|
||||
public function load( $group, $filename, $data ) {
|
||||
$file = fopen( $filename, 'r' );
|
||||
|
||||
if ( $file !== false ) {
|
||||
$separators = [
|
||||
',',
|
||||
';',
|
||||
'|',
|
||||
];
|
||||
|
||||
foreach ( $separators as $separator ) {
|
||||
fseek( $file, 0 );
|
||||
$count = $this->load_from_file( $group, $file, $separator );
|
||||
|
||||
if ( $count > 0 ) {
|
||||
return $count;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $group_id
|
||||
* @param resource $file
|
||||
* @param string $separator
|
||||
* @return int
|
||||
*/
|
||||
public function load_from_file( $group_id, $file, $separator ) {
|
||||
global $wpdb;
|
||||
|
||||
$count = 0;
|
||||
$group = Red_Group::get( $group_id );
|
||||
if ( $group === false ) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
/** @var Red_Group $group */
|
||||
|
||||
while ( ( $csv = fgetcsv( $file, 5000, $separator ) ) !== false ) {
|
||||
if ( $csv === null ) {
|
||||
continue;
|
||||
}
|
||||
|
||||
/** @var array<int, string> $csv */
|
||||
$csv = array_map(
|
||||
function ( $v ) {
|
||||
return (string) $v;
|
||||
},
|
||||
$csv
|
||||
);
|
||||
$item = $this->csv_as_item( $csv, $group );
|
||||
|
||||
if ( $item !== false && $this->item_is_valid( $item ) ) {
|
||||
$created = Red_Item::create( $item );
|
||||
|
||||
// The query log can use up all the memory
|
||||
$wpdb->queries = [];
|
||||
|
||||
if ( ! is_wp_error( $created ) ) {
|
||||
$count++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $count;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param CsvItem $csv
|
||||
* @return bool
|
||||
*/
|
||||
private function item_is_valid( array $csv ) {
|
||||
if ( strlen( $csv['url'] ) === 0 ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if ( $csv['action_data']['url'] === $csv['url'] ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param mixed $code
|
||||
* @return int
|
||||
*/
|
||||
private function get_valid_code( $code ) {
|
||||
if ( get_status_header_desc( $code ) !== '' ) {
|
||||
return intval( $code, 10 );
|
||||
}
|
||||
|
||||
return 301;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $code
|
||||
* @return 'url'|'error'
|
||||
*/
|
||||
private function get_action_type( $code ) {
|
||||
if ( $code > 400 && $code < 500 ) {
|
||||
return 'error';
|
||||
}
|
||||
|
||||
return 'url';
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array<int, string> $csv
|
||||
* @param Red_Group $group
|
||||
* @return CsvItem|false
|
||||
*/
|
||||
public function csv_as_item( $csv, Red_Group $group ) {
|
||||
if ( count( $csv ) > 1 && $csv[ self::CSV_SOURCE ] !== 'source' && $csv[ self::CSV_TARGET ] !== 'target' ) {
|
||||
$code = isset( $csv[ self::CSV_CODE ] ) ? $this->get_valid_code( $csv[ self::CSV_CODE ] ) : 301;
|
||||
|
||||
return array(
|
||||
'url' => trim( $csv[ self::CSV_SOURCE ] ),
|
||||
'action_data' => array( 'url' => trim( $csv[ self::CSV_TARGET ] ) ),
|
||||
'regex' => isset( $csv[ self::CSV_REGEX ] ) ? $this->parse_regex( $csv[ self::CSV_REGEX ] ) : $this->is_regex( $csv[ self::CSV_SOURCE ] ),
|
||||
'group_id' => $group->get_id(),
|
||||
'match_type' => 'url',
|
||||
'action_type' => $this->get_action_type( $code ),
|
||||
'action_code' => $code,
|
||||
'status' => $group->is_enabled() ? 'enabled' : 'disabled',
|
||||
);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string|int $value
|
||||
* @return bool
|
||||
*/
|
||||
private function parse_regex( $value ) {
|
||||
return intval( $value, 10 ) === 1 ? true : false;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $url
|
||||
* @return bool
|
||||
*/
|
||||
private function is_regex( $url ) {
|
||||
$regex = '()[]$^*';
|
||||
|
||||
if ( strpbrk( $url, $regex ) === false ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,109 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* @phpstan-import-type GroupJson from Red_Group
|
||||
*/
|
||||
|
||||
class Red_Json_File extends Red_FileIO {
|
||||
public function force_download() {
|
||||
parent::force_download();
|
||||
|
||||
header( 'Content-Type: application/json' );
|
||||
header( 'Content-Disposition: attachment; filename="' . $this->export_filename( 'json' ) . '"' );
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array<Red_Item> $items
|
||||
* @param array<GroupJson> $groups
|
||||
* @return string
|
||||
*/
|
||||
public function get_data( array $items, array $groups ) {
|
||||
$version = red_get_plugin_data( dirname( __DIR__ ) . '/redirection.php' );
|
||||
|
||||
$items = array(
|
||||
'plugin' => array(
|
||||
'version' => trim( $version['Version'] ),
|
||||
'date' => gmdate( 'r' ),
|
||||
),
|
||||
'groups' => $groups,
|
||||
'redirects' => array_map(
|
||||
function ( $item ) {
|
||||
return $item->to_json();
|
||||
},
|
||||
$items
|
||||
),
|
||||
);
|
||||
|
||||
return wp_json_encode( $items, JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES ) . PHP_EOL;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $group Group ID to import into.
|
||||
* @param string $filename Path to the file to import.
|
||||
* @param string|false $data File contents (or false if not pre-loaded).
|
||||
* @return int
|
||||
*/
|
||||
public function load( $group, $filename, $data ) {
|
||||
global $wpdb;
|
||||
|
||||
if ( $data === false ) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
$count = 0;
|
||||
/** @var array<string, mixed>|false $json */
|
||||
$json = @json_decode( $data, true );
|
||||
if ( $json === false ) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Import groups
|
||||
$group_map = array();
|
||||
|
||||
if ( isset( $json['groups'] ) ) {
|
||||
foreach ( $json['groups'] as $json_group ) {
|
||||
$old_group_id = $json_group['id'];
|
||||
unset( $json_group['id'] );
|
||||
|
||||
$json_group = Red_Group::create( $json_group['name'], $json_group['module_id'], $json_group['enabled'] ? true : false );
|
||||
if ( $json_group !== false ) {
|
||||
$group_map[ $old_group_id ] = $json_group->get_id();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
unset( $json['groups'] );
|
||||
|
||||
// Import redirects
|
||||
if ( isset( $json['redirects'] ) ) {
|
||||
foreach ( $json['redirects'] as $pos => $redirect ) {
|
||||
unset( $redirect['id'] );
|
||||
|
||||
if ( ! isset( $group_map[ $redirect['group_id'] ] ) ) {
|
||||
$new_group = Red_Group::create( 'Group', 1 );
|
||||
if ( $new_group !== false ) {
|
||||
$group_map[ $redirect['group_id'] ] = $new_group->get_id();
|
||||
}
|
||||
}
|
||||
|
||||
if ( $redirect['match_type'] === 'url' && isset( $redirect['action_data'] ) && ! is_array( $redirect['action_data'] ) ) {
|
||||
$redirect['action_data'] = array( 'url' => $redirect['action_data'] );
|
||||
}
|
||||
|
||||
$redirect['group_id'] = $group_map[ $redirect['group_id'] ];
|
||||
$created = Red_Item::create( $redirect );
|
||||
|
||||
if ( $created instanceof Red_Item ) {
|
||||
$count++;
|
||||
}
|
||||
|
||||
// Helps reduce memory usage
|
||||
unset( $json['redirects'][ $pos ] );
|
||||
$wpdb->queries = array();
|
||||
$wpdb->num_queries = 0;
|
||||
}
|
||||
}
|
||||
|
||||
return $count;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,189 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* @phpstan-import-type GroupJson from Red_Group
|
||||
* @phpstan-import-type RedirectMatchData from Red_Item
|
||||
*/
|
||||
|
||||
class Red_Nginx_File extends Red_FileIO {
|
||||
public function force_download() {
|
||||
parent::force_download();
|
||||
|
||||
header( 'Content-Type: application/octet-stream' );
|
||||
header( 'Content-Disposition: attachment; filename="' . $this->export_filename( 'nginx' ) . '"' );
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array<Red_Item> $items
|
||||
* @param array<GroupJson> $groups
|
||||
* @return string
|
||||
*/
|
||||
public function get_data( array $items, array $groups ) {
|
||||
$lines = array();
|
||||
$version = red_get_plugin_data( dirname( __DIR__ ) . '/redirection.php' );
|
||||
|
||||
$lines[] = '# Created by Redirection';
|
||||
$lines[] = '# ' . gmdate( 'r' );
|
||||
$lines[] = '# Redirection ' . trim( $version['Version'] ) . ' - https://redirection.me';
|
||||
$lines[] = '';
|
||||
$lines[] = 'server {';
|
||||
|
||||
$parts = array();
|
||||
foreach ( $items as $item ) {
|
||||
if ( $item->is_enabled() ) {
|
||||
$parts[] = $this->get_nginx_item( $item );
|
||||
}
|
||||
}
|
||||
|
||||
$lines = array_merge( $lines, array_filter( $parts ) );
|
||||
|
||||
$lines[] = '}';
|
||||
$lines[] = '';
|
||||
$lines[] = '# End of Redirection';
|
||||
|
||||
return implode( PHP_EOL, $lines ) . PHP_EOL;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return 'permanent'|'redirect'
|
||||
*/
|
||||
private function get_redirect_code( Red_Item $item ) {
|
||||
if ( $item->get_action_code() === 301 ) {
|
||||
return 'permanent';
|
||||
}
|
||||
return 'redirect';
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $group Group ID to import into.
|
||||
* @param string $filename Path to the file to import.
|
||||
* @param string|false $data File contents (or false if not pre-loaded).
|
||||
* @return int
|
||||
*/
|
||||
public function load( $group, $filename, $data ) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string|false
|
||||
*/
|
||||
private function get_nginx_item( Red_Item $item ) {
|
||||
$target = 'add_' . $item->get_match_type();
|
||||
|
||||
if ( method_exists( $this, $target ) ) {
|
||||
$match_data = $item->get_match_data();
|
||||
$match_data = is_array( $match_data ) ? $match_data : array();
|
||||
// @phpstan-ignore method.dynamicName
|
||||
return ' ' . $this->$target( $item, $match_data );
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param RedirectMatchData $match_data
|
||||
* @return string
|
||||
*/
|
||||
private function add_url( Red_Item $item, array $match_data ) {
|
||||
// @phpstan-ignore booleanAnd.rightAlwaysTrue
|
||||
$source = isset( $match_data['source'] ) && is_array( $match_data['source'] ) ? $match_data['source'] : null;
|
||||
$regex = $item->source_flags !== null && $item->source_flags->is_regex();
|
||||
|
||||
return $this->get_redirect( $item->get_url(), $item->get_action_data(), $this->get_redirect_code( $item ), $source, $regex );
|
||||
}
|
||||
|
||||
/**
|
||||
* @param RedirectMatchData $match_data
|
||||
* @return string
|
||||
*/
|
||||
private function add_agent( Red_Item $item, array $match_data ) {
|
||||
$lines = array();
|
||||
|
||||
// @phpstan-ignore booleanAnd.rightAlwaysTrue
|
||||
$source = isset( $match_data['source'] ) && is_array( $match_data['source'] ) ? $match_data['source'] : null;
|
||||
|
||||
// Help PHPStan: ensure we operate on an Agent_Match
|
||||
$match = $item->match;
|
||||
if ( ! ( $match instanceof Agent_Match ) ) {
|
||||
return '';
|
||||
}
|
||||
|
||||
if ( $match->url_from !== '' ) {
|
||||
$lines[] = 'if ( $http_user_agent ~* ^' . $match->agent . '$ ) {';
|
||||
$lines[] = ' ' . $this->get_redirect( $item->get_url(), $match->url_from, $this->get_redirect_code( $item ), $source );
|
||||
$lines[] = ' }';
|
||||
}
|
||||
|
||||
if ( $match->url_notfrom !== '' ) {
|
||||
$lines[] = 'if ( $http_user_agent !~* ^' . $match->agent . '$ ) {';
|
||||
$lines[] = ' ' . $this->get_redirect( $item->get_url(), $match->url_notfrom, $this->get_redirect_code( $item ), $source );
|
||||
$lines[] = ' }';
|
||||
}
|
||||
|
||||
return implode( "\n", $lines );
|
||||
}
|
||||
|
||||
/**
|
||||
* @param RedirectMatchData $match_data
|
||||
* @return string
|
||||
*/
|
||||
private function add_referrer( Red_Item $item, array $match_data ) {
|
||||
$lines = array();
|
||||
// @phpstan-ignore booleanAnd.rightAlwaysTrue
|
||||
$source = isset( $match_data['source'] ) && is_array( $match_data['source'] ) ? $match_data['source'] : null;
|
||||
|
||||
// Help PHPStan: ensure we operate on a Referrer_Match
|
||||
$match = $item->match;
|
||||
if ( ! ( $match instanceof Referrer_Match ) ) {
|
||||
return '';
|
||||
}
|
||||
|
||||
if ( $match->url_from !== '' ) {
|
||||
$lines[] = 'if ( $http_referer ~* ^' . $match->referrer . '$ ) {';
|
||||
$lines[] = ' ' . $this->get_redirect( $item->get_url(), $match->url_from, $this->get_redirect_code( $item ), $source );
|
||||
$lines[] = ' }';
|
||||
}
|
||||
|
||||
if ( $match->url_notfrom !== '' ) {
|
||||
$lines[] = 'if ( $http_referer !~* ^' . $match->referrer . '$ ) {';
|
||||
$lines[] = ' ' . $this->get_redirect( $item->get_url(), $match->url_notfrom, $this->get_redirect_code( $item ), $source );
|
||||
$lines[] = ' }';
|
||||
}
|
||||
|
||||
return implode( "\n", $lines );
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $line
|
||||
* @param string $target
|
||||
* @param 'permanent'|'redirect' $code
|
||||
* @param array{
|
||||
* flag_query?: 'ignore'|'exact'|'pass'|'exactorder',
|
||||
* flag_case?: bool,
|
||||
* flag_trailing?: bool,
|
||||
* flag_regex?: bool
|
||||
* }|null $source
|
||||
* @param bool $regex
|
||||
* @return string
|
||||
*/
|
||||
private function get_redirect( $line, $target, $code, $source, $regex = false ) {
|
||||
$line = ltrim( $line, '^' );
|
||||
$line = rtrim( $line, '$' );
|
||||
|
||||
$source_url = new Red_Url_Encode( $line, $regex );
|
||||
$target_url = new Red_Url_Encode( $target );
|
||||
|
||||
// Remove any existing start/end from a regex
|
||||
$from = $source_url->get_as_source();
|
||||
$from = ltrim( $from, '^' );
|
||||
$from = rtrim( $from, '$' );
|
||||
|
||||
if ( isset( $source['flag_case'] ) && $source['flag_case'] ) {
|
||||
$from = '(?i)^' . $from;
|
||||
} else {
|
||||
$from = '^' . $from;
|
||||
}
|
||||
|
||||
return 'rewrite ' . $from . '$ ' . $target_url->get_as_target() . ' ' . $code . ';';
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,62 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* @phpstan-import-type GroupJson from Red_Group
|
||||
*/
|
||||
|
||||
class Red_Rss_File extends Red_FileIO {
|
||||
public function force_download() {
|
||||
header( 'Content-type: text/xml; charset=' . get_option( 'blog_charset' ), true );
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array<Red_Item> $items
|
||||
* @param array<GroupJson> $groups
|
||||
* @return string
|
||||
*/
|
||||
public function get_data( array $items, array $groups ) {
|
||||
$xml = '<?xml version="1.0" encoding="' . get_option( 'blog_charset' ) . '"?' . ">\r\n";
|
||||
ob_start();
|
||||
?>
|
||||
<rss version="2.0"
|
||||
xmlns:content="http://purl.org/rss/1.0/modules/content/"
|
||||
xmlns:wfw="http://wellformedweb.org/CommentAPI/"
|
||||
xmlns:dc="http://purl.org/dc/elements/1.1/">
|
||||
<channel>
|
||||
<title>Redirection - <?php bloginfo_rss( 'name' ); ?></title>
|
||||
<description><?php esc_html( bloginfo_rss( 'description' ) ); ?></description>
|
||||
<pubDate><?php echo esc_html( (string) mysql2date( 'D, d M Y H:i:s +0000', get_lastpostmodified( 'gmt' ), false ) ); ?></pubDate>
|
||||
<generator>
|
||||
<?php echo esc_html( 'http://wordpress.org/?v=' ); ?>
|
||||
<?php bloginfo_rss( 'version' ); ?>
|
||||
</generator>
|
||||
<language><?php echo esc_html( get_option( 'rss_language' ) ); ?></language>
|
||||
|
||||
<?php foreach ( $items as $log ) : ?>
|
||||
<item>
|
||||
<title><?php echo esc_html( $log->get_url() ); ?></title>
|
||||
<link><![CDATA[<?php echo esc_url( home_url() ) . esc_url( $log->get_url() ); ?>]]></link>
|
||||
<pubDate><?php echo esc_html( gmdate( 'D, d M Y H:i:s +0000', intval( $log->get_last_hit(), 10 ) ) ); ?></pubDate>
|
||||
<guid isPermaLink="false"><?php echo esc_html( (string) $log->get_id() ); ?></guid>
|
||||
<description><?php echo esc_html( $log->get_url() ); ?></description>
|
||||
</item>
|
||||
<?php endforeach; ?>
|
||||
</channel>
|
||||
</rss>
|
||||
<?php
|
||||
$xml .= ob_get_contents();
|
||||
ob_end_clean();
|
||||
|
||||
return $xml;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $group Group ID to import into.
|
||||
* @param string $filename Path to the file to import.
|
||||
* @param string|false $data File contents (or false if not pre-loaded).
|
||||
* @return int
|
||||
*/
|
||||
public function load( $group, $filename, $data ) {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user