~ overflow ~

Archive for June, 2010

How to abort ajax requests gracefully

by z3n on Jun.28, 2010, under Coding, Tips & Hints

Problem:

Ajax is great, everyone knows, but sometimes for network issues, server slowdowns or simply users issues request fails or keep loading for a long time. How to abort a request or all of them without needing to reload the whole page?

Solution:

First you need to throw all your ajax requests into a array, that way you can use it as api, so you can abort any “slow” requests, in my case i have a complex admin interface which sometimes bugs or get swamped with lots of requests at same time, usually due user related issues, so i added this “cancel” button which clears up all pending ajax requests, making the system more realiable. Before developing it i did a test on how it works, here’s the source:

<?php

// (c) z3n - R1V1@100628 - www.overflow.biz - rodrigo.orph@gmail.com

if (isset($_REQUEST['q'])) {
	header('Content-Type: application/json; charset=utf-8'); // mandatory for jquery compatibility
	if (!isset($_REQUEST['a']))
		sleep(20);
	echo json_encode(array("r" => 1));
	die;
} else {

?>

<html>
	<head>
		<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.4/jquery.min.js" type="text/javascript"></script>
		<script type="text/javascript">
			var _ajax=[];

			function do_dbg(msg) {
				$("#dbg").prepend(msg+"<BR>");
			}

			function do_ajax() {
				do_dbg("do ajax");
				_ajax[_ajax.length] = $.ajax({data:"q=something",success:function(r,s) {
					do_dbg("do ajax reply");
					return;
				}});
			}

			function do_ajax_fast() {
				do_dbg("do ajax_fast");
				_ajax[_ajax.length] = $.ajax({data:"q=something&a=other_thing",success:function(r,s) {
					do_dbg("do ajax fast reply");
					return;
				}});
			}

			function kill_ajax() {
				do_dbg("aborting all ajax");
				for (var i in _ajax)
					_ajax[i].abort();
			}

			$(document).ready(function(){
				$.ajaxSetup({
					url:"<?=$_SERVER['PHP_SELF']?>",
					global:true,
					type:"POST",
					dataType:'json',
					cache:false,
					async:true,
					timeout:12000000,
					scriptCharset:"UTF-8"
				});
			});
		</script>
	</head>
	<body>
		<input type="button" onClick="do_ajax();" value="do ajax">
		<input type="button" onClick="kill_ajax();" value="kill ajax">
		<input type="button" onClick="do_ajax_fast();" value="do ajax fast">

		<BR><BR>

		<span id="dbg"></span>
	</body>
</html>
<?php

}

?>

Have fun!

Leave a Comment :, , more...

CSS Packer Reloaded

by z3n on Jun.21, 2010, under Coding, Tips & Hints

Sometime ago i posted a simple css packer which basically wipes out the whitespaces,  new lines and so on. The javascript packer was also included. Although none of those were 100% my creations i’ve improved the way it works by adding a couple of things:

- Caching based on timestamp on files (aka automatic cache expiry on update)

- Packing multiple files into a single one (ex. if you have 100s of jquery extensions you don’t need to pack them individually, packing everything into a single file is faster and smaller)

- Flexible layout for packing IE specific files

Source:

function css_specifics($fn) {
	global $_GET;
	if (isset($_GET['q'])) {
		return str_replace(".css",".".trim(str_replace(array("..","/"),"",$_GET['q'])).".css",$fn);
	} else {
		return $fn;
	}
}

base_defines(array(
	"css_packed" => _is_sadm ? "packed-adm.css" : "packed.css",												// css worked file output
	"css_include_path" => "css/",																											// css base include path
	"css_cache_path" => "css/cache/",																									// css cache path
	"css_compression" => -1,																													// css compression method, -1 = disabled
	"css_copyright" => "/* (c) z3n - www.overflow.biz - rodrigo.orph@gmail.com */\n\n", 	// css copyright notice, will appear on packed verisons
	"css_debug" => 0,
	"css_gzip" => 1
));

$css="";
$_use_cache=0;
$css_packed=css_specifics(css_packed);

$l=(file_exists(css_cache_path.$css_packed)) ? filemtime(css_cache_path.$css_packed) : 0;

if (isset($css_includes) && (!empty($css_includes))) {
	if ($l > 0) { // check last mod first
		$_use_cache=1;
		if (css_debug)
			echo "collected includes: ".var_export($css_includes,true)."\n";
		foreach ($css_includes as $v) {
			$fn=_fn_fix($v{0} == "/" || strpos($v,":\\") !== false || $v{0} == "\\" ? $v : css_include_path.$v);
			if (css_debug)
				echo "checking lastmod for: ".$v."\n";
			if (foo((substr($v,0,5) == "http:") ?
					getlastmod($fn)
				:
					filemtime($fn)
			) > $l) {
				$_use_cache=0;
				break;
			}
		}
	}

	if (!$_use_cache) { // re/pack
		if (css_debug)
			echo "building new cache\n";
		// load all js into one
		foreach ($css_includes as $v)
			$css.=substr($v,0,5) == "http:" ?
					file_get_contents($v)."\n"
				:
					_fs($v{0} == "/" || strpos($v,":\\") !== false || $v{0} == "\\" ? $v : css_include_path.$v)."\n"
			;

		// @Packager.RemoveLine -> nothing

		if (css_debug)
			echo "replacing..\n";
		// perform basic replaces
		$css=str_replace(array(
				"##SITE_FULL_URI##"
			),array(
				site_full_uri
		),$css);

		// compress
		switch (css_compression) {
			case "0": // css tidy - http://csstidy.sourceforge.net/
				require_once("classes/csstidy/class.csstidy.php");

				$x=new csstidy();
				$x->set_cfg('preserve_css',true);
				$x->set_cfg('remove_last_;',true);
				$x->set_cfg('merge_selectors',1);
				$x->set_cfg('optimise_shorthands',1);
				$x->set_cfg('silent',true);
				$x->set_cfg('compress_colors',true);
				$x->set_cfg('sort_selectors',false);
				$x->set_cfg('sort_properties',false);
				$x->set_cfg('discard_invalid_properties',false);
				$x->set_cfg('timestamp',false);
				$x->load_template("highest_compression");

				$x->parse(strip_comments($css));
				$css=$x->print->plain();

				break;
			case "1": // minify - http://www.lateralcode.com/css-minifier/
				$css = preg_replace( '#\s+#', ' ', $css );
				$css = preg_replace( '#/\*.*?\*/#s', '', $css );
				$css = str_replace( '; ', ';', $css );
				$css = str_replace( ': ', ':', $css );
				$css = str_replace( ' {', '{', $css );
				$css = str_replace( '{ ', '{', $css );
				$css = str_replace( ', ', ',', $css );
				$css = str_replace( '} ', '}', $css );
				$css = str_replace( ';}', '}', $css );
				break;
			default: // no compression/invalid
				// nothing!
				break;
		}

		$css=css_copyright.$css; // add copyright notice

		if (css_debug)
			echo "writing cache..\n";

		_fw(css_cache_path.$css_packed,$css,"w"); // save cache
	} else { // use cache
		if (css_debug)
			echo "loading from cache\n";
		$css=_fs(css_cache_path.$css_packed);
	}

	if (css_debug)
		echo "output\n - - - \n".$css;

	_opt_headers(gmdate(_dt_lm,filemtime(css_cache_path.$css_packed))." GMT"); // check/send 304

	header('Content-Type: text/css');

	if (css_gzip) // compress
		ob_start("ob_gzhandler");

	print $css; // final output
}

die;

Usage:

Configure files to be added by:

$css_includes=array(
    "file1.css",
    "file2.css",
    "fileN.css",
    "http://www.remote.com/style.css"
);

Do the link by:

<link rel="stylesheet" href="/lib/css.php" type="text/css">
<!--[if IE]><link rel="stylesheet" href="/lib/css.php?q=ie" type="text/css"><![endif]-->

Assuming you have the source into /lib/css.php and, on this case, you have an exception for all IEs.

Notes:

css_include_path = source of css (uncompressed, commented)
css_cache_path = path to save the compressed css
css_compression = method of compression , -1 no compression , 0 = css tidy, 1 = minify
css_debug = enables step by step debug
css_gzip = forces php to output as gzip

Required:

CSS Tidy

You may also need some functions of my framework, i will post them when i compile a decent common file.

Leave a Comment :, , , more...

jQuery validator special highlights for radio and checkbox

by z3n on Jun.17, 2010, under Coding, Tips & Hints

Problem:

Highlighting a checkbox or radio button on error with jquery’s validator plugin is not a good idea, specially if you’re adding borders , backgrounds or something like, since it’s NOT supported over all browsers. I have a little bar around them that goes red if something is wrong, however, it’s not possible to add it if there’s many elements, so it’s better add a wrapper element and style it, in my case i added an element which ID is the same of input NAME, a little change on the plugin make things automatic.

Solution:

		highlight: function( element, errorClass, validClass ) {
			$(element).addClass(errorClass).removeClass(validClass);
			if (($(element).attr("type") == "radio" || $(element).attr("type") == "checkbox") && $("#"+$(element).attr("name")).length > 0)
				$("#"+$(element).attr("name")).addClass(errorClass).removeClass(validClass);
		},
		unhighlight: function( element, errorClass, validClass ) {
			$(element).removeClass(errorClass).addClass(validClass);
			if (($(element).attr("type") == "radio" || $(element).attr("type") == "checkbox") && $("#"+$(element).attr("name")).length > 0)
				$("#"+$(element).attr("name")).removeClass(errorClass).addClass(validClass);
		}
Leave a Comment :, , , , more...

Dynamic width / height jQuery tools overlay content

by z3n on Jun.17, 2010, under Coding, Tips & Hints

Problem:

I have a form where user sends a image and, if needed, he will select an area of the image for cropping. Everything is loaded by AJAX and image size is dynamic, nothing wrong with Jcrop but overlay is not able to work right if there’s no width set the div floats at wrong position.

The setup of the form is quite complex (uploadify + jQuery tools overlay + Jcrop + AJAX), so it was complicated isolating the issue.

Solution:

By adding a image height / width reply to the ajax after image upload, setting the overlay container css width with it and reloading the overlay call fixed the issue.
Here’s a snippet:

				$("#crop_container").css({
					height:"auto",
					width: r.w+"px"
				}).overlay({
					speed: 500,
					fixed:false,
					closeOnClick: false,
					closeOnEsc: false,
					oneInstance: true,
					mask: {
						color: '#fff',
						opacity: 0.5
					}
				});

				$("#crop_container > span").html("<img height="+r.h+" width="+r.w+" src='"+img+"?"+Math.random()+"' id='crop_img'>");
1 Comment :, , , more...

Botnet ddos and mail server hammering

by z3n on Jun.05, 2010, under Coding, Linux Happyness

Problem:
So i noticed a real slow down on my server recently, nothing new was installed, no new sites launched. Investigating it a little further i saw like +100 sendmail processes running in background, WTF!

Solution:

Looking at huge maillogs, i found that there’s a botnet hammering my mail server, trying to authenticate with random strings and send unauthenticated emails, as if my server were configured as a promiscuous email server.

So, i had to put in practice my never used before iptables config skills.

First i added a rule to avoid global hammering:

-N SMTP-BLOCK
-A SMTP-BLOCK -s 127.0.0.1 -j ACCEPT
-A SMTP-BLOCK -s ##YOUR_SERVER_IPS## -j ACCEPT
-A SMTP-BLOCK -m limit --limit 1/m --limit-burst 3 -j LOG --log-level notice --log-prefix "iptables SMTP-BLOCK "
-A SMTP-BLOCK -m recent --name SMTPBLOCK --set -j DROP
-A INPUT -p tcp --dport 25 -m state --state NEW -m recent --name SMTPBLOCK --rcheck --seconds 360 -j SMTP-BLOCK
-A INPUT -p tcp --dport 25 -m state --state NEW -m recent --name SMTP --set
-A INPUT -p tcp --dport 25 -m state --state NEW -m recent --name SMTP --rcheck --seconds 60 --hitcount 10 -j SMTP-BLOCK
-A INPUT -p tcp --dport 25 -m state --state NEW -j ACCEPT

This will avoid hammering on port 25, SMTP, make sure you add your server’s ip here, otherwise it might slowdown your own server from sending emails out. This will ban users for 60 seconds if they send more than 3 packets a minute on port 25, pretty much enough what you need to do.

Now the bot net will still hammering, since they have MANY different ips , 800 so far, they can still hammering and eating up your server resources and bandwidth, since they will not stop i wrote a script to analyze maillogs and ban by ip:

// (c) z3n - R1V1@100605 - www.overflow.biz - rodrigo.orph@gmail.com

if (!isset($argv[2])) die("Usage: ".$_SERVER['PHP_SELF']." <input file> <ip tables>");

function _gii($s,$s_1,$s_2,$st=1) { // what, start string, end string, strip tags bool
	if ((stripos($s,$s_1) !== false) && (stripos($s,$s_2) !== false)) {
		$p=strlen($s_1)+stripos($s,$s_1);
		return ($st == 0) ? substr($s,$p,stripos($s,$s_2,$p)-$p) : strip_tags(substr($s,$p,stripos($s,$s_2,$p)-$p));
	} else {
		return "";
	}
}
function _r($x) { echo $x."\n"; }

$ips=array();
$handle=fopen($argv[1],"r");
while (!feof($handle)) {
	$buf=fgets($handle,4096);
	$x=explode("\n",$buf);
	foreach ($x as $v) {
		if (strpos($v,"Relaying denied") !== false) {
			$ip=_gii($v," [","]",0);
			if (!in_array($ip,$ips))
				$ips[]=$ip;
		}
	}
}

for ($r="",$i=0,$j=count($ips),_r("Found: ".$j." entries, building ban list..."),$ip_tables=file_get_contents($argv[2]);$i < $j;$i++)
	if (strpos($ips[$i],$ip_tables) === false)
		$r.="-A INPUT -s ".$ips[$i]." -j REJECT\n";

if (!empty($r)) {
	file_put_contents("maillog.ban",$r);
	_r("Wrote maillog.ban");
} else {
	_r("No new entries found");
}

..not so good on preg, but it works :P
once you generated the maillog.ban file just paste it on the iptables.

Besides that you may want to tune up your MTA child limit in order to avoid server overloading.

You may also want to keep this:

-A INPUT -p tcp -m tcp --syn -m limit -m state --limit 1/second --limit-burst 5 --state NEW -j ACCEPT
-A INPUT -p tcp -m tcp --syn -m state --state NEW -j REJECT

on for a while, it will ban ips based on their sync packet usage, let’s say that our unhappy script kiddie who owns the botnet starts to ping the server instead, this will avoid server from having resources wasted, but may also cause issues with legit clients.

I also found this article that shows how to disable ping echoing straight on kernel just by adding net.ipv4.icmp_echo_ignore_all = 1 at /etc/sysctl.conf.

Leave a Comment :, , , , , , , more...

Looking for something?

Use the form below to search the site:

Still not finding what you're looking for? Drop a comment on a post or contact us so we can take care of it!