Perishable Press

Just a heads up to anyone else getting the occasional PayPal phishing spam.. Usually it’s pretty easy to spot one of those crafty phishing emails, just hover over any links before clicking to view the real URL in the status bar. You know, the link says something like, “click here to restore your PayPal account,” but you know that’s garbage and could easily prove it by checking the actual link URL, which is usually something completely bonkers, like:

http://luqomu-qiry.freewebportal.com/puvermiqer.html

Yeh right, stuff like that isn’t even close to PayPal.com or Chase.com or any other authentic website. There are a million ways to identify these sorts of phishing scams, including:

  • you don’t do business with that particular company
  • the email just looks weird (poor graphics/design)
  • email is poorly written (grammar, syntax, tone, etc.)
  • anything that sounds too urgent or important
  • they don’t address you by name, but request some specific account action
  • Disguised links (links go to phishing site)

That last one is a fast, easy way to discredit even the most well-crafted phishing spam. Here are some examples showing the obviousness of most phishing emails — notice how hovering over links reveals the true URL in the status bar:

[ PayPal Phishing Spam Email ]

[ PayPal Phishing Spam Email ]

Obviously “http://qan-ajidyt.virtue.nu/hsdadria.html” does not equal PayPal.com, so dismissing this kind of garbage is a no-brainer. But watch out, because the little bastards are getting sneakier about how they craft their phishing links. For example, this email rolled in the other day and hovering over the link almost fooled me:

[ PayPal Phishing Spam Email ]

..and here is another that arrived recently:

[ PayPal Phishing Spam Email ]

Look at that — it says “paypal.com” right there at the beginning of the URL, so it must be legit, right? So instead of clicking the link that I think might be real, I copy/pasted into a plain text file to examine further..

Here is what a typical legitimate PayPal URL looks like:

https://www.paypal.com/us/cgi-bin/webscr?cmd=_flow&SESSION=MpHa_hHUj321dZnjFYN4xbFElxhCr0_HYlLwhbFkxWKE6uq9GjK3dpwe&dispatch=38ebb9cf0857de5aa44fd01837204ea000ee2a3114de1a3b2f88683c1178a267c59c90680d

And here is the disguised URL from the phishing email:

http://paypal.com.us.cgi-bin.ebscr.cmd.home.general.dispatch.0db1f38432c9462fe7313791b4c12e10393700.viemzaza.com/sas/cgi-bin/ias/A/1/FGT/ibd/IAS/presentation/pm_token=C2886KJEHD89483JSO3829ENDHU8392OJD/

As you can see, they are strikingly similar, with the main difference that periods/dots are used in place of forward slashes. With a carefully constructed series of subdomains, the phishing link looks like it goes to somewhere at PayPal.com, but the real domain is viemzaza.com, using the following subdomain structure:

paypal.com.us.cgi-bin.ebscr.cmd.home.general.dispatch.0db1f38432c9462fe7313791b4c12e10393700

I’m guessing more than a few people fall for this sneakier tactic, so hopefully this post will help raise awareness. Keep a close eye on those URLs and assume every business/bank/account/whatever email is bogus until proven otherwise.

More..

Here are more examples of phishing emails. And for reference, here are screenshots from the phishing emails that sparked this post:

© 2012 Perishable Press

Read more: http://perishablepress.com/paypal-phishing-spam/

[ 5G ] The 5G Blacklist helps reduce the number of malicious URL requests that hit your website. It’s one of many ways to improve the security of your site and protect against evil exploits, bad requests, and other nefarious garbage.

After extensive beta testing, the 5G Blacklist/Firewall is solid and ready to help secure sites hosted on Apache servers. In addition to beta testing for the 5G, this is the 5th major update of my “G”-series blacklists. Here is a quick overview of its evolution:

  1. Ultimate htaccess Blacklist (Compressed Version)
  2. 2G Blacklist: Closing the Door on Malicious Attacks
  3. Perishable Press 3G Blacklist
  4. The Perishable Press 4G Blacklist
  5. 5G Firewall (Beta)

Along the way, I’ve explored a wide variety of different blacklist techniques. The 5G is the culmination of all these efforts, and will eventually be replaced by the imminent 6G Blacklist/Firewall.

What it does

The 5G Blacklist is a simple, flexible blacklist that checks all URI requests against a series of carefully constructed HTAccess directives. This happens quietly behind the scenes at the server level, saving resources for stuff like PHP and MySQL for all blocked requests.

How it works

Blacklists can block just about any part of a request: IP, user agent, request string, query string, referrer, and everything in between. But IP addresses change constantly, and user agents and referrers are easily spoofed. As discussed, request strings yield the best results: greater protection with fewer false positives.

The 5G works beautifully with WordPress, and should help any site conserve bandwidth and server resources while protecting against malicious activity.

How to use

To install the 5G Firewall, append the following code to your site’s root .htaccess:

# 5G BLACKLIST/FIREWALL
# @ http://perishablepress.com/5g-blacklist/

# 5G:[QUERY STRINGS]
<IfModule mod_rewrite.c>
 RewriteEngine On
 RewriteBase /
 RewriteCond %{QUERY_STRING} (environ|localhost|mosconfig|scanner) [NC,OR]
 RewriteCond %{QUERY_STRING} (menu|mod|path|tag)\=\.?/? [NC,OR]
 RewriteCond %{QUERY_STRING} boot\.ini  [NC,OR]
 RewriteCond %{QUERY_STRING} echo.*kae  [NC,OR]
 RewriteCond %{QUERY_STRING} etc/passwd [NC,OR]
 RewriteCond %{QUERY_STRING} \=\\%27$   [NC,OR]
 RewriteCond %{QUERY_STRING} \=\\\'$    [NC,OR]
 RewriteCond %{QUERY_STRING} \.\./      [NC,OR]
 RewriteCond %{QUERY_STRING} \?         [NC,OR]
 RewriteCond %{QUERY_STRING} \:         [NC,OR]
 RewriteCond %{QUERY_STRING} \[         [NC,OR]
 RewriteCond %{QUERY_STRING} \]         [NC]
 RewriteRule .* - [F]
</IfModule>

# 5G:[USER AGENTS]
<IfModule mod_setenvif.c>
 SetEnvIfNoCase User-Agent ^$ keep_out
 SetEnvIfNoCase User-Agent (casper|cmsworldmap|diavol|dotbot)   keep_out
 SetEnvIfNoCase User-Agent (flicky|ia_archiver|jakarta|kmccrew) keep_out
 SetEnvIfNoCase User-Agent (libwww|planetwork|pycurl|skygrid)   keep_out
 SetEnvIfNoCase User-Agent (purebot|comodo|feedfinder|turnit)   keep_out
 SetEnvIfNoCase User-Agent (zmeu|nutch|vikspider|binlar|sucker) keep_out
 <Limit GET POST PUT>
  Order Allow,Deny
  Allow from all
  Deny from env=keep_out
 </Limit>
</IfModule>

# 5G:[REQUEST STRINGS]
<IfModule mod_alias.c>
 RedirectMatch 403 (https?|ftp|php)\://
 RedirectMatch 403 /(cgi|https?|ima|ucp)/
 RedirectMatch 403 /(Permanent|Better)$
 RedirectMatch 403 (\=\\\'|\=\\%27|/\\\'/?|\)\.css\()$
 RedirectMatch 403 (\,|//|\)\+|/\,/|\{0\}|\(/\(|\.\.\.|\+\+\+|\||\\\"\\\")
 RedirectMatch 403 \.(cgi|asp|aspx|cfg|dll|exe|jsp|mdb|sql|ini|rar)$
 RedirectMatch 403 /(contac|fpw|install|pingserver|register)\.php$
 RedirectMatch 403 (base64|crossdomain|localhost|wwwroot|e107\_)
 RedirectMatch 403 (eval\(|\_vti\_|\(null\)|echo.*kae|config\.xml)
 RedirectMatch 403 \.well\-known/host\-meta
 RedirectMatch 403 /function\.array\-rand
 RedirectMatch 403 \)\;\$\(this\)\.html\(
 RedirectMatch 403 proc/self/environ
 RedirectMatch 403 msnbot\.htm\)\.\_
 RedirectMatch 403 /ref\.outcontrol
 RedirectMatch 403 com\_cropimage
 RedirectMatch 403 indonesia\.htm
 RedirectMatch 403 \{\$itemURL\}
 RedirectMatch 403 function\(\)
 RedirectMatch 403 labels\.rdf
 RedirectMatch 403 /playing.php
 RedirectMatch 403 muieblackcat
</IfModule>

# 5G:[BAD IPS]
<Limit GET POST PUT>
 Order Allow,Deny
 Allow from all
 # uncomment/edit/repeat next line to block IPs
 # Deny from 123.456.789
</Limit>

That’s the golden ticket right there. The 5G Firewall is serious protection for your website: extensively tested, plug-n-play, and completely free. “Grab, gulp, n go” as they say. For more information, see the beta article (and comments).

Troubleshooting

Remember, test thoroughly. If something stops working when the 5G is installed, try removing the 5G. If things start working normally again, you can either pass on the 5G or investigate further. Investigating further is straightforward using something like the halving method, where you remove chunks of the 5G until isolating and identifying the issue. Here is a quick example:

  • I’ve installed the 5G, thanks Jeff.
  • Uh-oh, the page at http://example.com/indonesia.html stopped loading
  • Hmm, the URL contains the phrase “indonesia”, so let’s check the 5G for it
  • Yep, there’s a rule that blocks indonesia\.htm
  • Removing that line resolves the issue, thanks me.

Is it okay to remove rules that are blocking your own pages? Yes, the only downside is that malicious requests that would have otherwise been blocked will now get through. The 5G will continue to block a massive volume of malicious requests — it’ll just be a bit less effective. The protective effect is cumulative, not dependent on any one rule. So customization is encouraged. Once you dial it in, you’re all set.

Disclaimer

The 5G Firewall is provided “as-is”, with the intention of helping site administrators protect their sites against bad requests and other malicious activity. The code is open and free to use and modify as long as the first two credit lines remain intact. By using this code you assume all risk & responsibility for anything that happens, whether good or bad. In short, use wisely, test thoroughly, don’t sue me.

Learn more..

To learn more about the theory and development of the 5G Firewall, check out my articles on building the 3G, 4G and 5G Blacklist. A search for “blacklist” in the sidebar should also yield many results.

Happy securing!

© 2012 Perishable Press

Read more: http://perishablepress.com/5g-blacklist-2012/

Things have been busy! I’m working on a new book and site and having a blast. I’ll share more on that later, but for now I just want to get back into posting at Perishable Press. To kick it into gear, here is one of the jQuery snippets I’m using at the new book site.

jQuery Hover Swap Text

There is probably a better way to do this, but I needed a way to swap link text with the title attribute on hover. Nothing fancy, and I thought for sure there would be an easier/existing way of doing this with jQuery, but didn’t see anything so came up with this lil’ snippet:

// jQuery hover swap text @ http://perishablepress.com/jquery-hover-swap-text/ 
function xycss_swap_text(){
	$('a').hover(function(){
		var title = $(this).attr('title');
		var text  = $(this).text();
		$(this).text(title).attr('rel', text).removeAttr('title').wrapInner('<span />');

	},function(){
		var title = $(this).text();
		var text  = $(this).attr('rel');
		$(this).text(text).attr('title', title);
	});
}
$(document).ready(function(){
	xycss_swap_text();
});

Just drop into your JavaScript file and edit the $('a') selector with your choice. Going thru, this is just a jQuery hover function that swaps the contents of the title attribute with the anchor text. I also wrap the hover text with a <span> (for styling purposes), but you can yank that out of there if it’s not needed.

Update:

Bryan Watson extends this snippet into more of a plugin format:

(function($){

    // Swap text with title attribute
    $.fn.swapTitleAttr = function() {
    
        var title = this.attr('title');
        var text  = this.text(); 
        
        $(this).wrapInner('<span />');
        
        $(this).hover(function(){
            $(this).text(title).attr('rel', text).removeAttr('title');
        },function(){
            $(this).text(text).attr('title', title).removeAttr('rel');
        });
    };
    
})(jQuery);

$(document).ready(function(){
    $('a').swapTitleAttr();
});

As Bryan explains, with this version “the vars are outside of the hover function (and don’t need to be redefined). Plus, it makes the function reusable for any selector with a title attribute.”

Better way?

Drop some hints if you know an easier way of doing this — I’m sure there’s a better way :)

© 2011 Perishable Press

Read more: http://perishablepress.com/jquery-hover-swap-text/

By design the 5G Blacklist works on Apache servers, but thanks to Scott Stawarz, here is a version for Microsoft IIS:

<?xml version="1.0" encoding="UTF-8"?>
<configuration>
  <system.webServer>
    <rewrite>
      <rules>
                <clear />
                <rule name="Block Bad Query String" stopProcessing="true">
                    <match url=".*" ignoreCase="false" />
                    <conditions logicalGrouping="MatchAny" trackAllCaptures="false">
                        <add input="{QUERY_STRING}" pattern="(environ|localhost|mosconfig|scanner)" />
                        <add input="{QUERY_STRING}" pattern="(menu|mod|path|tag)\=\.?/?" />
                        <add input="{QUERY_STRING}" pattern="boot\.ini" />
                        <add input="{QUERY_STRING}" pattern="echo.*kae" />
                        <add input="{QUERY_STRING}" pattern="etc/passwd" />
                        <add input="{QUERY_STRING}" pattern="\=\\%27$" />
                        <add input="{QUERY_STRING}" pattern="\=\\\'$" />
                        <add input="{QUERY_STRING}" pattern="\.\./" />
                        <add input="{QUERY_STRING}" pattern="\:" />
                        <add input="{QUERY_STRING}" pattern="\[" />
                        <add input="{QUERY_STRING}" pattern="\]" />
                    </conditions>
                    <action type="CustomResponse" statusCode="403" statusReason="Forbidden" statusDescription="Forbidden" />
                </rule>
                <rule name="Block Bad User Agents" stopProcessing="true">
                    <match url=".*" />
                    <conditions logicalGrouping="MatchAny" trackAllCaptures="false">
                        <add input="{HTTP_USER_AGENT}" pattern=" ^$" />
                        <add input="{HTTP_USER_AGENT}" pattern="(casper|cmsworldmap|diavol|dotbot)" />
                        <add input="{HTTP_USER_AGENT}" pattern="(flicky|ia_archiver|jakarta|kmccrew)" />
                        <add input="{HTTP_USER_AGENT}" pattern="(libwww|planetwork|pycurl|skygrid)" />
                    </conditions>
                    <action type="CustomResponse" statusCode="403" statusReason="Forbidden: Access is denied." statusDescription="You do not have permission to view this directory or page using the credentials that you supplied." />
                </rule>
                <rule name="Block Bad Request Strings" stopProcessing="true">
                    <match url=".*" />
                    <conditions logicalGrouping="MatchAny" trackAllCaptures="false">
                        <add input="{URL}" pattern="(https?|ftp|php)\://" />
                        <add input="{URL}" pattern="/(cgi|https?|ima|ucp)/" />
                        <add input="{URL}" pattern="(\=\\\'|\=\\%27|/\\\'/?|\)\.css\()$" />
                        <add input="{URL}" pattern="(\,|//|\)\+|/\,/|\{0\}|\(/\(|\.\.\.|\+\+\+|\|)" />
                        <add input="{URL}" pattern="\.(cgi|asp|aspx|cfg|dll|exe|jsp|mdb|sql|ini|rar)$" />
                        <add input="{URL}" pattern="/(contac|fpw|install|pingserver|register)\.php" />
                        <add input="{URL}" pattern="(base64|crossdomain|localhost|wwwroot)" />
                        <add input="{URL}" pattern="\.well\-known/host\-meta" />
                        <add input="{URL}" pattern="/function\.array\-rand" />
                        <add input="{URL}" pattern="\)\;\$\(this\)\.html\(" />
                        <add input="{URL}" pattern="proc/self/environ" />
                        <add input="{URL}" pattern="/ref\.outcontrol" />
                        <add input="{URL}" pattern="indonesia\.htm" />
                        <add input="{URL}" pattern="\{\$itemURL\}" />
                        <add input="{URL}" pattern="function\(\)" />
                        <add input="{URL}" pattern="labels\.rdf" />
                    </conditions>
                    <action type="CustomResponse" statusCode="403" statusReason="Forbidden: Access is denied." statusDescription="You do not have permission to view this directory or page using the credentials that you supplied." />
                </rule>
      </rules>
    </rewrite>
  </system.webServer>
</configuration>

Just copy/paste into your web.config file and you should be good to go. I really don’t know much about IIS, but this code looks logical to me and should be entirely plug-n-play, so no editing required. If you discover bugs or have ways of improving the code, please share via comment or directly.

Tested on IIS version 7.5.

Bonus

In his IIS version of 5G, Scott included a couple of bonus rules, one for protecting against hotlinking, and another for WordPress permalinks:

                <rule name="Prevent Image HotLinking">
                    <match url=".*\.(gif|jpg|png)$" />
                    <conditions logicalGrouping="MatchAll" trackAllCaptures="false">
                        <add input="{HTTP_REFERER}" pattern="^$" negate="true" />
                        <add input="{HTTP_REFERER}" pattern="^http(s)?://(.*\.)?your-domain-name-goes-here\.com/.*$" negate="true" />
                    </conditions>
                    <action type="Rewrite" url="/some-random-directory/some-random-file.html" />
                </rule>
                <rule name="wordpress" patternSyntax="Wildcard">
                    <match url="*" />
                    <conditions logicalGrouping="MatchAll" trackAllCaptures="false">
                        <add input="{REQUEST_FILENAME}" matchType="IsFile" negate="true" />
                        <add input="{REQUEST_FILENAME}" matchType="IsDirectory" negate="true" />
                    </conditions>
                    <action type="Rewrite" url="index.php" />
                </rule>

This code is pre-indented for easy copy/paste into the 5G/IIS code.

Huge thanks to Scott for sharing his work with us!

Credit link: Screenflex Room Dividers

© 2011 Perishable Press

Read more: http://perishablepress.com/5g-blacklist-iis/

My current ISP likes to keeps things spicy by changing my IP address every few months or so. There are a million ways to get this changing IP information, but as an obsessive web developer, I like to roll my own whenever possible. That means using my own resources instead of spending time and energy elsewhere.

So the goal for this project is to create a web page that does one thing very well: display the visitor’s current IP information. In this tutorial, we use PHP, HTML, CSS, and JavaScript to roll our own sleek & stylish “What’s my IP” page in 3 easy steps.

“What’s My IP?” Demo

Here is a demo of the “What’s my IP” page we’re building in this tutorial. It’s simple, sleek and stylish, providing the IP address in big, easy type. Plus, you get teh fancy JavaScript toggle for additional IP information, including:

  • Remote Port
  • Request Method
  • Server Protocol
  • Server Host
  • User Agent
  • Proxy Info (when available)

And yeah the IP address too. It’s all done with one file that’s entirely plug-n-play. Worth playing for? Let’s build this thing..

Step 1: PHP/HTML

Gotta say up front that you don’t need to copy/paste any code to roll your own. Just grab the zip file, unzip and upload to your server. There’ll be a few things you want to customize, and the tutorial should provide all the details. That said, let’s begin by creating a blank PHP file named index.php. Add the following PHP/HTML code:

<!DOCTYPE html>
<html><meta http-equiv="Content-Type" content="text/html; charset=utf-8">
	<title>What's my IP dude!</title>
	<body>
		<div id="tools" class="tools">
			<p>Your IP:</p>
		</div>
		<div id="ip-lookup" class="tools">
			<?php if ($_SERVER["HTTP_X_FORWARDED_FOR"] != "") {
				$IP = $_SERVER["HTTP_X_FORWARDED_FOR"];
				$proxy = $_SERVER["REMOTE_ADDR"];
				$host = @gethostbyaddr($_SERVER["HTTP_X_FORWARDED_FOR"]);
			} else {
				$IP = $_SERVER["REMOTE_ADDR"];
				$host = @gethostbyaddr($_SERVER["REMOTE_ADDR"]);
			} ?>
			<h1><?php echo $IP; ?></h1>
		</div>
		<div id="more" class="tools">
			<p><a id="more-link" title="More information" href="javascript:toggle();">More info</a></p>
		</div>
		<div id="more-info" class="tools">
			<ul>
			<?php 
				echo '<li><strong>Remote Port:</strong> <span>'.$_SERVER["REMOTE_PORT"].'</span></li>';
				echo '<li><strong>Request Method:</strong> <span>'.$_SERVER["REQUEST_METHOD"].'</span></li>';
				echo '<li><strong>Server Protocol:</strong> <span>'.$_SERVER["SERVER_PROTOCOL"].'</span></li>';
				echo '<li><strong>Server Host:</strong> <span>'.$host.'</span></li>';
				echo '<li><strong>User Agent:</strong> <span>'.$_SERVER["HTTP_USER_AGENT"].'</span></li>'; 
				if ($proxy) echo '<li><strong>Proxy: <span>'.($proxy) ? $proxy : ''.'</span></li>';

				$time_start = microtime(true);
				usleep(100);
				$time_end = microtime(true);
				$time = $time_end - $time_start;
			?>
			</ul>
			<p><small>It took <?php echo $time; ?> seconds to share this info.</small></p>
		</div>
	</body>
</html>

No edits are required for this step. You may of course customize things however you want. The markup is straightforward, and the first chunk of PHP is just collecting the various server variables for later use. After this, we echo the IP address to the browser and continue with a toggle link for additional IP information.

The last slice of PHP generates a pseudo value for the amount of time to run the script. This of course isn’t required for the “What’s my IP” page to work, so feel free to remove it and change or remove the last paragraph to something else, like maybe the current date & time:

<p><small><?php echo date('l jS \of F Y h:i:s A'); ?></small></p>

It’s all up to you – consider this tutorial as just a starting point for further customization. Remember: PHP is PHun! ;)

Now let’s add some style..

Step 2: CSS (w/ encoded image)

The previous PHP/HTML code works great, but looks pretty boring without any CSS, so let’s add some fresh styles for sort of an edgy, minimal look. Here again is a demo showing how it looks with the CSS. Notice the obligatory drop-shadows on various text and box elements, and the crazy-looking base64-encoded background-image. This code should be placed above the <body> tag in the index.php file:

<style type="text/css">
	* { margin:0; padding:0; }
	body { background:#333; color:#efefef; margin-top:50px; }
	.tools { margin:25px auto; width:960px; }
	.tools p {
		margin-left:20px; color:#777; font-family: Georgia,serif;
		-webkit-text-shadow:0 0 7px #000; -moz-text-shadow:0 0 7px #000; text-shadow:0 0 7px #000;
		}
	#ip-lookup { 
		border:1px solid #aaa; 
		background-position:50% 50%; background-repeat:repeat-x; background-color:#777;
		background-image: url(data:image/gif;base64,R0lGODlhAQBWAfcAAHZ2dkVFRXJyck1NTVFRUUVEREpKSnR0dEhISEZGRklJSW1tbVNTU1ZWVnV1dW9vb2lpaUdHR2dnZ2tra0xMTFpaWlBQUFRUVF9fX1VVVFlZWWRkZGBgYEtLS2FhYU5OTl1dXVVVVW5ubnZ1dmpqakZGR2tsbGZmZmJiYnZ1dWNjY0xNTVpbWmxsbFtbW0ZFRkZFRVJSUnBwb15eXlhYWWVlZVdXV05PT09PT1JTUm5vbnNzc3Nyc3BwcHFxcXFwcGppamhoaFhYWF5fXnJxcWhpaWJiY0hISVRUU25tbXV1dmNkY25vb3Rzc1NUU0xLTG1ubnR1dUhHSHV0dGNkZEhHR19eXk5OTXd3dlxdXVdXWHR1dFFRUFxcXU9PUFxbXFdWVlxcXHFxcGFhYmNjYlxdXFhYV3Bvb21sbGNjZGVlZmZmZUxNTFlZWF5dXnBxcFxcW3V2dnR0c1tcW2BfX2JhYlBQUVZXV2hnaFBPT3BxcUhJSElISG5ubXJzc2tqanJzcmZmZ0lKSlhXV1JSUXd2dkdGR2VkZFBQT0tMS2loaGJjY2ZnZmxtbEtLTExMS0lISVtbWkVFRkdGRmRlZGdnaHFxclxbW1FSUUpLSklJSkdHSF9gX2FgYFtaW09OTmtrak9QT1lZWnN0dF5dXVJSU0RFRXN0c2VmZUtMTHNzdGtsa1VVVkRERHd3dwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACH5BAAAAAAALAAAAAABAFYBAAj/AF0JHEiQYCFXABJiSQhgxIg4KUakUOKgYhQHU7Yc2LhxlJxTTVTt2MGDhwA/gASoVGmJiA+Xen6I+fGmRw8ZMs482PmAiQ4dIoJC6ZNkgdEFjdC0aGGi6aoJUCeA+kOCBBCrECAU0QpBUZAgeCpJGCvhBKNAJ9ScWIOqRg1KGw5t2EAljYolKsgYWWQEBYo6KMZ4GNyJg2E6nDAoHmJlyIwZbkCQApEFRJkuYb64gHNpjotInliwqEBalAYNbTTQoCFEiJlBWmzYuAOmge0GrELozsD7gm8GSJwwYJCDeKkYMQgRIIBpOQEuFuxYQGQhj5dQOD7dwHHjg/crA8IPUFgxng2F848cpXqSqIN7AwYywTcgSIF9TfYhIdhzBAEfBFIgUAUCm0RgoCElRFBCAiVMksCDLyQQwAswBACDJAEUEEAApmRYwIethChiiAEBADs=);

		-webkit-border-radius:11px; -moz-border-radius:11px; border-radius:11px; 
		-webkit-box-shadow:0 0 11px #111; -moz-box-shadow:0 0 11px #111; box-shadow:0 0 11px #111;
		}
	#tools p { font-size:77px; }
	#more p  { font-size:24px; }
	#more-info p { font-size:18px; }
	#more-info ul { margin:20px 0 35px 50px; font-size:18px; color:#ccc; }
	#more-info li { margin:10px 0; line-height:25px; font-family:Helvetica, Arial; }
	h1 { 
		font: 124px/1 Helvetica, Arial; text-align:center; margin:50px 0; color:#efefef;
		-webkit-text-shadow:0 0 7px #333; -moz-text-shadow:0 0 7px #333; text-shadow:0 0 7px #333;
		}
	h1 a:link { color:#efefef; }
	a:link,a:visited { 
		color:#777; text-decoration:none; outline:0 none; 
		-webkit-text-shadow:0 0 7px #000; -moz-text-shadow:0 0 7px #000; text-shadow:0 0 7px #000;
		}
	a:hover,a:active { color:#eee; text-decoration:underline; outline:0 none; }
	li span { 
		font:16px/1 Monaco,"Panic Sans","Lucida Console","Courier New",Courier,monospace,sans-serif; color:#ccc; 
		-webkit-text-shadow:0 0 3px #777; -moz-text-shadow:0 0 3px #777; text-shadow:0 0 3px #777;
		}
</style>

This fancy slice of CSS code folding is placed inline with the PHP/markup to reduce the number of HTTP requests to optimize performance and keep things simple. Likewise, using the base-64 encoded image eliminates another HTTP request.

After adding the CSS, it’s time to finish it off with some JavaScript..

Step 3: JavaScript

The main thing we want to do with the JavaScript is toggle the extra IP information. We hide it by default, and then toggle it open/closed with a “more info” link. Hiding all the gory server data keeps things clean, simple, and focused on the IP address. Then if the user wants to know more, “click” – there it is. This chunk of JavaScript should be placed above the closing </body> tag in the index.php file:

<script type="text/javascript">
	function hideStuff(){
		if (document.getElementById){
			var x = document.getElementById('more-info');
			x.style.display="none";
		}
	}
	function toggle(){
		if (document.getElementById){
			var x = document.getElementById('more-info');      
			var y = document.getElementById('more-link');      
			if (x.style.display == "none"){
				x.style.display = "";
				y.innerHTML = "Less info";
			} else {
				x.style.display = "none";
				y.innerHTML = "More info";
			}
		}
	}
	window.onload = hideStuff;
</script>

No edits required – just copy/paste your way to done. Why didn’t I use a simpler jQuery toggle instead of regular JavaScript? As with the other code samples, we’re optimizing performance by eliminating unnecessary HTTP requests and keeping things simple. Including the entire jQuery library just for a simple toggle event is overkill in my opinion. This slab of JavaScript may not be the most elegant, but it works. Please share if you know a better toggle method :)

Putting it all together

At this point, we’ve got one file named index.php. In this file, we’ve placed the following code:

  • (Step 1) PHP/HTML
  • (Step 2) CSS
  • (Step 3) JavaScript

Save the file, upload to the server, and visit in your web browser. Everything should be working great. If not, let me know in the comments. Alternately, you can skip the code pasting and just download the complete file..

Download the file

Grab a copy, unzip and upload to your server. Should work fine out of the box, but really is meant as a starting point for further customization and experimentation. Have fun!!

What’s my IP – DOWNLOAD ZIP FILE (4K)

© 2011 Perishable Press

Read more: http://perishablepress.com/roll-your-own-whats-my-ip/

More Articles...

Page 1 of 21

Start
Prev
1