Posted by Wojtek Kosinski at 6 July 2010

Category: CSS, HTML

Tags: , ,

How to make a div with multiple borders?

Usual approach is to create a div with border then create another div inside that one with different border. We end up with lots of divs inside of another divs. If there only was an easier way to do it in CSS without the need of more divs… There is!

:before and :after pseudo classes

Internet Explorer 6 and 7 does not support :before and :after pseudo classes and to be honest I couldn’t find a working fix for it. The good thing is that those dinosaurs are fading out from our lives.
:before and :after pseudo classes allow to place text or an image before and after each HTML element using content: ”; attribute. In below example content is empty as we need just a border.

<!DOCTYPE html>
<html lang="en">
<head>
<title>Multiple borders with CSS2</title>
<meta charset="utf-8" />
<style>
body { background: #fff; }
#box {
	float: left;
	position: relative;
	width: 100px;
	height: 100px;
	margin: 20px;
	border: #f00 solid 5px;
}
	#box:before {
		position: absolute;
		width: 90px;
		height: 90px;
		content: '';
		border: #0f0 solid 5px;
	}
	#box:after {
		position: absolute;
		left: 5px;
		top: 5px;
		width: 80px;
		height: 80px;
		content: '';
		border: #00f solid 5px;
	}
</style>
</head>
<body>
	<div id="box"></div>
</body>
</html>

Above code should result in:
Multiple borders with CSS

More information about :before and :after pseudo classes can be found here

 

Posted by Wojtek Kosinski at 15 June 2010

Category: HTML

Tags: , , , , ,

Everyone is excited about the new kid on the block – HTML5, but where to start and how to use it? There are couple of things you can start using right now with a few hacks for our lovely IE6 and other browsers not yet supporting HTML5. Before we get into it, it’s good to know the level of support of HTML5 in different browsers. These few links can help you find it out.

Not supported elements

Following elements are no longer supported in HTML5:

  • <acronym>
  • <applet>
  • <basefont>
  • <big>
  • <center>
  • <dir>
  • <font>
  • <frame>
  • <frameset>
  • <noframes>
  • <s>
  • <strike>
  • <tt>
  • <u>
  • <xmp>

Now, lets start with a few simple tags.

Doctype

Oh the doctype, who could remember the whole thing?

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">

Instead of old doctype like the one above we can finally start using something that is really easy to remember.

<!DOCTYPE html>

YES! That’s it, we’re done :) Even Google is using it already.

Character Set

Again, a lot simpler than it used to be.

<meta charset="utf-8" />

<script>, <style> and <link> elements

We’re all used to this

<script type="text/javascript" src="/path/to/my/file.js"></script>
<style type="text/css">
#myId { margin:0px; }
</style>
<link type="text/css" rel="stylesheet" href="/path/to/my/file.css" />

but with HTML5 the we can omit the type attributes as the values above are set as default. Our bit of code becomes a little more clean.

<script src="/path/to/my/file.js"></script>
<style>
#myId { margin:0px; }
</style>
<link rel="stylesheet" href="/path/to/my/file.css" />

Semantic structure

A few new elements were added to only add a more semantic meaning to well known <div> tag. Some of those elements are:

  • <article>
  • <section>
  • <aside>
  • <hgroup>
  • <header>
  • <footer>
  • <nav>
  • <time>
  • <mark>
  • <figure>
  • <figcaption>

Support in IE

IE9 is supposed to support HTML5 when it’s out but for now we have to tell IE what type are those elements. To not complicate things too much all we need to do is make a use of this awesome script. Just paste it within your head tag.

<!--[if IE]>
<script src="http://html5shim.googlecode.com/svn/trunk/html5.js"></script>
<![endif]-->

Sample page layout

<!DOCTYPE html>
<html lang="en">
<head>
<title>Title</title>
<meta charset="utf-8" />
<meta http-equiv="imagetoolbar" content="no" />
<meta name="robots" content="index, follow" />
<meta name="keywords" content="Keywords" />
<meta name="description" content="Description" />
<!--[if IE]>
<script src="http://html5shim.googlecode.com/svn/trunk/html5.js"></script>
<![endif]-->
</head>
<body>
<div id="wrapAll">
	<header>
		<nav>
			<ul>
				<li><a href="#">Item 1</a></li>
				<li><a href="#">Item 2</a></li>
				<li><a href="#">Item 3</a></li>
			</ul>
		</nav>
	</header>
	<section>
		<article>
			<header>
				<h1>Article Header</h1>
				<time datetime="2010-06-15" pubdate>June 15th, 2010</time>
			</header>
			<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit.</p>
		</article>
	</section>
	<footer>
		Footer content
	</footer>
</div>
</body>
</html>

 

Posted by Wojtek Kosinski at 8 June 2010

Category: Self development

Tags: , ,

What motivates us

At the beginning of the video I didn’t agree to what he was saying but then he explained “Why” and “How” and it all made sense.

 

Posted by Wojtek Kosinski at 1 June 2010

Category: CSS, HTML

Tags: , , , , , ,

Problem

Gmail recently made a few changes in their email rendering engine. Unfortunately for us our image based HTML newsletters that used to look fine in gmail are now broken. Each image seems to have a weird spacing after it.
If you’ve been sending HTML newsletters for your clients for some time now, you probably have your own email templates that work well in all email clients. Well not all thanks to Google.

Solution

To make things back to what they were just add style=”display:block;” to every img tag in your HTML email and we’re back in business.

 

Posted by Wojtek Kosinski at 25 May 2010

Category: non-tech

Tags: , , ,

Technorati code: G8GA9E4SYN2J

Recently I wrote about Google making our life much easier. Unfortunately there are still companies that make our life a never ending stream of frustration. Yes Technorati I’m talking about your awesome blog claim process. I was under an impression of mutual benefits from me adding my blog to your directory. You have more blogs in your database providing better search results and I get a bit more exposure thanks to you. In theory that is.

I registered, filled in my profile details and made it to claiming my blog part. After reading a bit vague instructions I guessed you want me to write a new post adding my unique claim code to the body of that post. I did that and surprise, surprise, it’s not working. Googling for problems with you blog claim process returns close to 600 000 results with increase of about 5k a day. I think that’s quite a lot of people who have no clue why it’s not working. Here’s another post by a frustrated blogger. I found at least 4 separate threads in your GetSatisfaction board.

If you haven’t noticed a lot of people have problems with this tedious process.

Guys, admit it already, scanning RSS feeds does not work for most of us. A word of advice, why won’t you do what other services are doing like claiming a blog by adding a meta tag to my homepage, uploading a blank HTML file with my claim code in the filename or maybe requiring an email address in the same domain. Even if someone has access only to admin panel and can’t upload files nor modify meta tags maybe something easy like adding your damn code in my blog’s sidebar could work? No? Sorry for trying.

Your instructions are so unclear as no one seems to know for sure how to make it work.

I’m trying to put your claim code in the beginning of my post so that maybe it will be visible in my RSS’s preview that you’re scanning.

Crossing fingers and hoping for the best.

 

Posted by Wojtek Kosinski at 23 May 2010

Category: HTML

Tags: , , , , ,

Technorati code: G8GA9E4SYN2J

Google just made our life much easier by announcing Google font api and Google font directory.
Using custom fonts on your website is as easy as adding two lines of code. Lets consider this simple example.

<!DOCTYPE html>
<html lang="en">
<head>
<title>Custom fonts</title>
<meta charset="utf-8" />
<style>
      body { font-size: 48px; }
</style>
</head>
<body>
<header>
	<p>Hello world!</p>
</header>
</body>
</html>

Nothing fancy here, result as expected.

 

Hello world!

 

Now lets add those two aforementioned lines. Line 6 and line 9 in below listing.

<!DOCTYPE html>
<html lang="en">
<head>
<title>Custom fonts</title>
<meta charset="utf-8" />
<link href='http://fonts.googleapis.com/css?family=Tangerine' rel='stylesheet' type='text/css'>
<style>
      body { font-size: 48px; }
      p { font-family: 'Tangerine', serif; }
</style>
</head>
<body>
<header>
	<p>Hello world!</p>
</header>
</body>
</html>

and the effect

 

Hello world!

 

The font directory is a bit limited at the moment but I think we can safely assume that Google will be adding more fonts over time.

 

Posted by Wojtek Kosinski at 14 April 2010

Category: PHP

Tags: , ,

Recently I had a small problem with cURL. The request was supposed to return only JSON data to use in my app. I wrote the following:

$curl = curl_init();
curl_setopt($curl, CURLOPT_URL, 'http://somedomain.com/api/123');
curl_setopt($curl, CURLOPT_HEADER, false);
curl_setopt($curl, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_1);
curl_exec($curl);
$status = curl_getinfo($curl);
curl_close($curl);

The variable $status contained the API’s response in plain text and concatenated, inaccessible in this format, array with cURL’s status response. This made impossible for example checking if the request was successful. I had to get rid of the JSON response and leave only cURL status array. In order to do that I added curl_setopt($curl, CURLOPT_RETURNTRANSFER, 1); option which cleared all this garbage and left only cURL’s status array.

$curl = curl_init();
curl_setopt($curl, CURLOPT_URL, 'http://somedomain.com/api/123');
curl_setopt($curl, CURLOPT_HEADER, false);
curl_setopt($curl, CURLOPT_RETURNTRANSFER, 1);
curl_setopt($curl, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_1);
curl_exec($curl);
$status = curl_getinfo($curl);
curl_close($curl);

Last thing I had to do was retrieve API’s JSON response and assign it to another variable. I have to say the solution wasn’t my first logical choice. After some time it turned out that curl_exec() returns exactly what I need.
In the end, my bit of code became something like this:

$curl = curl_init();
curl_setopt($curl, CURLOPT_URL, 'http://somedomain.com/api/123');
curl_setopt($curl, CURLOPT_HEADER, false);
curl_setopt($curl, CURLOPT_RETURNTRANSFER, 1);
curl_setopt($curl, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_1);
$response = curl_exec($curl);
$status = curl_getinfo($curl);
curl_close($curl);

Now, variable $response contained only JSON and $status contained only cURL’s response status. I was happy again.
 

Posted by Wojtek Kosinski at 7 April 2010

Category: MySQL

Tags: , , ,

Is your MySQL really slow without actually being too busy?
Does your scripts take very long time to connect to the database?
Do you have lots of RAM, strong CPU, just a little traffic and despite that a very long database response time?
Are you seeing connections with “unauthenticated user” while running show processlist in MySQL console?

mysql> show processlist;
+------+----------------------+-----------+----------+----------+------+-------+--------------+
| Id   | User                 | Host      | db      | Command   | Time | State | Info         |
+------+----------------------+-----------+----------+----------+------+-------+--------------+
| 2047 | unauthenticated user | localhost | myDB    | Connect   |   81 |       | NULL         |
| 2049 | unauthenticated user | localhost | myDB    | Connect   |   81 |       | NULL         |
| 2050 | unauthenticated user | localhost | myDB    | Connect   |   76 |       | NULL         |
...
+------+----------------------+-----------+----------+----------+------+-------+--------------+
131 rows in set (0.00 sec)

If you answered yes to any of the above questions your MySQL might have a problem with resolving connection’s host name.
When attempt is made for a new connection, MySQL tries to resolve the host name for that request. It takes the IP address and resolves it to a host name (using gethostbyaddr()). It then takes that host name and resolves it back to the IP address (using gethostbyname()) and compares to ensure it is the original IP address.
This might considerably increase connection time and slow down your whole application or produce show processlist result as above. You can easily solve this problem by disabling DNS host name lookups. In order to do this you need to run your mysqld with –skip-name-resolve option or add it to your my.cnf file like that:

[mysqld]
skip-name-resolve

After that running show processlist will result in “Host” column displaying only IP addresses instead of host names and the connection speed should be much faster.

Just keep in mind that also you have to change allowed hosts for your database users to proper IP addresses.
 

Posted by Wojtek Kosinski at 30 March 2010

Category: MySQL, PHP

Tags: , , , ,

The bug

If you’re running PHP 5.1.6 and just started using PDO for your database connection, it’s likely you’ll run into quite an annoying bug.
Lets test a simple query partly taken from PHP documentation.

$calories = 150;
$colour = 'red';
$sth = $myPDO->prepare('SELECT name, colour, calories
    FROM fruit
    WHERE calories < :calories AND colour = :colour');
$sth->bindParam(':calories', $calories, PDO::PARAM_INT);
$sth->bindParam(':colour', $colour, PDO::PARAM_STR, 12);
$sth->execute();
if ($sth->rowCount() >= 1) {
    // iterate through results
}

Everything seems great. The problem is that $sth->rowCount() will always return 0. No matter how many results your query returns, the value of rowCount() will always be 0.

Full bug report can be found here: http://bugs.php.net/40822.

Solution

Upgrade PHP :)

If that’s not an option read on.

Lets create our own simple PDO and PDOStatement classes.

class myPDO extends PDO {
	function __construct($name_host, $username='', $password='', $driverOptions=array()) {
		parent::__construct($name_host, $username, $password, $driverOptions);
		$this->setAttribute(PDO::ATTR_STATEMENT_CLASS, array('myPDOStatement', array($this)));
	}
}
class myPDOStatement extends PDOStatement {
	public $db;
	protected function __construct($db) {
		$this->db = $db;
	}
}

Above will not fix anything. This is just a start so we can overload some PDO methods to apply the fix.

To fix the bug we need to tell MySQL to use the buffered versions of the MySQL API by setting attribute MYSQL_ATTR_USE_BUFFERED_QUERY to true.
For some reason, still unknown to me setting this option like that

class myPDO extends PDO {
	function __construct($name_host, $username='', $password='', $driverOptions=array()) {
		parent::__construct($name_host, $username, $password, $driverOptions);
		$this->setAttribute(PDO::ATTR_STATEMENT_CLASS, array('myPDOStatement', array($this)));
		$this->setAttribute(PDO::MYSQL_ATTR_USE_BUFFERED_QUERY, true);
	}
}

will not work.

After many hours of tearing my hair out I found out that all you need to do is this:

class myPDO extends PDO {
	function __construct($name_host, $username='', $password='', $driverOptions=array()) {
		$driverOptions[PDO::MYSQL_ATTR_USE_BUFFERED_QUERY] = true;
		parent::__construct($name_host, $username, $password, $driverOptions);
		$this->setAttribute(PDO::ATTR_STATEMENT_CLASS, array('myPDOStatement', array($this)));
	}
}

You have to set MYSQL_ATTR_USE_BUFFERED_QUERY before instantiating a connection. Setting it after the connection was made will not work.

When this is done we need to modify our myPDOStatement class.

class myPDOStatement extends PDOStatement {
	public $db;
	// other attributes
	private $foundRows; // will hold number of affected rows
	protected function __construct($db) {
		$this->db = $db;
	}
	public function execute($array = null) {
		if ($array === null) {
			$result = parent :: execute();
		} else {
			$result = parent :: execute($array);
		}
		// fix for PHP 5.1.6 rowCount error
		$this->foundRows = $this->db->query("SELECT FOUND_ROWS()")->fetchColumn();
		return $result;
	}
	public function rowCount() {
		return $this->foundRows;
	}
}

After above changes our rowCount() method will return proper values.
 

Posted by Wojtek Kosinski at 24 March 2010

Category: Linux

Tags: , ,

If you want to avoid situation when after server restart you have to start lots of services manually, a little thing like chkconfig would come in handy.
First you might want to take a look at a list of services handled by chkconfig:

chkconfig --list

You should see something like this:

mysql           0:off   1:off   2:on    3:on    4:on    5:on    6:off
named           0:off   1:off   2:off   3:on    4:off   5:off   6:off
sshd            0:off   1:off   2:on    3:on    4:on    5:on    6:off

To add for example mysql to autostart list simply type:

chkconfig --add mysql on

To remove a service from autostart list type:

chkconfig --del mysql

For full list of chkconfig options go here.

Page optimized by WP Minify WordPress Plugin