mongodb geospatial query example in php with distance radius in miles and km

Recently for a project involving 311 reports in New York city, I had to find a speedy way to query over 3 million records within a certain radius of a latitude longitude point. Mysql is slow for this sort of thing, so I decided to try the data set out with Solr. Solr worked great and was quite responsive, but required a massive amount of RAM on our server to hold the entire dataset. This was “ok” for our current dataset, but what would happen when we started to expand beyond NYC? or if we kept adding on new 311 reports from NYC as they come in over time? Solr was not scaleable. Mongodb to the rescue!

I wrote a simple import script in PHP to pull in the data we had already imported into mysql into mongodb. The only special part of the data mirgation was the creation of a “lnglat” field in each imported document array which is a “2d index” in mongo. You have to set a multivalued field with the lat/lng values cast as floats in the document array, like this:

$doc['lnglat'] = array('lng'=>(float)$row['lng'],'lat'=>(float)$row['lat']);

After the data has been imported to mongo, you create the 2d index on that multivalued field using the mongo command line, with this command:

my_mongodb.my_collection.ensureIndex( { lnglat : "2d" } )

Once I had the data in mongo, I had a hard time finding good examples of Geospatial queries for mongodb in php. I finally found this page:
http://comments.gmane.org/gmane.comp.db.mongodb.user/48789
which solved all my problems and pointed out that when querying mongo with a lat/lng point as an array, mongodb expects the lng to be first, not the lat. Durrrr…

Anyway, here is the code snippit that I pulled from the url above which was the first comprehensible example I found of php code for geospatial queries in with a distance radius specified:

public function getRadiusMiles($lng, $lat, $radius = 3) {
	$radiusOfEarth = 3956; //avg radius of earth in miles
	$cursor = $this->collection->find(
		array('lnglat' =>
			array('$within' =>
				array('$centerSphere' =>
					array(
						array(floatval($lng), floatval($lat)), $radius/$radiusOfEarth
					)
				)
			)
		)
	);
	$resultset = $this->jsonCursor($cursor);
	return json_encode($resultset);
}
 
public function getRadiusKm($lng, $lat, $radius = 5) {
	$radiusOfEarth = 6378.1; //avg radius of earth in km
	$cursor = $this->collection->find(
		array('lnglat' =>
			array('$within' =>
				array('$centerSphere' =>
					array(
						array(floatval($lng), floatval($lat)), $radius/$radiusOfEarth
					)
				)
			)
		)
	);
 
	$resultset = $this->jsonCursor($cursor);
	return json_encode($resultset);
}

Hopefully this saves someone some time!

mysqldump 5.1.36 unable to successfully dump a MySQL database in UTF-8 character encoding issues

Today I had a character encoding problem when importing some data from a mysqldump from a contractor we had hired to do some work.  Everything about the dump was fine, the database, tables, and fields were all using utf8_unicode_ci utf8 collation, the dump file was encoded in utf8, and the database I was importing to was all utf8 as well.  The contractor said he was able to re-import the dump into his server and local environment fine, but I was still unable to get the dump imported without all the utf8 characters getting garbled.  As it turns out, his mysql and mysqldump versions were older than mine and it was messing everything up.  Apparently, according to this mysql bug post:

http://bugs.mysql.com/bug.php?id=28969

“As of today (Feb 6, 2012) mysqldump 5.1.36 still exhibits the faulty behavior (unable to successfully dump a MySQL database in UTF-8)”.  We were able to fix this issue by following these steps:

  1. add latin1 default character set to the mysql dump command from the older versioned database, like so:
    mysqldump -u dbuser -p --default-character-set=latin1 my_database_name > db_dump.sql

    You can also try adding a “-r” flag to this command which should allow non-latin characters to dump properly as well, but this did not work in our case.

  2. before importing into the newer version database, open the in the newly created dump file and change the line that reads:
    /*!40101 SET NAMES latin1 */;

    to:

    /*!40101 SET NAMES utf8 */;

    then save the file

  3. import to the newer version database using:
    mysql -u dbuser -p --default-character-set=utf8 my_database_name < db_dump.sql

Took a lot of emails back and forth to finally come to this solution.  Hopefully this helps some one and thank god for the original bug post linked above!

disable firefox native inspect element context menu

With the latest update of Firefox to version 10.0, they included some new developer tools which are similar to what is available via Firebug or WebKit’s developer tools.  About time!  Unfortunately, I still am so used to firebug that will continue using it instead of these new native development tools.  One thing that really grinds my gears was the native “Inspect Element” context menu item because it lives directly above the Firebug one.  This was extremely frustrating for me because I kept clicking on that instead of the “Inspect with Firebug” menu item.  This would bring up the native inspector console, which I would then have to close, then go back and right click again and make sure I click on the inspect with firebug menu item.  Sigh…..how annoying.

Anyway, there is a simple way to disable the native inspect element context menu item.  In the Firefox address bar, put “about:config” and press Enter.  This will bring up Firefox’s preference configurations.  In the “filter” search box enter “inspector”.  This will bring up three configuration preferences.  Simply double click on the “devtools.inspector.enabled” preference to change it to “false” and viola!  No more native inspect element in the context menu!  Horray.

UPDATE:

A recent update to the firebug extension add’s config preferences for hiding the default inspector (thanks Ilya).  Now when you filter your config preferences by searching for “inspector”, some new firebug config settings appear as well.  Simply set “extensions.firebug.hideDefaultInspector” to “true” in addition to setting “devtools.inspector.enabled” to “false”.

 

Don’t muck around in here too much or you will mess up your firefox configuration.  I hope someone finds this useful =)

php mysql collation change script

There are times when we get stuck with bad collations on our mysql tables and we are overwhelmed by having to change them by hand. Well, I have written a php script which will go through all your tables and fields in a database and update them to the collation which works for you. In my case for this example, I have a database which contains a mix of collations and changes them all to utf8_unicode_ci. This example uses the mysqli object in php as the database connection.

Your will need to update the database connection credentials as they are all bogus in this example. You will also need to change the “$execute_sql” to equal true if you want the script to actually perform the collation change via this script.

<?php
 
	$execute_sql = false;
 
	$host = 'mydbhost';
	$username = 'username';
	$password = 'passsword';
	$dbname = 'databasename';
 
	$db = new mysqli($host, $username, $password, $dbname);
 
	$mysqldatabase = 'databasename';
	$collation = 'CHARACTER SET utf8 COLLATE utf8_unicode_ci';
 
	echo '<div>';
	$db->query("ALTER DATABASE $mysqldatabase $collation");
 
	$result = $db->query("SHOW TABLES");
 
	$count = 0;
	while($row = $result->fetch_assoc()) {
		$table = $row['Tables_in_'.$mysqldatabase];
		if($execute_sql) $db->query("ALTER TABLE $table DEFAULT $collation");
		$result1 = $db->query("SHOW COLUMNS FROM $table");
		$alter = '';
		while($row1 = $result1->fetch_assoc()) {
			if (preg_match('~char|text|enum|set~', $row1["Type"])) {
				if(strpos($row1["Field"], 'uuid')){
					// why does this not work
				}else{
					$alter .= (strlen($alter)?", \n":" ") . "MODIFY `$row1[Field]` $row1[Type] $collation" . ($row1["Null"] ? "" : " NOT NULL") . ($row1["Default"] && $row1["Default"] != "NULL" ? " DEFAULT '$row1[Default]'" : "");
				}
			}
		}
		if(strlen($alter)){
			$sql = "ALTER TABLE $table".$alter.";";
			echo "<div>$sql\n\n</div>";
			if($execute_sql) $db->query($sql);
		}
		$count++;
	}
	echo '</div>';
 
?>

The only gotcha that I have run into with my script that I have yet to solve is that when you change the collation of an existing uuid field which has a foreign key, the copy table fails in mysql. Not that the collation of a uuid field really matters, but you can see a comment in the routine which questions why this does not work.

Anyway, I hope someone finds this useful =) Enjoy…

MySQL alter table to re-order columns

Sometimes because of my completely anal nature, I want the fields that I’ve already added to a table in MySQL to be in a different order. To do this you can simply alter that table column, without changing any of its properties, then adding “AFTER column_3”.

So for instance you had a table like this:

mysql> describe test;
+-----------+---------+------+-----+---------+----------------+
| Field     | Type    | Null | Key | Default | Extra          |
+-----------+---------+------+-----+---------+----------------+
| column_id | int(11) | NO   | PRI | NULL    | auto_increment |
| column_1  | int(11) | NO   |     | NULL    |                |
| column_2  | int(11) | NO   |     | NULL    |                |
| column_3  | int(11) | NO   |     | NULL    |                |
+-----------+---------+------+-----+---------+----------------+
4 rows in set (0.00 sec)

But you really want column_1 to be ordered after column_3 because you are as ridiculous as I am. You can run this query:

ALTER TABLE `test` CHANGE `column_1` `column_1` INT( 11 ) NULL AFTER column_3;

Now your table looks like this:

mysql> describe test;
+-----------+---------+------+-----+---------+----------------+
| Field     | Type    | Null | Key | Default | Extra          |
+-----------+---------+------+-----+---------+----------------+
| column_id | int(11) | NO   | PRI | NULL    | auto_increment |
| column_2  | int(11) | NO   |     | NULL    |                |
| column_3  | int(11) | NO   |     | NULL    |                |
| column_1  | int(11) | YES  |     | NULL    |                |
+-----------+---------+------+-----+---------+----------------+
4 rows in set (0.00 sec)

I find this to be useful for me on larger tables that have grown over time and I want some relevant columns grouped together for when I am viewing data in phpMyAdmin or whatever.

Hope this helps someone =)

CSS3 dual background glow highlight button

I have been working on a new UI at work and decided to go full on with it in HTML5 and CSS3 because its 98% for internal company users who all use a “modern browser” and I don’t have to worry about those pesky IE users. The following code is for a cool looking glow highlight button which involves multiple backgrounds with rgba color. I have included three states: normal, hover, and active.

Enjoy!

 
 
<button id="css3-button" type="button">Cool Arse Button</button>
 
 
<style>
button#css3-button{
	padding: 0.4em 1em 0.4em 1em;
	font-family:Helvetica, Arial, sans-serif;
	font-size:1.1em;
	color: #2885ab;
	letter-spacing:-0.05em;
	text-shadow: 1px 1px 0 rgba(255, 255, 255, 0.4), 0px 0px 6px rgba(0, 0, 0, 0.2);
	font-weight:bold;
	cursor:pointer;
	border:1px solid #FFFFFF;
	-moz-border-radius: 0.7em;
	-webkit-border-radius: 0.7em;
	border-radius: 0.7em;
	background: -moz-linear-gradient(left, rgba(131, 182, 202,  0.8), rgba(131, 182, 202, 0.2) 15%, rgba(131, 182, 202, 0) 50%, rgba(131, 182, 202, 0.2) 85%, rgba(131, 182, 202, 0.8)),
				-moz-linear-gradient(top, #e2f4fb, #b5d4e0 50%, #b5d4e0 50%, #91bfd1);
	background: -webkit-gradient(linear, 0% 0%, 100% 0%, from(rgba(131, 182, 202, 0.8)), to(rgba(131, 182, 202, 0.8)), color-stop(.15, rgba(131, 182, 202, 0.2)), color-stop(.5, rgba(131, 182, 202, 0)), color-stop(.85, rgba(131, 182, 202, 0.2))),
				-webkit-gradient(linear, 0% 0%, 0% 100%, from(#e2f4fb), to(#91bfd1), color-stop(.5, #b5d4e0), color-stop(.5, #b5d4e0));
	-moz-box-shadow: 0px 0px 6px rgba(0, 0, 0, 0.2);
	-webkit-box-shadow: 0px 0px 6px rgba(0, 0, 0, 0.2);
	box-shadow: 0px 0px 6px rgba(0, 0, 0, 0.2);
}
 
button#css3-button:hover{
	color:#01678F;
	background: -moz-linear-gradient(left, rgba(131, 182, 202,  0.8), rgba(131, 182, 202, 0.2) 15%, rgba(131, 182, 202, 0) 50%, rgba(131, 182, 202, 0.2) 85%, rgba(131, 182, 202, 0.8)),
				-moz-linear-gradient(top, #f7f7f7, #e2f4fb 50%, #e2f4fb 50%, #91bfd1);
	background: -webkit-gradient(linear, 0% 0%, 100% 0%, from(rgba(131, 182, 202, 0.8)), to(rgba(131, 182, 202, 0.8)), color-stop(.15, rgba(131, 182, 202, 0.2)), color-stop(.5, rgba(131, 182, 202, 0)), color-stop(.85, rgba(131, 182, 202, 0.2))),
				-webkit-gradient(linear, 0% 0%, 0% 100%, from(#f7f7f7), to(#91bfd1), color-stop(.5, #e2f4fb), color-stop(.5, #e2f4fb));
}
 
button#css3-button:active{
	color:#6EAAC2;
	border-color: #999999 #f1f1f1 #f1f1f1 #aaaaaa;
	background: -moz-linear-gradient(top, #f1f1f1, #dddddd);
	background: -webkit-gradient(linear, left top, left bottom, from(#f1f1f1), to(#dddddd));
}
 
</style>

php imagick complex gradient composite image

Manipulating images with imagemagick for php can be difficult, especially when you are trying to create complex images for a web template. Here is a more complex example of how to create sweet dynamic web graphics. This is a version of a header image that I created for a template design. It involves 4 colors, and adds a nice gradient sheen over the top of the base gradients.

The script first creates an new base image using the background color. Next, the script uses imagickdraw to create some lines and solid rectangles. Then the script creates another image which will fill in a gradient between the top two lines. Now comes the more complicated part, adding the sheen over the image that was just created.

The hard part of this is the fact we need an almost horizontal gradient. This involves creating two vertical gradients, reversing the color directions, then compositing them together. Once they have been combined, we rotate the image just beyond vertical, then set the transparency to 50%.

Now, the script puts the gradient image and sheen image together, and you have a sweet looking header image….

<?
 
$background = "#FFFFFF";
$color1 = '#999999';
$color2 = '#333333';
$color3 = '#CCCCCC';
 
//$cachefile = 'path/to/cachefile.jpg';
//if (!file_exists($cachefile)) {
 
try{
 
	$im = new Imagick();
	$im->newImage( 400, 86, $background, "jpg" );
 
	$draw1 = new ImagickDraw();
	$draw1->setFillColor($color1);
	$draw1->rectangle(0, 0, 400, 3);
	$draw1->setFillColor($color1);
	$draw1->rectangle(0, 73, 400, 86);
 
	$draw1->setFillColor($color1);
	$draw1->line(0, 2, 400, 2);
	$draw1->setFillColor($color3);
	$draw1->line(0, 73, 400, 73);
 
	$gradient1 = new Imagick();
	$gradient1->newPseudoImage(400, 70, "gradient:".$color1."-".$color2);
	$im->compositeImage( $gradient1, imagick::COMPOSITE_OVER, 0, 3 );
 
	$im->drawImage($draw1);
 
 
	$gradient_over1 = new Imagick();
	$gradient_over1->newPseudoImage(400, 200, "gradient:transparent-".$background);
	$gradient_over2 = new Imagick();
	$gradient_over2->newPseudoImage(400, 200, "gradient:".$background."-transparent");
 
	$gradient_over = new Imagick();
	$gradient_over->newImage(400,400,$color2,'png');
	$gradient_over->compositeImage( $gradient_over1, imagick::COMPOSITE_OVER, 0, 0 );
	$gradient_over->compositeImage( $gradient_over2, imagick::COMPOSITE_OVER, 0, 200 );
	$gradient_over->rotateImage('transparent',120);
	$gradient_over->setImageOpacity(.5);
 
	$im->compositeImage($gradient_over, imagick::COMPOSITE_OVER, -100, -200 );	
 
	header( "Content-Type: image/jpg" );
	echo $im;
 
	$im->writeImage($cacheFilepath);
 
	$im->clear();
	$im->destroy();
 
}catch(Exception $e){
	echo 'Error: ',  $e->getMessage(), "";
}
 
/*
}else{
 
	$canvas = new Imagick($cachefile);
	header("Content-Type: image/png");
	echo $canvas;
 
}
*/
 
?>

As usual, I have commented out file caching code. Simply uncomment those lines and put a correct cachefile path (directory must be writable by the server).

simple but useful php base object for mysql table interaction

I started a project creating an online game which involved lots of objects and tables. Rather than rewrite the same code over and over, I decided to create a base object in which i could simple extend the base object to work with any mySQL table by simply listing all the fields.

Here is the code for the base object:

<?
abstract class _base
{
 
	protected $db = null;
	protected $table = '';
	protected $primary_field = '';
	protected $primary_id = -1;
	protected $fields = array();
	protected $values = array();
 
	private $db_info = array(
		'host'=>'localhost',
		'username'=>'',
		'password'=>'',
		'database'=>''
	);
 
	public function __construct($primary_id=-1)
	{
 
		$this->db = $this->db_connect();
 
		if($this->primary_id>0){
			$this->primary_id = $primary_id;
			$this->load($this->primary_id);
		}
 
		return true;
	}
 
	public function load($primary_id=-1)
	{
		if($primary_id>0) $this->primary_id = $primary_id;
 
		if($this->primary_id<0) return false;
 
		$sql = "SELECT * FROM ".$this->table." WHERE ".$this->primary_field."='".intval($this->primary_id)."' LIMIT 1";
		$result = $this->db->query($sql);
		if($this->db->errno) echo '<div class="red b ac">Query Fail ('.$this->db->error.')<br>sql: '.$sql.'</div>';
 
		if($result && $result->num_rows>0){
			$tmp_vals = $result->fetch_assoc();
			$this->values = $tmp_vals;
			foreach($tmp_vals as $k=>$v){
				$this->$k = $v;
			}
			return true;
		}else{
			return false;
		}
	}
 
	public function load_from_array($load_array = array())
	{
		foreach($load_array as $field=>$value){
			$this->$field = $value;
		}
		return true;
	}
 
	public function save()
	{
		$primary_field = $this->primary_field;
 
		$save_new = true;
 
		if($this->$primary_field>0) $save_new = false;
 
		$this->prepare_save();
 
		if($save_new){
 
			$sql = "INSERT INTO ".$this->table;
			$fields = "(".implode(',',array_keys($this->values)).")";
			$values = "('".implode("','",array_values($this->values))."')";
			$sql .= ' '.$fields. ' VALUES '.$values; 
 
		}else{
 
			$sql = "UPDATE ".$this->table." SET ";
			$set = '';
			foreach ($this->values as $k => $v){
				$set.=(strlen($set)?', ':'').$k."='".$v."'";
			}
			$sql .= $set." WHERE ".$primary_field."=".intval($this->primary_id);
		}
 
		$result = $this->db->query($sql);
		if($this->db->errno) echo '<div class="red b ac">Query Fail ('.$this->db->error.')<br>sql: '.$sql.'</div>';
 
		if($result){
 
			if($save_new) $this->$primary_field = $this->db->insert_id;
 
			return true;
		}else{
			return false;
		}
	}
 
	protected function prepare_save()
	{
 
		$this->values = array();
		foreach($this->fields as $field){
			if(isset($this->$field)) $this->values[$field] = $this->db->real_escape_string($this->$field);
		}
		unset($this->values[$this->primary_field]);
	}
 
	protected function set_or_get($key='',$value=null)
	{
		if(!strlen($key)) return false;
 
		if(is_null($value) || (is_string($value) && !strlen($value)) || (is_int($value) && $value < 0)){
			return $this->$key;
		}else{
			$this->$key = $value;
			return true;
		}
	}
 
	public function set($key='',$value=null)
	{
		if(!strlen($key) || is_null($value)) return false;
		if(!in_array($key,$this->fields)) return false;
 
		$this->$key = $value;
 
	}
 
	public function get($key='')
	{
		if(!strlen($key)) return false;
		if(!in_array($key,$this->fields)) return false;
		return $this->$key;
	}
 
	public function object_info()
	{
		$object_info = array();
		$object_info['primary_field'] = $this->primary_field;
		$object_info['table'] = $this->table;
		$object_info['fields'] = $this->fields;
 
		return $object_info;
	}
 
	public function db_connect(){
		$this->db = new mysqli($this->db_info['host'],$this->db_info['username'],$this->db_info['password'],$this->db_info['database']);
		return $this->db;
	}
 
}
?>

To extend the object to use a certain mysql table, you simply set the table name, list the name of the fields, and the primary key. Then you ca access all the values of the mysql table with the variable name of the field names…. here is an example:

class user extends _base
{
	protected $primary_field = 'user_id';
	protected $table = 'users';
	protected $fields = array(
		'user_id ',
		'username',
		'password'
	);
 
	protected $user_id  = -1;
	protected $username  = '';
	protected $password  = '';
 
	public function __construct($user_id=-1)
	{
 
		parent::__construct();
 
		if($user_id>0){
			$this->user_id = $user_id;
			$this->load($user_id);
		}
 
		return true;
	}
 
	public function login($username='', $password='')
	{
		if(!strlen($username) || !strlen($password)) return false;
		$sql = "SELECT user_id FROM users WHERE username='".$this->db->real_escape_string($username)."' AND password='".$this->db->real_escape_string($password)."'";
		$result = $this->db->query($sql);
		if($this->db->errno) echo '<div class="red b ac">Query Fail ('.$this->db->error.')<br>sql: '.$sql.'</div>';
		if($result && $result->num_rows > 0){
			$user_data = $result->fetch_assoc();
			$this->load($user_data['user_id']);
 
			// do user login stuff
 
			return true;
		}else{
			return false;
		}
	}
 
}

php imagick round corner box with dropshadow

In this post I will show you how to create a rounded corner box with a drop shadow. First set your background color, foreground color, and the color of the drop shadow.

Once you’ve set up your colors, the script will create two identical imagick objects, one for the background, and one for the foreground. The background is just a base file where you will composite over the drop shadow image and the foreground rounded rectangle.

First the script creates a rounded rectangle within the bounds of the background image with space enough to not cut off the drop shadow. Once this rectangle is drawn on the second “over” image, the script applies a gaussian blur to the image to create the effect of a drop shadow. Once this is done, the script draws another identical rounded rectangle over the drop shadow, only this time with the foreground color rather than the drop shadow color.

After thats all taken care of, the script composites the drop shadow/round rectangle image over the background image that was created first. And, its done. Uncomment the caching code to write the resulting file to disk.

<?
$background = "#FFFFFF";
$foreground = "#EAEAEA";
$shadow = "#666666";
 
//$cachefile = './path/to/your/cachefile.png';
//if (!file_exists($cachefile)) {
 
	try{
 
		$canvas = new Imagick();
		$canvas->newImage(200, 200, $background, "png" );
 
		$box_over = new Imagick();
		$box_over->newImage(200, 200,  $background, "png" );
 
		$draw = new ImagickDraw();
		$draw->setFillColor($shadow);
		$draw->roundRectangle(10, 10, 190, 190, 10, 10);
 
		$box_over->drawImage($draw);
		$box_over->blurImage(8, 5);
 
		$canvas->compositeImage($box_over, imagick::COMPOSITE_OVER, 0, 0);
 
		$draw = new ImagickDraw();
		$draw->setFillColor($foreground);
		$draw->roundRectangle(10, 10, 190, 190, 10, 10);
 
		$box_over->drawImage($draw);
 
		$canvas->compositeImage($box_over, imagick::COMPOSITE_OVER, 0, 0);
 
		$canvas->setImageFormat('jpeg'); 	
 
		//$canvas->writeImage($cachefile);
 
		header( "Content-Type: image/jpg" );
		echo $canvas;
 
		$canvas->clear();
		$canvas->destroy();
 
 
	}catch(Exception $e){
		echo 'Error: ',  $e->getMessage(), "";
	}
 
/*
}else{
 
	$canvas = new imagick($cachefile);
	header("Content-Type: image/png");
	echo $canvas;
 
}
*/
 
?>

NOTE: the cachefile folder must be writable by the server.

php imagick button with round corners and a bezier curve

This post involves a little more complex example of what imagick can do. I am going to show you how to use the draw object to create an button which has rounded corners and a multi-colored curve accent using the “bezier” function of the ImagickDraw object.

First, lets get things set up. We are using four colors for this example. The border color, the accent color, the bezier curve color, and the font color. The bezier curve color in this example is placed over the accent color at 50% alpha to darken it. If you want a specific color, simply change the fill alpha value to 1 and change the bezier color to whatever you want. Note that this example’s image dimensions (as well as the coordinates of the bezier curve) are specific to the text “go” and the font sizes specified. If you want to change the text, you will have to play with these values to make it look right.

Once you’ve set up your colors, the script creates a new imagick object with background color of what you’ve specified in the “accent” color. The script then creates a new ImagickDraw object for the bezier curve. Next is the array of coordinates for the bezier curve to follow. You can have as many points in the curve as you want, but remember that the last point to have in the array will automatically be connected to the first point by the ImagickDraw object. You’ll notice that this script ends it’s curve well outside the x bounds of the image, but the y portion of the coordinate is at 0. This is done so when the draw object connects the first and last points, its at the top of the image and not cutting through the middle of the image making it look wacky.

The rest of the script is fairly straight forward. It continues adding to the draw object by setting the alpha value of the fill color to 1 for the text it’s about to write on the image. Then it draws the bezier curve and the text to the first canvas it set up. It then rounds the edges of the canvas to get the rounded corner effect.

The last step of the script is to create the border, or in this example, a rounded corner fill image that is slightly larger than the canvas the script just created with the text and the bezier curve. Once the corners are rounded on this new canvas, the script composites the first image on top of the second. And its done. The resulting image is outputted to the browser. Uncomment the caching code if you wish to write the resulting image to the server.

<?
 
$border = "#000000";
$accent = "#1365B1";
$bezier = "#000000";
$fontcolor = "#FFFFFF";
$text = "go";
 
$fontfile = "/path/to/your/fontfile.ttf";
 
//$cachefile = './path/to/your/cachefile.png';
//if (!file_exists($cachefile)) {
 
 
	try{
 
		$canvas = new Imagick();
		$canvas->newImage(30, 24, $accent, "png");
 
		$draw = new ImagickDraw();
 
		$draw->setFillColor($bezier);
		$draw->setFillAlpha(.5);
		$draw->bezier(
			array(
				 array("x" => 0, "y" => 0),
				 array("x" => 5, "y" => 8),
				 array("x" => 10, "y" => 11),
				 array("x" => 15, "y" => 15),
				 array("x" => 23, "y" => 18),
				 array("x" => 35, "y" => 30),
				 array("x" => 55, "y" => 0)
			 )
		);
 
		$draw->setFillAlpha(1);
		$canvas->drawImage($draw);
		$draw->setFontSize(16);
		$draw->setFillColor($fontcolor);
		$draw->setFont($fontfile);
		$canvas->annotateImage($draw, 7, 16, 0, $text);
		$canvas->roundCorners(2,2);
 
		$canvas2 = new Imagick();
		$canvas2->newImage( 32, 26, $border, "png" );	
		$canvas2->roundCorners(2,2);
		$canvas2->setImageFormat('png');
 
		$canvas2->compositeImage($canvas,Imagick::COMPOSITE_OVER,1,1);
 
		header( "Content-Type: image/png" );
		echo $canvas2;
 
 
		$canvas->clear();
		$canvas->destroy();
		$canvas2->clear();
		$canvas2->destroy();
 
		//$canvas2->writeImage($cachefile);
 
	}catch(Exception $e){
		echo 'Error: ',  $e->getMessage(), "";
	}
 
/*
}else{
 
	$canvas = new imagick($cachefile);
	header("Content-Type: image/png");
	echo $canvas;
 
}
*/
 
?>

NOTE: the cachefile folder must be writable by the server.