Archive for the ‘PHP’ category

Cloaking and Faking the Referrer

November 23rd, 2009

Cloaking the Referrer

This portion is the more useful portion out of the two if you are trying to drive traffic from a site that is not exactly ‘kosher’ (ie: blackhat). You’ll need a whitehat domain and landing page to make this method effective.

For this article I wrote a simple php script, it may take a second to wrap your head around. I’m not using short tags here because as of PHP 5.3 they are no longer supported by default.

At the very least there is three components to Cloaking the referrer:

  • The Blackhat Domain
  • The Whitehat Domain
  • The ‘Fake’ Landing Page

The first part is simply direct linking from the blackhat domain to the whitehat one.

The second part is the PHP code below, for my example I’m treating it as the base file on the domain (index.php) which will start the redirect process when the blackhat domain is detected as the referrer.

<?php
/* Grabs the querystring, referer, and initialized some variables */
$pg = (isset($_SERVER['QUERY_STRING']))?$_SERVER['QUERY_STRING']:'';
$rf = (isset($_SERVER['HTTP_REFERER']))?$_SERVER['HTTP_REFERER']:'';
$meta=$js=$ie=$lp="";
 
/* Setup your sites here, blackhat, whitehat and advertiser */
$bh = "http://blackhat.kbeezie.com/";
$wh = "http://whitehat.kbeezie.com/";
$ad = "http://advertiser.kbeezie.com/";
 
/* if the referrer is the blackhat domain start a meta redirect
and assign a temporary cookie for 5 seconds */
if(substr($rf, 0, strlen($bh)) == $bh) { 
	/* appends querystring to wh destination */
	$meta = $wh.'?'.$pg; 
	setcookie("r", "1", time()+5); 
}
/* The first meta refresh has completed, and 
we're checking for the 'r' cookie, if set
set a meta refresh back to the domain and set
a new 'rr' cookie while killing the old 'r' one. */
elseif(isset($_COOKIE['r'])) {
	$meta = $wh."?".$pg; 
	setcookie("r", "", time()-5); 
	setcookie("rr", "1", time()+5);
}
/* If we're back to the base of the domain, and the 'rr' cookie is set
then we need to prepare for the final redirect to the advertiser
using javascript */
elseif(isset($_COOKIE['rr']))
{
	if (isset($_SERVER['HTTP_USER_AGENT']) && (strpos($_SERVER['HTTP_USER_AGENT'], 'MSIE') !== false))
	{
		$js = "document.forms[0].submit();";
		$ie = true; 
	} else {
		$js = 'window.location = "'.$ad.'?'.$pg.'";';
	}
	setcookie("rr", "", time()-5);
}
 
/* It is much faster to send meta data via the HTTP headers
its also a good way to hide the meta data from the HTML 
source itself */
header("Content-Type: text/html; charset=UTF-8");
if($meta != "") header("refresh: 0;url=".$meta);
if(($meta == "") && ($js == "")) $lp = true;
echo '<?xml version="1.0" encoding="UTF-8"?>'; 
?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en-US">
	<head profile="http://gmpg.org/xfn/11">
		<title>Whitehat Domain</title>
		<script type="text/javascript" defer="defer">
		<!--
			<?php echo $js; ?>
		//-->
		</script>
	</head>
	<body>
		<?php if($lp === true)
			//Redirect to your lander, or load it here.
			echo "<b>There would be a landing page here if the destination owner attempted to visit the referral url.</b>";
		?>
		<?php if($ie === true) { ?>
			<form action="<?=$ad.'?'.$pg?>" method="get"></form>
		<? } ?>
		&nbsp;
	</body>
</html>

Some Explanations

You’ll notice the first two redirects are to blank out the referrer using a Double Meta Refresh (DMR). Course with Firefox and Internet Explorer using a quick meta refresh already blanks out the referrer by the time the second page loads, as such why cookies are being used. Safari appears to keep the previous page as the referrer during each zero second refresh, but that configuration wasn’t compatible with all three browsers.

After the DMR has completed, we want to refresh via Javascript. Safari and Firefox will carry the referrer over from the whitehat domain when the window.location method is used, but Internet Explorer will instead blank the referrer. Because of this, we have to resort to using a form submission to force the referrer to be sent.

The result of the above script will cause the advertiser to see http://whitehat.kbeezie.com as the referrer instead of http://blackhat.kbeezie.com. Also any attempt of the advertiser to visit the referring URL will result in the landing page loading, instead of a redirection.

On the next page I’ll show you how to fake a referrer, even if you don’t own that domain.

WordPress Automatic Update with SSH

November 22nd, 2009

If you’re like me, you don’t even want the insecure FTP protocol running on your server, but by default wordpress doesn’t even give you the option of using SSH to automatically upgrade your plugins, or wordpress itself.

I’m using a barebone CentOS server for this site, running on the Nginx webserver. I do not have a FTP server installed, and would very much prefer not to have one. Right now the only way to get into the server is via SSH. Below is a working configuration added to the wp-config.php file.

define('FS_METHOD', 'direct'); // 'ssh' is also an option, but did not work for my setup
define('FTP_BASE', '/opt/local/nginx/html/domain.com/');
define('FTP_CONTENT_DIR', '/opt/local/nginx/html/domain.com/wp-content/');
define('FTP_PLUGIN_DIR ', '/opt/local/nginx/html/domain.com/wp-content/plugins/');
define('FTP_PUBKEY', '/home/username/.ssh/id_rsa.pub');
define('FTP_PRIKEY', '/home/username/.ssh/id_rsa');
define('FTP_USER', 'username');
define('FTP_HOST', 'your-domain.com:22');

You can generate a public/private key by executing the following:

$ ssh-keygen

It will ask you where you wish to save the key (the default path usually /home/username/.ssh/id_rsa should be fine), followed by a passphrase which you can just leave blank for this purpose, then the location of the public key which is fine at its default location (usually /home/username/.ssh/id_rsa.pub)

You’ll also want to create an authorized key file by copying the public key into authorized_keys. We also need to make sure to set the proper permissions.

$ cd ~/.ssh
$ cp id_rsa.pub authorized_keys
$ cd ~/
$ chmod 755 .ssh
$ chmod 644 .ssh/*

By using the key pair shown in the configuration above you only have to supply the SSH username, otherwise if you don’t want to use key pairs, you can instead provide your SSH password with the following line:

define('FTP_PASS', 'password');

Make sure that the folders where updates (such as plugins) will need to be performed are writable by wordpress. From there when you click “upgrade automatically” it should just simply happen.

Handling wildcard subdomains with PHP

November 5th, 2009

Subdomains can be a very handy way to make your urls more friendly looking. They can also be incredibly useful for membership driven websites to allow members to have their own custom subdomain. But how do make manage dynamic subdomains with PHP?

There is two parts to making dynamic subdomains work in this case. The first is updating your DNS and webserver to expect wildcard requests. On the DNS side its a simple matter of adding * as an ‘A’ record, or cname pointing to the primary domain or IP. In most cases if you are using shared hosting, you’ll need to contact your hosting provider to enable wildcard DNS on your account. Otherwise if you are on a dedicated server or virtual private server, this can be most likely handled by yourself, such as editing the DNS zone in WHM.

Once you have enabled wildcard DNS, you’ll need to configure your webserver to expect a *.domain.com request. Otherwise it will ignore all requests other than the base domain and pre-defined subdomains.

In Nginx simply modify the server_name directive:

server_name yourdomain.com *.yourdomain.com;

In Apache you would add a ServerAlias directive to the appropriate virtual host entry.

ServerAlias *.yourdomain.com

On most Cpanel driven servers the http.conf file for Apache can be found in /usr/local/apache/conf.

Once you have configured both the name server and web server for wildcard requests you can now use php to not only detect the provide subdomain, but also generate them. The code below will obtain the subdomain being visited.

$sub = str_replace(".yourdomain.com", "", $_SERVER["HTTP_HOST"]);

The above will simply take the hostname stored in the HTTP_HOST enviroment variable, and attempt to replace the base domain with nothing (if no subdomain was provided all that remains is the base domain).

Once the subdomain is determined, you can filter out requests either with an if/then block or in a switch/case statement. In the event of using memeber names as subdomains you can use a switch statement to make sure that the subdomain doesn’t match the homepage (www / yourdomain.com) or a reserved page name such as register.yourdomain.com and assume anything else must be a member name. With that information you can pull the members information from a file or database.

Using PHP to handle the subdomain is certainly easier for most novice as opposed to modifying an htaccess to do rewrite rules passing the subdomain off as a query (which takes more resources than str_replace) or having to modify the webservers configuration file, especially if you do not have direct access to the webserver’s configuration file or do not have override permission.

If your current hosting provider does not support wildcard subdomain, and you are running a memeber based site, consider upgrading to a Virtual Private Server or use a shared hosting provider such as HostGator that allows you to turn on such capability via a support ticket.

Scraping Google Front Page Results

August 25th, 2009

In this article I’ll show you how you can use cURL and simple_html_dom functionality to scrap the basic content from the front page results of google provided with a search query.

What you will need:

The Code

<?
include('simple_html_dom.php');
 
function strip_tags_content($text, $tags = '', $invert = FALSE) {
	/*
	This function removes all html tags and the contents within them
	unlike strip_tags which only removes the tags themselves.
	*/
	//removes <br> often found in google result text, which is not handled below
	$text = str_ireplace('<br>', '', $text);
 
	preg_match_all('/<(.+?)[\s]*\/?[\s]*>/si', trim($tags), $tags);
	$tags = array_unique($tags[1]);
 
	if(is_array($tags) AND count($tags) > 0) {
		//if invert is false, it will remove all tags except those passed a
		if($invert == FALSE) {
			return preg_replace('@<(?!(?:'. implode('|', $tags) .')\b)(\w+)\b.*?>.*?</\1>@si', '', $text);
		//if invert is true, it will remove only the tags passed to this function
		} else {
			return preg_replace('@<('. implode('|', $tags) .')\b.*?>.*?</\1>@si', '', $text);
		}
	//if no tags were passed to this function, simply remove all the tags
	} elseif($invert == FALSE) {
		return preg_replace('@<(\w+)\b.*?>.*?</\1>@si', '', $text);
	}
 
	return $text;
}
 
function file_get_contents_curl($url) {
	/*
	This is a file_get_contents replacement function using cURL
	One slight difference is that it uses your browser's idenity
	as it's own when contacting google. 
	*/
	$ch = curl_init();
 
	curl_setopt($ch, CURLOPT_USERAGENT,	$_SERVER['HTTP_USER_AGENT']);
	curl_setopt($ch, CURLOPT_HEADER, 0);
	curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
	curl_setopt($ch, CURLOPT_URL, $url);
 
	$data = curl_exec($ch);
	curl_close($ch);
 
	return $data;
}
 
//Set query if any passed
$q = isset($_GET['q'])?urlencode(str_replace(' ', '+', $_GET['q'])):'none';
 
//Obtain the first page html with the formated url
$data = file_get_contents_curl('http://www.google.com/search?hl=en&q='.$q);
 
/*
create a simple_html_dom object from the retreived string
you could also perform file_get_html("http://...") instead of
file_get_contents_curl above, but it wouldn't change the default
User-Agent
*/
 
$html = str_get_html($data);
 
 
$result = array();
 
foreach($html->find('li.g') as $g)
{
	/*
	each search results are in a list item with a class name 'g'
	we are seperating each of the elements within, into an array
 
	Titles are stored within <h3><a...>{title}</a></h3>
	Links are in the href of the anchor contained in the <h3>...</h3>
	Summaries are stored in a div with a classname of 's'
	*/
 
	$h3 = $g->find('h3.r', 0);
	$s = $g->find('div.s', 0);
	$a = $h3->find('a', 0);
	$result[] = array('title' => strip_tags($a->innertext), 
		'link' => $a->href, 
		'description' => strip_tags_content($s->innertext));
}
 
if($_GET['serialize'] == '1')
{
	/* 
	if you pass serialize=1 to the script
	it will echo out a serialized string
	which can be unserialized back to an 
	array on a receiving script
	*/
	echo serialize($result);
}
else
{
	/* 
	Otherwise it prints out the array structure so that it
	is more human readible. You could instead perform a 
	foreach loop on the variable $result so that you can 
	organize the html output, or insert the data into a database
	*/
	echo "<textarea style='width: 1024px; height: 600px;'>";
	print_r($result);
	echo "</textarea>";
}
//Cleans up the memory 
$html->clear(); exit();
?>

The variable ‘q’ passed to the file will provide the query string. If you pass serialize=1 to the script, the output will be a serialized string which can be converted back to an array with the PHP function unserialize.

Keep in mind that hitting google too often for search results from the same server might eventually get your server blocked from accessing, especially if you all multiple queries in a short period of time.

An example of the output when the word ‘funny’ is searched.

Array
(
    [0] => Array
        (
            [title] => Funny Videos, Funny Pictures, Funny Jokes, Funny News - Funny.com
            [link] => http://www.funny.com/
            [description] =>  videos,  pictures,  jokes,  news.
        )
 
    [1] => Array
        (
            [title] => Lolcats 'n' Funny Pictures of Cats – I Can Has Cheezburger?
            [link] => http://icanhascheezburger.com/
            [description] => Aug 25, 2009  Humorous captioned pictures of felines and other animals. 
            Visitors can submit their own material or add captions to a large archive of 
        )
 
    [2] => Array
        (
            [title] => Funny Videos, Funny Pictures, Flash Games, Jokes
            [link] => http://www.ebaumsworld.com/
            [description] =>  videos, flash games, clean jokes, clean humor, hilarious flash,  pics , 
            office humor, prank phone calls, flash cartoons,  animation, 
        )
 
    [3] => Array
        (
            [title] => Video results for funny
            [link] => http://video.google.com/videosearch?hl=en&q=funny&um=1&ie=UTF-8&ei=TW2USrSHIIK0NriQwPoH&sa=X
            &oi=video_result_group&ct=title&resnum=4
            [description] => CollegeHumor's recent videos section has all the best  videos on the Internet. 
            There are  video clips, hilarious viral videos,  college 
        )
 
    [4] => Array
        (
            [title] => Funny Videos on CollegeHumor. Watch funny videos and comedy movie ...
            [link] => http://www.collegehumor.com/videos
            [description] => CollegeHumor's recent videos section has all the best  videos on the Internet. 
            There are  video clips, hilarious viral videos,  college 
        )
 
    [5] => Array
        (
            [title] => Funnyjunk - Funny Pictures and Funny Videos
            [link] => http://www.funnyjunk.com/
            [description] =>  pictures,  videos, flash games and  movies.
        )
 
    [6] => Array
        (
            [title] => Photobucket | funny Pictures, funny Images, funny Photos
            [link] => http://photobucket.com/images/funny/
            [description] => View 462373  Pictures,  Images,  Photos on Photobucket. Share them with 
            your friends on MySpace or upload your own!
        )
 
    [7] => Array
        (
            [title] => FAIL Blog: Pictures and Videos of Owned, Pwnd and Fail Moments
            [link] => http://failblog.org/
            [description] =>  FAIL Pictures and Videos. Home Send In The Fail Boat Vote [Random]. You must 
            be logged in to add favorites | Register for a new account 
        )
 
    [8] => Array
        (
            [title] => funny
            [link] => http://www.reddit.com/r/funny/
            [description] => . (147376 subscribers). a community for 1 year. moderators · Submit a link. to 
            anything interesting: news article, blog entry, video, picture. 
        )
 
    [9] => Array
        (
            [title] => News results for funny
            [link] => http://news.google.com/news?hl=en&q=funny&um=1&ie=UTF-8&ei=TW2USrSHIIK0NriQwPoH&sa=X
            &oi=news_group&ct=title&resnum=11
            [description] => "A more mature but still  Judd Apatow comedy whose move into serious 
            human relation issues nearly scuttles the third act. 
        )
 
)

Four free Geolocation Methods

August 22nd, 2009

Geolocation or Geo-Targeting is a method of identifying a visitor’s location in the world. You can use this information for anything as simple as greeting a visitor in their native language to automatically redirecting visitors to valid affiliate offers for the visiting demographic. This article takes a look at four different services that offer geolocation for free. This article will focus primarily on retrieving the visitor’s country code.

Maxmind GeoLite Country

Touting a 99.5% data accuracy is the GeoLite Country database allowing you to lookup a visitor’s country locally on your server. The database file is updated at the first of each month. The benefit with a local binary database is that lookups are performed right at the server and as a result may be faster and easier to cache than hitting a remote server you have no control over. However performing a large number of queries maybe cause some strain on your server if you have a cheaper machine or use shared hosting.

The easiest way to use the GeoLite country database is to download the binary format along with the geoip.inc file from the Maxmind PHP API. Once the GeoIP.dat and geoip.inc files are uploaded onto the server, the following PHP code will retrieve the visitor’s country code.

include("geoip.inc");
$gi = geoip_open("GeoIP.dat",GEOIP_STANDARD);
$addr = $_SERVER["REMOTE_ADDR"];
$country_code = geoip_country_code_by_addr($gi, $addr);	
geoip_close($gi);

Other APIs include C, Perl, Javascript, Python, C#, Ruby and Java examples, as well as an Apache Module and Microsoft COM Objects.

GeoPlugin

One of the more flexible remote service is GeoPlugin.com. This one provides the most information from a single line PHP code, but requires a connection to the geoplugin.com server for every request (I recommend caching or using cookies for repeat visitors).

PHP Example:

$fetch = unserialize(fetch_url('http://www.geoplugin.net/php.gp?ip='.$_SERVER['REMOTE_ADDR']));
$geo_code = $fetch['geoplugin_countryCode'];

You can also easily grab the city name using the ‘geoplugin_city’ key in the returned array. Other options supported are Javascript, JSON and XML .

HostIP.info

HostIP.info offers the simplest way to retreive a country code for a given IP address.

$geo_code = trim(fetch_url("http://api.hostip.info/country.php?ip=".$_SERVER['REMOTE_ADDR']));

ipinfodb.com
While not as straight forward as HostIP or GeoPlugin, IpInfoDB.com provides a backup server in the event the first request fails.

$fetch = fetch_url("http://www.ipinfodb.com/ip_query_country.php?ip=".$_SERVER['REMOTE_ADDR']."&output=xml");
if(!$fetch)
	$fetch = fetch_url("http://backup.ipinfodb.com/ip_query.php?ip=".$_SERVER['REMOTE_ADDR']."&output=xml");
 
$fetchb = new SimpleXMLElement($fetch);
if (!$fetchb) 
	$geo_code = "";
else
	$geo_code = $fetchb->CountryCode;

There you have it, four different geolocation services, depending on your needs some may perform better than others, for high traffic sites the Maxmind solution is likely the best one short of paying for a monthly service.

Paypal IPN with PhP

August 19th, 2009

If you’re a freelance coder you most likely have a PayPal account. One of the most useful feature provided by PayPal for anyone looking to automate their ordering process is the Instant Payment Notification. This guide will show you how to utilize IPN with a PayPal ‘Buy Now’ button and PHP. Additional tips to further secure your ordering process are also discussed.

What is IPN?

In a nutshell IPN is PayPal method of instantly notifying your server of a payment. This can either be setup globally for all transactions on your account, or can be provided for a specific button or subscription.

Merchant Services

The IPN Process:

  1. Paypal sends details of the transaction to your server at the provided url.
  2. Your script compiles the information provided and sends it to Paypal’s verification server.
  3. Paypal’s server will either verify the information as valid, or will reject it as invalid.
  4. If considered a valid transaction, process the information as needed, otherwise discard and ignore.

Creating a Payment Button

Once logged into PayPal you should direct your attention to the Merchant Service.

The “Buy Now Button” will be sufficient for a one-time-purchase of an electronic or tangible product. The button can be setup as a simple buy now button for a single purchase with no options, or can be setup with drop down for product choices or other options. Either way there is two key settings you will want to use when creating your button.

Secure Merchant ID

Select Secure Merchant ID as means of identifying the account as opposed to an email address. This will not only help prevent automated spam attempts but will also help prevent fake transactions (more on that later).

IPN LocationYou will also need to add the following line to the advanced option. The url will be the destination notified in the event of a payment or related transaction. Normally you don’t want to call it something as obvious as ipn.php in the root of your site, rather bury the script in a folder and give it some other name such as txn1.php.



Tracking OptionIf you have multiple options that you will want to verify in your IPN script you can get PayPal to send you the specific Item ID by turning on the tracking option for the button:

Once you have created your button and generated the code to be used on the site you will want to setup your IPN script to save the necessary transactions.