PHP Implementation of Haversine Computation

December 17th, 2011 by Eric Cope

We needed to compute the distance between two points on the Earth using longitude and latitude from Google’s Geocode API service. We use PHP, but there was no reference to a PHP implementation of the Haversine Equation, so I made one. I needed miles, but if you need another unit, just replace $earth_radius with the appropriate value. Enjoy!

public function distance($long_1,$lat_1,$long_2,$lat_2)
{
$earth_radius = 3963.1676; // in miles

$sin_lat   = sin(deg2rad($lat_2  - $lat_1)  / 2.0);
$sin2_lat  = $sin_lat * $sin_lat;

$sin_long  = sin(deg2rad($long_2 - $long_2) / 2.0);
$sin2_long = $sin_long * $sin_long;

$cos_lat_1 = cos($lat_1);
$cos_lat_2 = cos($lat_2);

$sqrt      = sqrt($sin2_lat + ($cos_lat_1 * $cos_lat_2 * $sin2_long));

$distance  = 2.0 * $earth_radius * asin($sqrt);

return $distance;
}
 

Making a Push Notification Server

December 8th, 2011 by Eric Cope

We had a need to test locally an endpoint of a SaaS Push Service. We did not want to rely on the SaaS for testing, so we needed a way to generate an equivalent push locally. This method requires a PECL extension, pecl_http. On a side note, I had to download the PHP source files to my MAMP installation, but that’s another story.

Once pecl_http was installed, it was very easy.


<?php
if(isset($_POST['data'])){
$data = $_POST['data'];
$info = '';
$response = http_post_data('http://localhost/path/to/endpoint', $data,array(0,$info));
echo $response;
}
?>
<html><body>
<form action="#" method="post">
<textarea name="data" rows="10" cols="40"><?php echo stripslashes($_POST['data']); ?></textarea><br />
<input type="submit"></input><br />
</form>
</body></html>

Its as easy as that. You can serialize, json, xml, your data before you send it, then interpret it when you receive it. Of course, be sure to santize your inputs!

 

PHP Exceptions and CodeIgniter

December 8th, 2011 by Eric Cope

I’ve been toying around with PHP’s Exceptions for a number of years now. I never found a clean way to integrate them into my CodeIgniter codebases, until now. I learned about PHP’s SPL Exception library recently as well, so it was a bit of a motivator.

I updated my models and libraries to throw exceptions, rather than my custom error structures. Here is an example model.

class some_model extends CI_Model {
	public function add()
	{
		some_logic();
		if($some_error == TRUE){
			throw new Exception('my exception message',1234);
		}
		more_logic();
		if($some_other_error == TRUE){
			throw new Exception('my 2nd exception message',1234);
		}
		return my_response();
	}
}

Now in my controller, I put:

class MY_Controller extends CI_Controller
{
	public function controller_method()
	{
		$this->load->model('some_model');
		try {
			some_more_logic();
			$expected_response = $this->some_model->add();
			more_logic_assuming_expected_response_is_valid($expected_response);
		} catch (Exception $e) {
			do_behavior_for_exceptions();
		}
	}
}

In my controller method, I wrap the entire controller code in a try/catch loop to catch systematic errors, like database errors, function input validation errors, and other fatal errors. If I have other reasons to throw an exception, then I can add additional try/catch blocks.

Also, because exceptions are classes, you can extend them and perform common logic from within the exception’s constructor when its thrown.

For more information, see the PHP manual, or give us a holler.

 

PHPUnit’s CodeCoverage and CodeIgniter

December 4th, 2011 by Eric Cope

We have not figured out how to integrate PHPUnit well into our projects, especially when CI’s unit test library is so handy. However, I did take the time to try using PHPUnit’s CodeCoverage metric. However, in order to get it to work, I had to blacklist the CI system directory (the application directory is outside the system directory). It took some debugging, but here is how to do that.

To black list a directory:

$filter  = new PHP_CodeCoverage_Filter;
$filter->addDirectoryToBlacklist('/path/to/system');
$filter->addDirectoryToBlacklist('/path/to/app/logs');
$coverage = new PHP_CodeCoverage(null,$filter);

You have to create a new CodeCoverage_Filter object, add the blacklisted directories, then pass that object to the PHP_CodeCoverage constructor.

I still want to determine why I had to blacklist the system directory. But until then, this is good and generating the reports I am looking for.

 

PHP’s Header Function, IIS and FastCGI, and POST variables

June 25th, 2010 by Eric Cope

On a recent project, I was submitting a web form to a page, processing the POST variables, then redirecting to the same page. The server is IIS running in a FastCGI environment. I found that the POST data existed within the PHP environment after the redirect. Here is some test code:

<?php
 ob_start();
 session_start();
 if(isset($_GET['redirect'])){
 var_dump('<pre>get set',array('post' => $_POST,'get' => $_GET,'request' => $_REQUEST),'</pre><br />');
 unset($_POST);
 }
 if(isset($_POST['sub'])){
 var_dump('post set<br />');
 session_write_close();
 header ("Location: ".$_SERVER['SCRIPT_NAME']."?redirect=1");
 exit;
 }
 else {
 var_dump('<pre>get set',array('post' => $_POST,'get' => $_GET,'request' => $_REQUEST),'</pre><br />');
 }
 ob_flush();
?>

If you run this on a typical Apache installation, it will behave as expected, POST data being local to the first request. If you run this code on IIS, it will not. I am not sure if this is an IIS or PHP bug. Either way, I now check for a GET variable, redirect. If it exists, I destroy the POST data. This cost me several hours of my life. I hope it helps you more.