Background color for inline text

In searching for a solution to a CSS problem I had I stumbled over another interesting problem, similar to mine. Most people seemed to agree that it
was impossible to do in pure CSS. The effect those people were after is commonly used in magazines where text with a background color is put over an image. A simple effect hard to achieve.

One solution was to surround each line of text using styled span elements. Another solution used ”a teeny weeny jquery” to solve the problem. I’m sure it’s a solid solution but using jquery and javascript to be able to style text is, well, wrong. Forcing editors to add invisible span elements in text is also not a good idea. But - the effect can actually be achieved using css only and still keep the html simple and semantically correct.

If you use a block element, like <p>, and set the background color, it will be  a filled square behind the text. By setting the css display property to inline you get  close to the effect wanted.

So far it is simple. The problem then is that using padding on inline text will only affect the horisontal padding (text indentation) on the first and last line of text. You get the following effect.

In order to get the effect we want we need to add two elements. A surrounding block element (div) surrounding the paragraph and an inline element (span) surrounding the text inside the paragraph. Both of which is semantically without meaning.

First we add a left border on the surrouding block element. Then we move the text in the span element slightly to the left. The background color is set on the paragraph and does not move. Using this neat little trick we simulate text padding or indentation on each line of text.

Finally we need to fix the vertical padding and line height to get rid of the spacing between the text lines. The end result is not perfect. There are still problems when the user resize text and you need to be careful with the spacing in Internet Explorer. But it’s a good start.

Chrome sometimes change line height seemingly in a random fashion when inserting html <br>. Setting white-space to pre-line fix this behaviour. If not for Internet Explorer it could be simplifed further. Internet Explorer does not seem to support white-space: pre-line. So Internet Explorer still needs manually added html breaks.

The full source

<pre>
<html>
  <head>
  <style type="text/css">
  div#column {
    border-left: 6px solid #000;
  }

  p.subs {
    display: inline;
    font: bold 14px/18px arial;
    color: #fff;
    background: #000;
    padding: 1px 0 1px 0;
    white-space: pre-line; /* Not understood by IE, use manual br for IE */
  }

  p.subs span {
    position: relative;
    left: -3px;
  }

  p.subs br {
    display: none;
  }
  </style>


  <!--[if IE ]>
    <style type="text/css">
      p.subs br {
      display: inline;
    }
    </style>
  <![endif]-->
  </head>
  <body>
    <div id="column">
      <p class="subs"><span>Ground round <br />
salami pig, meatball short loin frankfurter <br />
short ribs pork hamburger rump <br />
strip steak beef ribs T-bone salami ham hock.</span></p>
    </div>
  </body>
</html>
Web

PHP development on Mac – my experience

A while ago I saw a lot of people writing about their PHP development environment and tools. I didn’t get around to it at the time but yesterday I found me some time to write down my experiences of moving from Linux to MacOS X as primary OS for PHP  and web development

Me and my partner in Dotvoid, a small web development and integration company, have used linux as a client OS for more than a decade. All the tools I needed for developing are there already; emacs, apache, php, MySQL, xdebug, other scripting languages, various compilers, OpenOffice and so much more. For my partner, Gimp and Inkscape have provided all the functionality for producing both designs and graphics. And all for free. Fantastic. Even so, a few months ago I suddenly decided it was time to abandon our ugly plastic laptops from Dell and Sony. I ordered two Macbook Pro. I haven’t used or even touched a Macintosh since 1995. But hey, they look good.

We soon discovered that some things aren’t as user friendly as we exptected. The multitouch trackpad with it’s gestures is wonderful. My partner still use Inkscape and Gimp under MacOS. Still excellent tools. But she needs more precision and bought the Magic mouse which she’s not very satisfied with. You can change the acceleration but not the speed. Annoying. OpenOffice also works like a charm on MacOS.

As for me I really – really – miss a decent keyboard with keys as delete, home, end, page up and page down. I didn’t expect them to be missing from the Macbook keyboard. In time I guess I’ll get use to the weird key combinations that is needed to replace them. I might even get used to the weird combinations needed to write backspace, brackets and curly braces. But the keyboard is not really designed for programmers. On the other hand the multitouch trackpad is great. Virtual desktops in MacOS is also a bit limited but it’s not a big issue. All in all I’m slowly getting used to the hardware and the way things work under MacOS.

However, MacOS is not enough. There are PHP distributions for Mac. But as I use Ubuntu in production I use Virtualbox to run a 32-bit Ubuntu in a virtual machine. After disabling the Intel VT-x CPU optimization the 32-bit Ubuntu runs as smooth as ever. For some reason Virtualbox refuse to disable VT-x for Ubuntu 64-bit which is the reason I have to use 32-bit. With the VT-x (optimization) enabled the virtual machine with Ubuntu freeze for a couple of seconds every five seconds or so. I work in many different places, in different wireless networks and often using 3G. To make it work in any network I’m connected to I needed to setup two network adapters for the guest OS. One network adapter to allow the guest OS reach the outside world and another for communication between the host OS and the guest. I also have Virtualbox running a windows installation to allow me easy testing in a windows environment without hassle.

When buying Macbooks I also decided to buy Zend Studio for MacOS. I haven’t looked back once to either PDT or emacs. It is a great feeling being able to use subversion, debug, refactor, run tests and much more in the same editor without setting things up and tweaking PDT. It just works. I’m happy with it. Let’s me focus on development. And it is not as slow as for example SpringSource Tool Suite for java development. The workspace with the projects I work on I have in a shared directory accessible to both MacOS and the Ubuntu virtual machine.

In addition I use MySQL Workbench a lot. It is also available for MacOS. It is a great tool for designing and working with MySQL databases. I still use the command line a lot as I’ve done since 1997 when I first started working with MySQL. But with just a few clicks the Workbench let me see changes between a database and the schema, export all the changes to a database in development, staging and finally production. (I always use an ssh tunnel to push schema changes to staging and production databases as I never allow ftp or anything else.) I still run the MySQL development databases on the virtual machine though.

OmniGraffle is another application I decided to buy. I use it to create diagrams and flowcharts but also to build graphical user interfaces. Especially when designing iPhone apps. Great tool and well worth the money. You can find stencils for most purposes at Graffletopia.

Even though we still use mostly open source software, compared to a linux environment, the move to Macbook cost a lot. Especially for a small company as ours. But after a few months I still think it’s worth the money. The actual hardware is great. Looks good. Silent although it does get a bit too hot underneath. The high resolution anti-glare screen is fantastic. I can even work in direct sunlight outdoors. I never want to see another crappy Sony Vaio. If only my Macbook could stop crashing every now and then I’d be really satisfied.

PHP

Setting up a new company

In July, after another few months in Spain as a PHP consultant for a European debt collection company, I have been trudging along with my family in Kalmar. I am still doing consultancy work as a PHP developer and mostly for the very same company. It’s a great opportunity to work with PHP in a financial context where accuracy and quality is important. But the last couple of months I have also been busy setting up a new company as Artamus AB is investing in my Swedish event guide  Evenemang.se. This means more time to spend on coding PHP and less time needed to spend on marketing and SEO.

I really look forward to the coming year with excitement.

PHP

The MongoDB vs MySQL debate…

Same stupid debate as so often before. Just the topics are different from time to time. Found via the Swedish Utvbloggen, RWWhighscalability och myNoSQL.

Web

Recent activity…

Busy is good – but not being too busy. Recently I feel like I having been a bit too busy. A long time now me and my partner have been working on a new Swedish event guide. Completely written in Zend Framework, using MySQL as database and Sphinx as full text search engine. These tools are what I use normally nowadays while working on our own projects. The site has recently been launched as a beta in the spirit of release early/release often policy I have. The site is not near finished but releasing this early have already changed a few of our initial assumptions. So releasing early is good even though it sometimes can be hard to change the structure of a public website without getting in to trouble somehow.

Currently I’m also on a three month contract ending June 30th where I work three days a week with a European debt collection system in Fuengirola, Spain. I have been involved in the project every now and then for the past two years now. Fun and very interesting – but also challenging – as we’re a small team creating a complex system integrating many very different external systems (ranging from newly designed SOAP services to old COBOL systems to Windows bookkeeping applications. All in PHP of course. Beginning of July I’ll have some vacation and then we’ll just have too see what comes up.

So I thought I’d throw in an update of Wordpress and a new theme here on my blog as well… about time.

PHP, Personal

Detecting UTF BOM – byte order mark

When integrating systems with many different data sources and systems across Europe you are bound to eventually run in to issues with UTF-8 and national character sets as for example the Swedish ISO-8859-1. Even when parsing simple UTF-8 files with comma separated values things might things might popup to bite you.

One such thing is the occurrence of the UTF byte order mark, or BOM. The UTF-8 character for the byte order mark is U+FEFF, or rather three bytes – 0xef, 0xbb and 0xbf – that sits in the beginning of the text file. For UTF-16 it is used to indicate the byte order. For UTF-8 it is not really necessary.

But for UTF-8, especially on Windows, it has become more and more common to use it to indicate that the file is indeed UTF. Most text editors handle this well and you won’t ever see these bytes. As it should be.

The problems start when you are using PHP binary safe string functions such as strcmp() and substr(). Then these three bytes that won’t be visible even when using var_dump() can become bothersome. (You would however see that the string length output by var_dump() is correct and also counts the invisible bytes.)

So you need to detect the three bytes and remove the BOM. Below is a simplified example on how to detect and remove the three bytes.

$str = file_get_contents('file.utf8.csv');
$bom = pack("CCC", 0xef, 0xbb, 0xbf);
if (0 == strncmp($str, $bom, 3)) {
	echo "BOM detected - file is UTF-8\n";
	$str = substr($str, 3);
}

It’s as simple as that.

PHP

Dynamically change z-index on Google Maps markers

As many have noticed Google Maps API does not include a setIndex() method on the marker. You can set the z-index when adding a marker to the map. But it is not possible to change this afterwards.

I didn’t find a good solution to the problem when searching and had to resort to my own, hacking away on Google Maps. As I was feeling really good about myself when I had it working really well I just remembered that Google Maps Javascript API V3 has been released in Google Labs… And of course there it was. The Marker class has a new method, setZIndex(zIndex:number).

Well, version 3 of the API is still only released by Google Labs which is “home to developer products that are still in their formative stages“. So for anyone not inclined to use version 3 just yet, I’ll write down how I did it here.

As I use JQuery in this particular project the example is also using JQuery. If used in production I suggest using try/catch wherever appropriate as the solution depends on a specific dom structure.

I have the below HTML which is the container for the Google map.

<div id="indexmap"></div>

The map is created as below (you’ll have to add the lat/lng variable values yourselves.

var map = new GMap2($('#indexamp'));
var point = new GLatLng(lat, lng);
map.setCenter(point, zoom);

This, as most know, creates the actual map. Then it is time to add the markers. In my case I have a list of locations with the latitude/longitude in the actual html. JQuery helps me loop over these locations and dynamically add markers in the correct spots. This HTML looks like below. Note how each definition list have an id no with “mm_” as prefix. (Never mind any objections you have on having many definition lists like this… Never mind that these coordinates are fiction…)

<dl id="mm_0">
  <dt>...</dt>
  <dd>
    <span class="lat">61.333</span><span class="lng">31.1324</span>
    Random text
  </dd>
</dl>
<dl id="mm_1">
  <dt>...</dt>
  <dd>
    <span class="lat">61.333</span><span class="lng">31.1324</span>
    Random text
  </dd>
</dl>

What I want is the markers to be highlighted with a different icon every time I hover over a definition list element (dl). However, both have the same coordinates and one of the markers will be hidden behind the other.

So to prepare we need to make sure the actual images in the Google generated map can be connected to these defintion list id:s. The Google map have many different layers on top of each other. One layer contain the foreground images, another the shadows, mouse map definitions and so on. Each of these layers (normal div elements) have their own z-index.

In these different layers the images used have their own z-index. However, the z-index for the marker foreground image is the same as for the transparent clickable marker image. This makes it possible to use the transparent image z-index to restore the foreground image z-index. This is important as not to confuse the user when he later click on a marker…

So let’s loop over these images and give them appropriate id values as well as put the markers on the map. (No – Google does not give them id’s). This is, stripped to the bare essentials, the complete code with some comments.

// Create the map
var map = new GMap2($('#indexamp'));
var point = new GLatLng(lat, lng);
map.setCenter(point, zoom);

// Loop over the definition lists picking up coordinates
var n = 0;
$('dl').each(function() {
	var lat = parseFloat($('span.lat', this).text());
	var lng = parseFloat($('span.lng', this).text());
	var point = new GLatLng(lat, lng);

	// Create the marker with custom images
	var markerIcon = new GIcon(G_DEFAULT_ICON);
	markerIcon.image = 'marker_default.png';
	markerIcon.iconSize = new GSize(23, 30);
	markerIcon.shadow = "marker_shadow.png";
	markerIcon.shadowSize = new GSize(50, 30);
	markerIcon.iconAnchor = new GPoint(11, 29);
	markerIcon.infoWindowAnchor = new GPoint(11, 14);

	var marker = new GMarker(point, {icon: markerIcon});

	// Change the foreground image when hovering over a definition list
	// Note that the actual id's have not been created yet.
	var no = this.id.substring(3); // Exclude the prefix
	$(this).hover(
		function() {
			marker.setImage('marker_selected.png');
			// Bring this image to foreground
			$('#mf_' + no)[0].style.zIndex = 1;
		},
		function() {
			marker.setImage('marker_default.png');
			// Reset the z-index based on the transparent image
			// that has the same z-index
			$('#mf_' + no)[0].style.zIndex = $('#mt_' + no)[0].style.zIndex;
		}
	);
}

// Add id values to the foreground images, based on the
// dom structure created beneath the #indexmap div element used
// as the place holder for the map
n = 0;
$('#indexmap div > div > div:eq(6) img').each(function() {
	this.id = 'mf_' + n++;
});

// Add id values to the shadow images the same way
n = 0;
$('#indexmap div > div > div:eq(8) img').each(function() {
	this.id = 'mt_' + n++;
});

You might have to amend the code to get it working for you as I have cut’n pasted different parts. In the real code there is a lot of other things going on that would’ve made the example above hard to read. I do think however that you should be able to understand how it works.

Javascript

Moving on to php 5.3 and Zend Server CE

I have had some serious issues with one of my servers these last days. But finally things are starting to get back to normal. It seems /var was full due to mysql wreaking havoc for no particular reason. This lead – curiously enough – to network problems. If one of the discs failed because of these events or if it is somehow the original problem causing all this I really can’t tell…

Anyway, instead of quickly fixing the problem, I took the time to set up a new virtual private server running Zend Server CE with PHP 5.3. It feels good to finally move to 5.3 as well as trying out Zend Server in a production environment.

Now if I only had time to try out the new Zend Server 5.0. I’m especially curious about the job queue management. As I’ve more or less lost two days and two nights I guess that’ll have to wait.

PHP

Gartner report on PHP

A new Gartner report about PHP – PHP: Past, present and Future is mentioned in the last Zend newsletter. Even though I remain somewhat sceptical towards similar reports it is good to see that even Gartner is catching up. What they say actually do have an impact.

"PHP has been a cornerstone technology on the Web for more than a
decade. While its adoption among mainstream IT organizations has been
limited in the past, many corporate application development (AD)
projects are discovering the unique benefits of PHP."

One particular advice is especially interesting for large companies.

"Consider PHP as a supporting technology in a broader portfolio of AD
technologies, where it can provide a specialized toolset for building
Web graphical user interface (GUI) front ends to service-oriented
architecture (SOA) back-end services."

PHP is a fantastic tool for building rich web applications. It’s extensibility makes it versatile and extremely easy to integrate with modern integration solutions as Web Methods, legacy systems or just about any database technology.

To me – this has always been where PHP really shines.

PHP

Adding support for MS SQL Server to PHP in Linux

Adding support for MS SQL Server in PHP is not very difficult. Searching (Google/Bing/whatever) reveals lots of information on how to do this with Windows – naturally – but very little on how to go about it using Linux. Most people use precompiled PHP installations and I will show how to add MS SQL Server support to a precompiled PHP installation here. Those of you compiling PHP yourselves will probably understand what to do and what not based on the information here as well.

1. Install FreeTDS

First download and install FreeTDS from freetds.org. Use the following build commands to enable support for MS SQL Server (as root or using sudo).

./configure --enable-msdblib --prefix=/usr/local/freetds
make && make install

Unfortunately you need to tweak the installation somewhat as PHP still checks for files in FreeTDS that is no longer part of the installation. Just make sure these files exist (empty) by issuing the below commmands. (If you use another –prefix path above you will need to change the path accordingly)

touch /usr/local/freetds/include/tds.h
touch /usr/local/freetds/lib/libtds.a

2. Get the PHP source and compile the mssql extension

Yes – you need the complete PHP source even though you already have a precompiled PHP installed. You will not touch your PHP installation and we are not going to compile all of PHP. We need the source to be able to compile the mssql extension.

It is advised to always use the source of the same PHP version you have installed!

Unpack the source and compile the mssql extension. Remember again to change the path accordingly if you installed freeTDS in another location.

cd php*/ext/mssql
phpize
./configure --with-mssql=/usr/local/freetds
make

The extension should now be compiled and ready to install. You will find the binary in the immediate sub directory modules.

3. Install the extension

Find out where PHP expects to find extension libraries. The simplest way to check this is through the command line.

php -i | grep extension_dir

Some distributions use different php.ini files for command line PHP and the PHP web server module. So it might be good to double check using the function phpinfo() in a php script loaded through the web server (using your browser is easiest).

<?php phpinfo();

Then search for extension_dir in the configuration information displayed. For example, on my laptop running Ubuntu, the path is /usr/lib/php5/20060613+lfs.

Continuing from above without having moved away from the directory where you compiled your mssql extension.

cp modules/mssql.so /usr/lib/php5/20060613+lfs/

The extension is in the right place and all you have to do now is to make sure PHP actually loads it. To do this add the extension somewhere in the php.ini file. For example in the section Dynamic Extensions to keep it somewhere logical.

extension=mssql.so

3. Restart the web server

If using the Apache 2 web server you would normally issue

/etc/init.d/apache2 restart

4. Post installation

Well that’s about it. You should have a workable mssql extension added to your PHP installation. You should be able to continue using your platforms chosen way of upgrading PHP without affecting the MS SQL Server support.

However, you might need to dig into the freetds.conf file. If you have followed my steps without altering the installation path you will find the freetds.conf file in /usr/local/freetds/etc/freetds.conf.

Sometimes it is difficult getting the connection work without adding it to the the freetds.conf. Especially since you may have to use different values for the tds version directive depending on the MS SQL Server version. Examples:

[logisticsServer]
host = ntmachine.localdomain
port = 1433
tds version = 7.0

[intranetServer]
host = 192.168.1.145
port = 1433
tds version = 4.2

Again. Check that you are using the correct freetds.conf file and that you are using the correct tds version! More information on this at freetds.org. This and the above mentioned “missing files” that PHP is looking for are the two most common pitfalls.

Good luck!

PHP