'a' . bin2hex( openssl_random_pseudo_bytes( 5 ) ),
'/ad-type-1/' => 'a' . bin2hex( openssl_random_pseudo_bytes( 5 ) ),
'/ad_type_1/' => 'a' . bin2hex( openssl_random_pseudo_bytes( 5 ) ),
'/znContentIndicator/' => 'a' . bin2hex( openssl_random_pseudo_bytes( 5 ) ),
'/advlabel/' => 'a' . bin2hex( openssl_random_pseudo_bytes( 5 ) ),
'/adbladetitle/' => 'a' . bin2hex( openssl_random_pseudo_bytes( 5 ) ),
'/zone/' => 'a' . bin2hex( openssl_random_pseudo_bytes( 5 ) ),
);
update_option( ADBLADE_OPTIONS_KEY, $options, 'yes' );
// delete the transients because they have bad data now
foreach ( $transients as $transient ) {
if ( delete_transient( $transient ) ) {
adblade_log( 'deleted transient ' . $transient );
}
}
// try to remove pages with bad tags
wp_cache_flush();
}
}
add_action( 'adblade_cron_event', 'adblade_regenerate_bypass_rules' );
function adblade_deactivation() {
wp_clear_scheduled_hook( ADBLADE_CRON );
}
register_deactivation_hook( __FILE__, 'adblade_deactivation' );
// But WordPress has a whitelist of variables it allows, so we must put it on that list
function adblade_query_vars( $queryVars ) {
$options = get_option( ADBLADE_OPTIONS_KEY );
if ( false !== $options && array_key_exists( 'query_var', $options ) ) {
$queryVars[] = $options['query_var'];
$queryVars[] = $options['query_var'] . 'path';
}
// also add options for archived settings
$archivedOptions = get_transient( ADBLADE_OPTIONS_ARCHIVE_KEY );
if ( false !== $archivedOptions && array_key_exists( 'query_var', $archivedOptions ) ) {
$queryVars[] = $archivedOptions['query_var'];
$queryVars[] = $archivedOptions['query_var'] . 'path';
}
return $queryVars;
}
add_action( 'query_vars', 'adblade_query_vars' );
// add "settings" link on plugins page
function adblade_add_action_links( $links ) {
$links[] = 'Settings';
return $links;
}
add_filter( 'plugin_action_links_' . plugin_basename( __FILE__ ), 'adblade_add_action_links' );
// If this is done, we can access it later
// This example checks very early in the process:
// if the variable is set, we include our page and stop execution after it
function adblade_parse_request( &$wp ) {
$options = get_option( ADBLADE_OPTIONS_KEY );
$archivedOptions = get_transient( ADBLADE_OPTIONS_ARCHIVE_KEY );
if ( do_adblade_bypass() ) {
$queryVars = $wp->query_vars;
$query = null;
$path = null;
if ( false !== $options && array_key_exists( $options['query_var'], $queryVars ) ) {
$query = $queryVars[ $options['query_var'] ];
if ( array_key_exists( $options['query_var'] . 'path', $queryVars ) ) {
$path = $queryVars[ $options['query_var'] . 'path' ];
}
} else if ( false !== $archivedOptions && array_key_exists( $archivedOptions['query_var'], $queryVars ) ) {
$query = $queryVars[ $archivedOptions['query_var'] ];
if ( array_key_exists( $archivedOptions['query_var'] . 'path', $queryVars ) ) {
$path = $queryVars[ $archivedOptions['query_var'] . 'path' ];
}
}
if ( null !== $query ) {
switch ( $query ) {
case $options['redirect_actions']['blockadblock']:
case $archivedOptions['redirect_actions']['blockadblock']:
header( 'Content-Type: application/javascript' );
echo file_get_contents( WP_PLUGIN_DIR . '/adblade-publisher-tools/js/blockadblock.js' );
break;
case $options['redirect_actions']['logab']:
case $archivedOptions['redirect_actions']['logab']:
header( 'Content-Type: application/javascript' );
include WP_PLUGIN_DIR . '/adblade-publisher-tools/js/log-ab.php';
break;
case $options['redirect_actions']['show']:
case $archivedOptions['redirect_actions']['show']:
header( 'Content-Type: application/javascript' );
adblade_proxy( 'web.adblade.com', '/js/ads/async/show.js' );
break;
case $options['redirect_actions']['impsc']:
case $archivedOptions['redirect_actions']['impsc']:
$queryString = filter_input( INPUT_SERVER, 'QUERY_STRING' );
if ( ! empty( $queryString ) ) {
adblade_proxy( 'web.adblade.com', sprintf( '/impsc.php?%s=1&%s', ADBLADE_URL_PARAM, $queryString ), true );
} else {
adblade_log( 'Missing query string' );
}
break;
case $options['redirect_actions']['static']:
case $archivedOptions['redirect_actions']['static']:
// fix "zone" in CSS URL
$zoneReplacement = $options['replacements']['/zone/'];
$fixedPath = preg_replace( "/$zoneReplacement/", 'zone', $path );
adblade_proxy( 'static-cdn.adblade.com', $fixedPath );
break;
case $options['redirect_actions']['click']:
case $archivedOptions['redirect_actions']['click']:
wp_redirect( sprintf( 'http://web.adblade.com/clicks.php?%s=1&%s', ADBLADE_URL_PARAM, $path ) );
exit();
default:
adblade_log( 'No redirect action found for ' . $query );
};
exit();
}
}
}
add_action( 'parse_request', 'adblade_parse_request' );
/**
* Add shortcode for Adblade ads.
* e.g.[adblade container_id="####-##########"]
* @param array $atts - The short code attribures.
* @return An ad tag
*/
function adblade_shortcode( $atts ) {
$a = shortcode_atts(
array(
'container_id' => '',
'host' => 'web.adblade.com',
'protocol' => 'https',
'type' => 2,
'width' => 1,
'height' => 1,
),
$atts
);
// Do nothing if no container id was set.
if ( empty( $a['container_id'] ) ) {
return '';
}
return sprintf(
'',
$a['container_id'], $a['host'], $a['protocol'], $a['width'], $a['height'], $a['type'], $a['protocol'], $a['host']
);
}
add_shortcode( 'adblade', 'adblade_shortcode' );
/**
* Replace "[AdsWithin] with a specified ad tag
* @param array $atts - The short code attribures.
* @return The replacement text
*/
function adblade_ads_within_shortcode( $atts ) {
$options = get_option( ADBLADE_OPTIONS_KEY );
if ( array_key_exists( 'adsWithinTag', $options ) && ! empty( $options['adsWithinTag'] ) ) {
return $options['adsWithinTag'];
}
return '';
}
add_shortcode( 'AdsWithin', 'adblade_ads_within_shortcode' );
/**
* Filter posts so we can add tags before and after the content.
* @param string $content The content of the post.
* @return filtered content
*/
function adblade_content_filter( $content ) {
if ( ! is_single() ) {
return $content;
}
$options = get_option( ADBLADE_OPTIONS_KEY );
$beforeTag = '';
$afterTag = '';
if ( array_key_exists( 'beforePostTag', $options ) && ! empty( $options['beforePostTag'] ) ) {
$beforeTag = stripslashes( $options['beforePostTag'] );
}
if ( array_key_exists( 'afterPostTag', $options ) && ! empty( $options['afterPostTag'] ) ) {
$afterTag = stripslashes( $options['afterPostTag'] );
}
return $beforeTag . $content . $afterTag;
}
add_filter( 'the_content', 'adblade_content_filter' );
/**
* Add scripts to page.
*/
function adblade_enqueue_scripts() {
if ( do_adblade_bypass() ) {
$options = get_option( ADBLADE_OPTIONS_KEY );
// we only want to do this if the query_var was successfully made.
if ( array_key_exists( 'query_var', $options ) ) {
// These should not be added until after jQuery load.
wp_enqueue_script( 'blockadblock', '/?' . $options['query_var'] . '=' . $options['redirect_actions']['blockadblock'], array( 'jquery' ), null, true );
wp_enqueue_script( 'log-ab', '/?' . $options['query_var'] . '=' . $options['redirect_actions']['logab'], array( 'blockadblock', 'jquery' ), null, true );
}
}
}
add_action( 'wp_enqueue_scripts', 'adblade_enqueue_scripts' );
/**
* Make requests to the adblade servers.
* @param string $host The host the request is going to.
* @param string $path The path of the URL.
* @param boolean $skipCache Whether or not we should skip the cache.
*/
function adblade_proxy( $host, $path, $skipCache = false ) {
// Make sure it is an adblade domain.
$validDomains = array(
'web.adblade.com',
'web.industrybrains.com',
'static.adblade.com',
'static-cdn.adblade.com',
'staticd.cdn.adblade.com',
'static.industrybrains.com',
'staticd.cdn.industrybrains.com',
);
if ( ! in_array( $host, $validDomains ) ) {
adblade_log( $host . ' is not valid' );
return;
}
// Make sure the request matches one we are familiar with.
$requestMatch = false;
$validRequestPatterns = array(
'#^/?banners/images/\d+x\d+/.*\.[a-z]{3,4}$#',
'#^/?css/.*css$#',
'#^/?impsc?.php#',
'#^/?js/ads/async/show.js$#',
);
foreach ( $validRequestPatterns as $pattern ) {
if ( preg_match( $pattern, $path ) ) {
$requestMatch = true;
break;
}
}
if ( ! $requestMatch ) {
adblade_log( $path . ' is not valid' );
return;
}
$url = sprintf( 'http://%s%s', $host, $path );
adblade_log( 'Proxy for ' . $url );
/**
* A callback function to proxy requests.
* @param $url
* @return mixed (array|false) false if there was an error
*/
$proxy = function ( $url ) {
$options = get_option( ADBLADE_OPTIONS_KEY );
$defaultDisclosure = 'Advertisement';
$replacements = array(
'#/?\Qimpsc.php?\E#' => sprintf( '/?%s=%s&', $options['query_var'], $options['redirect_actions']['impsc'] ),
'#\Qhttp\Es?\Q://static-cdn.adblade.com\E#' => sprintf( '/?%s=%s&%spath=', $options['query_var'], $options['redirect_actions']['static'], $options['query_var'] ),
'/\QAds by Adblade\E/' => $defaultDisclosure,
'/\Q_common_dz.css\E/' => sprintf( '/?%s=%s&%spath=/css/zones/_common_dz.css', $options['query_var'], $options['redirect_actions']['static'], $options['query_var'] ),
);
if ( array_key_exists( 'replacements', $options ) ) {
$replacements = array_merge( $replacements, $options['replacements'] );
};
// Make the request.
$startTime = microtime();
$response = wp_remote_get(
$url,
array(
'user-agent' => 'Adblade WordPress Plugin',
'httpversion' => '1.1',
'timeout' => 10,
'headers' => array(
'X-Forwarded-For' => array_key_exists( 'HTTP_X_FORWARDED_FOR', $_SERVER ) ? filter_input( INPUT_SERVER, 'HTTP_X_FORWARDED_FOR' ) : filter_input( INPUT_SERVER, 'REMOTE_ADDR' ),
),
'cookies' => array(
'__tuid' => '6198487235506032324',
),
)
);
adblade_log( sprintf( 'Request to %s took %s seconds', $url, microtime() - $startTime ) );
if ( is_wp_error( $response ) ) {
adblade_log( 'Error: ' . $response->get_error_message() );
header( 'HTTP/1.0 500 Internal Server Error' );
echo $response->get_error_message();
return false;
}
$result = array(
// Replace anything that an ad blocker might not like.
'body' => preg_replace( array_keys( $replacements ), array_values( $replacements ), $response['body'] ),
);
// If one updates the plugin from a version before we did click rewrites, we need to add that option.
if ( ! array_key_exists( 'click', $options['redirect_actions'] ) ) {
$options['redirect_actions']['click'] = bin2hex( openssl_random_pseudo_bytes( 5 ) );
update_option( ADBLADE_OPTIONS_KEY, $options, 'yes' );
}
// this replacement needs a callback, so must be done on its own
$result['body'] = preg_replace_callback(
'#\Qhttp\Es?\Q://web.adblade.com/clicks.php?\E([^"\']+)#',
function( $matches ) {
$options = get_option( ADBLADE_OPTIONS_KEY );
return sprintf( '/?%s=%s&%spath=%s', $options['query_var'], $options['redirect_actions']['click'], $options['query_var'], urlencode( $matches[1] ) );
},
$result['body']
);
$result['headers'] = array();
$headerKeys = array(
'Content-Type',
'Cache-control',
'Etag',
'Expires',
'Last-modified',
'Pragma',
);
foreach ( $headerKeys as $key ) {
$keyLc = strtolower( $key );
if ( isset( $response['headers'][ $keyLc ] ) ) {
$result['headers'][ $key ] = $response['headers'][ $keyLc ];
}
}
return $result;
};
$responseHandler = function ( $response ) {
if ( $response ) {
if ( array_key_exists( 'headers', $response ) ) {
foreach ( $response['headers'] as $header => $value ) {
header( sprintf( '%s: %s', $header, $value ) );
}
}
echo $response['body'];
return;
}
};
if ( $skipCache ) {
$response = $proxy( $url );
$responseHandler( $response );
return;
} else {
// This is a static call, use a cache.
$transientKey = hash( 'crc32b', $url );
$transient = get_transient( $transientKey );
if ( ! $transient ) {
adblade_log( $url . ' is not cached' );
// Get transient and set it.
$response = $proxy( $url );
if ( $response ) {
adblade_log( sprintf( 'caching %s as %s', $url, $transientKey ) );
$options = get_option( ADBLADE_OPTIONS_KEY );
if ( ! array_key_exists( 'transients', $options ) || ! is_array( $options['transients'] ) ) {
$options['transients'] = array();
}
$options['transients'][] = $transientKey;
update_option( ADBLADE_OPTIONS_KEY, $options, 'yes' );
set_transient( $transientKey, $response, HOUR_IN_SECONDS );
}
$responseHandler( $response );
return;
} else {
adblade_log( sprintf( 'using %s cache for %s', $transientKey, $url ) );
$responseHandler($transient);
return;
}
}
}
/**
* Whether or not bypass is enabled.
* @return boolean - True if enabled.
*/
function do_adblade_bypass() {
$options = get_option( ADBLADE_OPTIONS_KEY );
return false !== $options && array_key_exists( 'bypass', $options ) && intval( $options['bypass'] ) === 1;
}
/**
* Log a message if debugging is enabled.
* @param $message - The message to log.
*/
function adblade_log( $message ) {
if ( WP_DEBUG === true ) {
if ( is_array( $message ) || is_object( $message ) ) {
error_log( print_r( $message, true ) );
} else {
error_log( '[ADBLADE] ' . $message );
}
}
}
function adblade_unique_path( array $previous_values, array $current_values, $target ) {
$merged = array();
// merge previous set of randomly generated paths ... to make sure there won't be a conflict
if ( null != $previous_values ) {
$merged = array_merge( $merged, array_values( $previous_values ) );
}
// merge any present-generation random paths, to make sure we aren't going to generate an invalid state
if ( null != $current_values ) {
$merged = array_merge( $merged, array_values( $current_values ) );
}
$merged = array_flip( $merged );
$tries = 20;
while ( $tries > 0 ) {
$tries--;
$random_path = bin2hex( openssl_random_pseudo_bytes( 5 ) );
if ( ! array_key_exists( $random_path, $merged ) ) {
return $random_path;
}
}
// should never get here
adblade_log( 'Unable to generate a unique path for: ' . $target );
}
function get_adblade_path_set( array $option_set ) {
$retval = array();
if ( null != $option_set ) {
if ( array_key_exists( 'query_var', $option_set ) ) {
$retval['query_var'] = $option_set['query_var'];
}
if ( array_key_exists( 'redirect_actions', $option_set ) && null != $option_set['redirect_actions'] && is_array( $option_set['redirect_actions'] ) ) {
$retval = array_merge( $retval, $option_set['redirect_actions'] );
}
}
return $retval;
}