Created
May 10, 2016 19:01
-
-
Save spacedmonkey/6590eeb5646439c615b1cdb22331be65 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?php | |
class Red_Item { | |
private $id = null; | |
private $created; | |
private $referrer; | |
private $url = null; | |
private $regex = false; | |
private $action_data = null; | |
private $action_code = 0; | |
private $action_type; | |
private $match_type; | |
private $title; | |
private $last_access = null; | |
private $last_count = 0; | |
private $tracking = true; | |
private $status; | |
private $position; | |
private $group_id; | |
function __construct( $values, $type = '', $match = '' ) { | |
if ( is_object( $values ) ) { | |
foreach ( $values as $key => $value ) { | |
$this->$key = $value; | |
} | |
if ( $this->match_type === '' ) { | |
$this->match_type = 'url'; | |
} | |
$this->match = Red_Match::create( $this->match_type, $this->action_data ); | |
$this->match->id = $this->id; | |
$this->match->action_code = $this->action_code; | |
$action = false; | |
if ( $this->action_type ) { | |
$action = Red_Action::create( $this->action_type, $this->action_code ); | |
} | |
if ( $action ) { | |
$this->action = $action; | |
$this->match->action = $this->action; | |
} | |
else | |
$this->action = Red_Action::create( 'nothing', 0 ); | |
if ( $this->last_access === '0000-00-00 00:00:00' ) | |
$this->last_access = 0; | |
else | |
$this->last_access = mysql2date( 'U', $this->last_access ); | |
} | |
else { | |
$this->url = $values; | |
$this->type = $type; | |
$this->match = $match; | |
} | |
} | |
static function get_all_for_module( $module ) { | |
global $wpdb; | |
$rows = Red_Item::get_cache( 'get_all_for_module', $module ); | |
if( false === $rows ){ | |
$sql = $wpdb->prepare( "SELECT {$wpdb->prefix}redirection_items.*,{$wpdb->prefix}redirection_groups.tracking FROM {$wpdb->prefix}redirection_items INNER JOIN {$wpdb->prefix}redirection_groups ON {$wpdb->prefix}redirection_groups.id={$wpdb->prefix}redirection_items.group_id AND {$wpdb->prefix}redirection_groups.status='enabled' AND {$wpdb->prefix}redirection_groups.module_id=%d WHERE {$wpdb->prefix}redirection_items.status='enabled' ORDER BY {$wpdb->prefix}redirection_groups.position,{$wpdb->prefix}redirection_items.position", $module ); | |
$rows = $wpdb->get_results( $sql ); | |
Red_Item::set_cache( 'get_all_for_module', $module, $rows ); | |
} | |
$items = array(); | |
if ( count( $rows ) > 0 ) { | |
foreach ( $rows as $row ) { | |
$items[] = new Red_Item( $row ); | |
} | |
} | |
return $items; | |
} | |
static function get_for_url( $url, $type ) { | |
global $wpdb; | |
$rows = Red_Item::get_cache( 'get_for_url', $url ); | |
if( false === $rows ){ | |
$sql = $wpdb->prepare( "SELECT {$wpdb->prefix}redirection_items.*,{$wpdb->prefix}redirection_groups.position AS group_pos FROM {$wpdb->prefix}redirection_items INNER JOIN {$wpdb->prefix}redirection_groups ON {$wpdb->prefix}redirection_groups.id={$wpdb->prefix}redirection_items.group_id AND {$wpdb->prefix}redirection_groups.status='enabled' AND {$wpdb->prefix}redirection_groups.module_id=%d WHERE ({$wpdb->prefix}redirection_items.regex=1 OR {$wpdb->prefix}redirection_items.url=%s)", WordPress_Module::MODULE_ID, $url ); | |
$rows = $wpdb->get_results( $sql ); | |
Red_Item::set_cache( 'get_for_url', $url, $rows ); | |
} | |
$items = array(); | |
if ( count( $rows ) > 0 ) { | |
foreach ( $rows as $row ) { | |
$items[] = array( 'position' => ( $row->group_pos * 1000 ) + $row->position, 'item' => new Red_Item( $row ) ); | |
} | |
} | |
usort( $items, array( 'Red_Item', 'sort_urls' ) ); | |
$items = array_map( array( 'Red_Item', 'reduce_sorted_items' ), $items ); | |
// Sort it in PHP | |
ksort( $items ); | |
$items = array_values( $items ); | |
return $items; | |
} | |
static function sort_urls( $first, $second ) { | |
if ( $first['position'] === $second['position'] ) | |
return 0; | |
return $first['position'] < $second['position']; | |
} | |
static function reduce_sorted_items( $item ) { | |
return $item['item']; | |
} | |
static function get_by_module( $module ) { | |
global $wpdb; | |
$rows = Red_Item::get_cache( 'get_by_module', $module ); | |
if( false === $rows ){ | |
$sql = "SELECT {$wpdb->prefix}redirection_items.* FROM {$wpdb->prefix}redirection_items INNER JOIN {$wpdb->prefix}redirection_groups ON {$wpdb->prefix}redirection_groups.id={$wpdb->prefix}redirection_items.group_id"; | |
$sql .= $wpdb->prepare( " WHERE {$wpdb->prefix}redirection_groups.module_id=%d", $module ); | |
$rows = $wpdb->get_results( $sql ); | |
Red_Item::set_cache( 'get_by_module', $module, $rows ); | |
} | |
$items = array(); | |
foreach ( (array) $rows as $row ) { | |
$items[] = new Red_Item( $row ); | |
} | |
return $items; | |
} | |
static function get_by_id( $id ) { | |
global $wpdb; | |
$row = Red_Item::get_cache( 'get_by_id', $id ); | |
if( false === $row ){ | |
$row = $wpdb->get_row( $wpdb->prepare( "SELECT * FROM {$wpdb->prefix}redirection_items WHERE id=%d", $id ) ); | |
Red_Item::set_cache( 'get_by_id', $id, $rows ); | |
} | |
if ( $row ) | |
return new Red_Item( $row ); | |
return false; | |
} | |
static function auto_generate() { | |
$options = red_get_options(); | |
$id = time(); | |
$url = $options['auto_target']; | |
$url = str_replace( '$dec$', $id, $url ); | |
$url = str_replace( '$hex$', sprintf( '%x', $id ), $url ); | |
return $url; | |
} | |
static function create( array $details ) { | |
global $wpdb; | |
$details = array_map( 'trim', $details ); | |
$details = array_map( 'stripslashes', $details ); | |
// Auto generate URLs | |
if ( empty( $details['source'] ) ) | |
$details['source'] = self::auto_generate(); | |
if ( empty( $details['target'] ) ) | |
$details['target'] = self::auto_generate(); | |
// Make sure we don't redirect to ourself | |
if ( $details['source'] === $details['target'] ) | |
return new WP_Error( 'redirect-add', __( 'Source and target URL must be different', 'redirection' ) ); | |
$parsed_url = parse_url( $details['source'] ); | |
$parsed_domain = parse_url( site_url() ); | |
if ( isset( $parsed_url['scheme'] ) && ( $parsed_url['scheme'] === 'http' || $parsed_url['scheme'] === 'https' ) && $parsed_url['host'] !== $parsed_domain['host'] ) { | |
return new WP_Error( 'redirect-add', sprintf( __( 'You can only redirect from a relative URL (<code>%s</code>) on this domain (<code>%s</code>).', 'redirection' ), $parsed_url['path'], $parsed_domain['host'] ) ); | |
} | |
$matcher = Red_Match::create( $details['match'] ); | |
$group_id = intval( $details['group_id'] ); | |
$group = Red_Group::get( $group_id ); | |
if ( $group_id <= 0 || ! $group ) | |
return new WP_Error( 'redirect-add', __( 'Invalid group when creating redirect', 'redirection' ) ); | |
if ( ! $matcher ) | |
return new WP_Error( 'redirect-add', __( 'Invalid source URL when creating redirect for given match type', 'redirection' ) ); | |
$regex = ( isset( $details['regex'] ) && $details['regex'] !== false ) ? 1 : 0; | |
$position = $wpdb->get_var( $wpdb->prepare( "SELECT COUNT(*) FROM {$wpdb->prefix}redirection_items WHERE group_id=%d", $group_id ) ); | |
$action = $details['red_action']; | |
$action_code = 0; | |
if ( $action === 'url' || $action === 'random' ) | |
$action_code = 301; | |
elseif ( $action === 'error' ) | |
$action_code = 404; | |
if ( isset( $details['action_code'] ) ) | |
$action_code = intval( $details['action_code'] ); | |
$data = array( | |
'url' => self::sanitize_url( $details['source'], $regex ), | |
'action_type' => $details['red_action'], | |
'regex' => $regex, | |
'position' => $position, | |
'match_type' => $details['match'], | |
'action_data' => $matcher->data( $details ), | |
'action_code' => $action_code, | |
'last_access' => '0000-00-00 00:00:00', | |
'group_id' => $group_id, | |
); | |
$data = apply_filters( 'redirection_create_redirect', $data ); | |
$wpdb->delete( $wpdb->prefix.'redirection_items', array( 'url' => $data['action_data'], 'action_type' => $data['action_type'], 'action_data' => $data['url'] ) ); | |
if ( $wpdb->insert( $wpdb->prefix.'redirection_items', $data ) ) { | |
Red_Item::update_last_updated(); | |
Red_Module::flush( $group_id ); | |
return self::get_by_id( $wpdb->insert_id ); | |
} | |
return new WP_Error( 'redirect-add', __( 'Unable to add new redirect - delete Redirection from the options page and re-install' ) ); | |
} | |
public function delete() { | |
global $wpdb; | |
$wpdb->query( $wpdb->prepare( "DELETE FROM {$wpdb->prefix}redirection_items WHERE id=%d", $this->id ) ); | |
RE_Log::delete_for_id( $this->id ); | |
// Reorder all elements | |
$rows = $wpdb->get_results( "SELECT id FROM {$wpdb->prefix}redirection_items ORDER BY position" ); | |
if ( count( $rows ) > 0 ) { | |
foreach ( $rows as $pos => $row ) { | |
$wpdb->update( $wpdb->prefix.'redirection_items', array( 'position' => $pos ), array( 'id' => $row->id ) ); | |
} | |
} | |
Red_Item::update_last_updated(); | |
Red_Module::flush( $this->group_id ); | |
} | |
static function sanitize_url( $url, $regex = false ) { | |
// Make sure that the old URL is relative | |
$url = preg_replace( '@^https?://(.*?)/@', '/', $url ); | |
$url = preg_replace( '@^https?://(.*?)$@', '/', $url ); | |
// No hash | |
$url = preg_replace( '/#.*$/', '', $url ); | |
// No new lines | |
$url = preg_replace( "/[\r\n\t].*?$/s", '', $url ); | |
// Clean control codes | |
$url = preg_replace( '/[^\PC\s]/u', '', $url ); | |
// Ensure a slash at start | |
if ( substr( $url, 0, 1 ) !== '/' && $regex === false ) | |
$url = '/'.$url; | |
return $url; | |
} | |
function update( $details ) { | |
if ( strlen( $details['old'] ) > 0 ) { | |
global $wpdb; | |
$details = array_map( 'stripslashes', $details ); | |
$this->regex = isset( $details['regex'] ) ? 1 : 0; | |
$this->url = self::sanitize_url( $details['old'], $this->regex ); | |
$this->title = $details['title']; | |
$data = $this->match->data( $details ); | |
$this->action_code = 0; | |
if ( isset( $details['action_code'] ) ) | |
$this->action_code = intval( $details['action_code'] ); | |
$old_group = false; | |
if ( isset( $details['group_id'] ) ) { | |
$old_group = intval( $this->group_id ); | |
$this->group_id = intval( $details['group_id'] ); | |
} | |
// Save this | |
$wpdb->update( $wpdb->prefix.'redirection_items', array( 'url' => $this->url, 'regex' => $this->regex, 'action_code' => $this->action_code, 'action_data' => $data, 'group_id' => $this->group_id, 'title' => $this->title ), array( 'id' => $this->id ) ); | |
Red_Item::update_last_updated(); | |
if ( $old_group !== $this->group_id ) { | |
Red_Module::flush( $this->group_id ); | |
Red_Module::flush( $old_group ); | |
} | |
} | |
} | |
static function save_order( $items, $start ) { | |
global $wpdb; | |
foreach ( $items as $pos => $id ) { | |
$wpdb->update( $wpdb->prefix.'redirection_items', array( 'position' => $pos + $start ), array( 'id' => $id ) ); | |
} | |
Red_Item::update_last_updated(); | |
Red_Module::flush( $this->group_id ); | |
} | |
function matches( $url ) { | |
$this->url = str_replace( ' ', '%20', $this->url ); | |
$matches = false; | |
// Check if we match the URL | |
if ( ( $this->regex === false && ( $this->url === $url || $this->url === rtrim( $url, '/' ) || $this->url === urldecode( $url ) ) ) || ( $this->regex === true && @preg_match( '@'.str_replace( '@', '\\@', $this->url ).'@', $url, $matches ) > 0) || ( $this->regex === true && @preg_match( '@'.str_replace( '@', '\\@', $this->url ).'@', urldecode( $url ), $matches ) > 0) ) { | |
// Check if our match wants this URL | |
$target = $this->match->get_target( $url, $this->url, $this->regex ); | |
if ( $target ) { | |
$target = $this->replace_special_tags( $target ); | |
$this->visit( $url, $target ); | |
if ( $this->status === 'enabled' ) | |
return $this->action->process_before( $this->action_code, $target ); | |
} | |
} | |
return false; | |
} | |
function replace_special_tags( $target ) { | |
if ( is_numeric( $target ) ) | |
$target = get_permalink( $target ); | |
else { | |
$user = wp_get_current_user(); | |
if ( ! empty( $user ) ) { | |
$target = str_replace( '%userid%', $user->ID, $target ); | |
$target = str_replace( '%userlogin%', isset( $user->user_login ) ? $user->user_login : '', $target ); | |
$target = str_replace( '%userurl%', isset( $user->user_url ) ? $user->user_url : '', $target ); | |
} | |
} | |
return $target; | |
} | |
function visit( $url, $target ) { | |
if ( $this->tracking && $this->id ) { | |
global $wpdb, $redirection; | |
// Update the counters | |
$count = $this->last_count + 1; | |
$wpdb->query( $wpdb->prepare( "UPDATE {$wpdb->prefix}redirection_items SET last_count=%d, last_access=NOW() WHERE id=%d", $count, $this->id ) ); | |
if ( isset( $_SERVER['HTTP_X_FORWARDED_FOR'] ) ) | |
$ip = $_SERVER['HTTP_X_FORWARDED_FOR']; | |
elseif ( isset( $_SERVER['REMOTE_ADDR'] ) ) | |
$ip = $_SERVER['REMOTE_ADDR']; | |
$options = red_get_options(); | |
if ( isset( $options['expire_redirect'] ) && $options['expire_redirect'] >= 0 ) | |
$log = RE_Log::create( $url, $target, $_SERVER['HTTP_USER_AGENT'], $ip, isset( $_SERVER['HTTP_REFERER'] ) ? $_SERVER['HTTP_REFERER'] : '', array( 'redirect_id' => $this->id, 'group_id' => $this->group_id ) ); | |
} | |
} | |
public function is_enabled() { | |
return $this->status === 'enabled'; | |
} | |
function reset() { | |
global $wpdb; | |
$this->last_count = 0; | |
$this->last_access = '0000-00-00 00:00:00'; | |
$wpdb->update( $wpdb->prefix.'redirection_items', array( 'last_count' => 0, 'last_access' => $this->last_access ), array( 'id' => $this->id ) ); | |
RE_Log::delete_for_id( $this->id ); | |
} | |
function show_url( $url ) { | |
return implode( '​/', explode( '/', $url ) ); | |
} | |
function move_to( $group ) { | |
global $wpdb; | |
$wpdb->update( $wpdb->prefix.'redirection_items', array( 'group_id' => $group ), array( 'id' => $this->id ) ); | |
} | |
public function enable() { | |
global $wpdb; | |
$this->status = 'enabled'; | |
$wpdb->update( $wpdb->prefix.'redirection_items', array( 'status' => $this->status ), array( 'id' => $this->id ) ); | |
} | |
public function disable() { | |
global $wpdb; | |
$this->status = 'disabled'; | |
$wpdb->update( $wpdb->prefix.'redirection_items', array( 'status' => $this->status ), array( 'id' => $this->id ) ); | |
} | |
static function actions( $action = '' ) { | |
$actions = array( | |
'url' => __( 'Redirect to URL', 'redirection' ), | |
'random' => __( 'Redirect to random post', 'redirection' ), | |
'pass' => __( 'Pass-through', 'redirection' ), | |
'error' => __( 'Error (404)', 'redirection' ), | |
'nothing' => __( 'Do nothing', 'redirection' ), | |
); | |
if ( $action ) | |
return $actions[ $action ]; | |
return $actions; | |
} | |
function match_name() { | |
return $this->match->match_name(); | |
} | |
function type() { | |
if ( ( $this->action_type === 'url' || $this->action_type === 'error' || $this->action_type === 'random' ) && $this->action_code > 0 ) | |
return $this->action_code; | |
else if ( $this->action_type === 'pass' ) | |
return 'pass'; | |
return '—'; | |
} | |
static function get_cache( $method, $key ){ | |
$last_changed = Red_Item::get_last_updated(); | |
$cache_key = "$method:$key:$last_changed"; | |
$value = wp_cache_get( $cache_key, 'redirect' ); | |
return $value; | |
} | |
static function set_cache( $method, $key, $value ){ | |
$last_changed = Red_Item::get_last_updated(); | |
$cache_key = "$method:$key:$last_changed"; | |
$value = wp_cache_set( $cache_key, $value, 'redirect' ); | |
return $value; | |
} | |
static function get_last_updated(){ | |
$last_changed = wp_cache_get( 'last_changed', 'redirect' ); | |
if ( ! $last_changed ) { | |
$last_changed = microtime(); | |
wp_cache_set( 'last_changed', $last_changed, 'redirect' ); | |
} | |
return $last_changed; | |
} | |
static function update_last_updated(){ | |
$last_changed = microtime(); | |
wp_cache_set( 'last_changed', $last_changed, 'redirect' ); | |
} | |
public function get_id() { | |
return $this->id; | |
} | |
public function get_position() { | |
return $this->position; | |
} | |
public function get_group_id() { | |
return $this->group_id; | |
} | |
public function get_url() { | |
return $this->url; | |
} | |
public function get_title() { | |
return $this->title; | |
} | |
public function get_hits() { | |
return $this->last_count; | |
} | |
public function get_last_hit() { | |
return $this->last_access; | |
} | |
public function is_regex() { | |
return $this->regex ? true : false; | |
} | |
public function get_match_type() { | |
return $this->match_type; | |
} | |
public function get_action_type() { | |
return $this->action_type; | |
} | |
public function get_action_code() { | |
return intval( $this->action_code ); | |
} | |
public function get_action_data() { | |
return $this->action_data; | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment