// Little known PHP features: method chaining, enabling you to call methods the short way

Since PHP5, methods can return objects (including $this). This enables you to chain the method calls after preparing your class by returning the object itself. Therefore, “Method chaining” may save you e.g. much copy & paste or chars to type, reducing typing time for dozens of $obj->method() calls.

<?php
 
//common way
class foo {	
    public function one() {
        echo "one ";
    }
    public function two() {
        echo "two ";
    }
    public function three() {
        echo "three\n\n";
    }
}
$object = new foo();
$object->one();
$object->two();
$object->three();
 
 
//with method chaining (note the "return $this;")
class bar {	
    public function one() {
        echo "one ";
        return $this;
    }
    public function two() {
        echo "two ";
        return $this;
    }
    public function three() {
        echo "three\n\n";
        return $this;
    }
}
$object = new bar();
$object->one()
       ->two()
       ->three();
?>

I did not made any performance measurements right now… so I can't say if method chaining is faster/slower in common environments or not. And to be honest, I don't use method chaining for myself:

  • You simply can't see if a class supports method chaining without trying it or looking at its source.
  • The need for all these return $this; within the class methods.
  • IMHO, both reasons are leading to inconsistent coding styles and behaviors in real world applications containing 3rd party classes.

// How to create an easily maintainable DokuWiki template

Creating templates for most web applications is not really a hard task. But if you plan to share your work with the public you face a little problem every now and then, namely when there's a new version of the application available: you have to track down what has changed since the last release to be able to update your template accordingly. Sure, not everyone has the time to follow the development of an application close enough to notice every small change which affects his work. IMHO that could be the cause why some of the available DokuWiki templates are a little outdated and likely not 100% compatible with the latest release. However, I would like to show a way to take advantage of DokuWiki's stylesheet handling and to keep the effort needed to keep such a template up-to-date at a minimum (we're all lazy people, right ;-)).

Creating a new template

The easiest way to create a new template is the Starter template by Anika Henke.1) Just download and extract it. Rename the folder, place it below <dokuwiki>/lib/tpl/templates and select it in the DokuWiki configuration manager.

The idea: taking advantage of DokuWiki's CSS handling

DokuWiki provides an advanced CSS handling system which uses a PHP .ini file named style.ini, which is part of the template. It is used to determine which files are getting loaded for a certain display mode. So lets have a look at the style.ini provided by the Starter template. Right now we're interested in the first section of the file:

style.ini
[stylesheets]
 
css/basic.css             = screen
css/structure.css         = screen
css/design.css            = screen
css/content.css           = screen
css/_imgdetail.css        = screen
css/_media_popup.css      = screen
css/_media_fullscreen.css = screen
css/_fileuploader.css     = screen
css/_tabs.css             = screen
css/_links.css            = screen
css/_toc.css              = screen
css/_footnotes.css        = screen
css/_search.css           = screen
css/_recent.css           = screen
css/_diff.css             = screen
css/_edit.css             = screen
css/_modal.css            = screen
css/_forms.css            = screen
css/_admin.css            = screen
css/includes.css          = screen
 
css/rtl.css               = rtl
css/print.css             = print

The above describes which .css file gets loaded for a certain display mode. “screen” is the normal display mode when you watch the page in a browser, “rtl” is loaded for right-to-left languages, and “print” obviously when you like to print a wiki page.2) For more information regarding the loading order of stylesheets refer to the docs.

So here is the key part:

We're not gonna edit any of the .css files we copied over from the Starter template!

We just add our own .css files for each mode at <dokuwiki>/lib/tpl/template/<mytemplate>/css instead and modify the style.ini so they get loaded after the original ones:

style.ini
[stylesheets]
 
css/_imgdetail.css        = screen
css/_media_popup.css      = screen
css/_media_fullscreen.css = screen
css/_fileuploader.css     = screen
css/_tabs.css             = screen
css/_links.css            = screen
css/_toc.css              = screen
css/_footnotes.css        = screen
css/_search.css           = screen
css/_recent.css           = screen
css/_diff.css             = screen
css/_edit.css             = screen
css/_modal.css            = screen
css/_forms.css            = screen
css/_admin.css            = screen
css/mytemplate_screen.css = screen
 
css/rtl.css                = rtl
css/mytemplate_rtl.css     = rtl
css/print.css              = print
css/mytemplate_print.css   = print

Instead of editing any of the .css files we copied over from the Starter template we add our CSS rules to the files we just created and make use of a key CSS feature: the so-called cascade.3) Expressed in simplified terms, CSS rules simply override previous rules affecting the same element.4) And in some cases where the specificity of your rule is not enough, you may use !important5) or an own class to solve such problems.

So we just override any Starter template CSS rule we like to change in our own mytemplate_screen.css, mytemplate_rtl.css and mytemplate_print.css. Developing a stylesheet this way is a little bit more advanced than if you just edit the existing .css files. But it has an advantage as you'll see later. Additionally, you may noticed that I removed some original Starter template files which are not starting with an underscore (basic.css, structure.css, design.css, content.css and includes.css). The reason for this is simple: only the files starting with an underscore plus rtl.css and print.css are the important core styles, the rest is supposed to be adjusted. Therefore use them as starting point for your own mytemplate_screen.css.

Another thing you may like to consider while modifying DokuWiki's CSS is that it is best to access the elements the same way as done in the Starter template CSS files and prepend most ids or classes with .dokuwiki. And have a look at the color placeholders. If you happen to edit the main.php of your template to add or edit something you shouldn't remove the <div class="dokuwiki"> as it will break the whole stylesheet!

To get a clue about which rules to overwrite, it may help you to look at the CSS files of my templates prsnl10 and mnml-blog:

As you may have noticed, this approach has one drawback. The size of the final stylesheet delivered to the browser will be bigger than if you just edit the existing .css files. This should be around ~2kB till 15kB (uncompressed), depending on the things you are changing. Since the whole CSS gets compressed and is usually delivered only once and then cached I don't think it's that much of a problem.6) And it is not “unclean” or something like that because the Wiki's data is not affected and a template is not triggering any dependencies for your data in general.

Keeping It Up-To-Date

If you follow the approach given above, keeping your template up-to-date after a new DokuWiki release is a task that can be done very quickly! The only thing you have to do is to run a diff against all .css files you copied from the Starter template against the original ones (or have a look at the Commits, e.g. if you are not familiar with tools like diff). Checking the Starter template changelog is also a good idea. If there have been changes, just copy the changed .css files of the Starter template to your template folder overriding the old ones, and, only if needed, add some extra rules to your custom .css files to adjust everything to your needs. The best place to check if everything is OK is the syntax page included in every DokuWiki release.7) It is also recommendable to have a look at the .php files provided by the Starter template to determine if there are any changes needed for new features. The official Developers Changelog may help you to support new features, too.

Some additional notes

That's it! At least this approach works pretty well for me ;-). Of course this only covers CSS issues but it assures that things don't get totally messed up. If you've added new functionality to a template you surely have to put more time into testing/debuging things. But if you create a different look for DokuWiki and like to share it, this is one way to keep things easy over time. Keeping things maintained is normally much harder than creating something new, therefore the additional work when starting a new template should pay off quickly. The approach is even powerful enough to make things like vector8) or this blog's template mnml-blog possible without getting to much trouble when a new DokuWiki version was released.

In the past, the best way to start an own template was to copy DokuWiki's default template. The reason is simple: there was no such useful thing as the Starter template. Therefore all of my existing templates were based on the default template CSS. But things changed a bit. First of all, DokuWiki will get a new default template called “dokuwiki” in the near future. Therefore I asked on the mailing list if it is better to use the “Starter” template CSS or wait for the new “dokuwiki” template CSS as technical base for the development approach described in this text. And the answer is clear: use the Starter template as the new default template is based on Starter, too. Therefore I switched all of my templates over from the old default template CSS to the Starter template CSS as technical base.9) I'm sure a comparable situation won't happen again. Relying on the default template simply was less future-proof than relying on the now existing Starter template which is just existing to make template developing easier.

Update 2011-12-03: I updated parts of the article to fit the newest changes and Anika's recommendations.

This post is based on a text created by Michael Klier. He decided to shut down his blog. The unmodified text was originally posted on August, 16th 2007 and is licensed under the Creative Commons BY-NC-SA License and accordingly this text also is. I just took his post and changed the needed things to fit the facts of 2011.

1)
Anika is an important and reliable part of the DokuWiki development and also responsible for the coming DokuWiki default template called “dokuwiki”.
2)
You can have a look at it by using your browser's print preview.
3)
The first “C” in CSS, you know.
4)
In fact, the priority scheme is a little bit more complicated but this should not matter in general. If you want to know more about, have a look at the weblinks at the end of this text.
5)
Usage example: p { font-size:1em !important; }
6)
I am sure there are other opinions on that topic though
7)
Tip: open two tabs in Firefox (one for the old, one for the new version) and use Ctrl+Page↑ / Ctrl+Page↓ to quickly switch between them for a comparison. Use the headline navigation (e.g. :wiki:syntax#tables) to jump to the exactly same point in both versions.
8)
which merges DokuWiki and MediaWiki CSS
9)
This sounds harder than it really is…

// HMAC-SHA-1 for PHP

Hash-based Message Authentication Codes (HMAC)10) are very useful. Especially HMAC-SHA-1 is used by more and more webservices (e.g. Amazon S3) to verify if a request comes from a valid user (by using a shared secret/key + submitting the result of HMAC-SHA-1($request)). The easiest way to generate them – hash_hmac() – is only available for PHP > 5.1.2 and I saw many system where the function is not available. I even saw people installing the whole PEAR system just to get PEAR::Crypt_HMAC running. :-O

If you need a simple function for creating SHA-1 based HMACs, you may be interested in the following:

hmac-sha1.php
<?php
 
/**
 * Returns the HMAC-SHA-1 of a string
 *
 * @param string The data to hash.
 * @param string The key to use. Use ASCII only for best compatibility.
 *        Otherwise, you have to take care about using the same encoding in
 *        every case.
 * @param bool (optional) TRUE leads to PHP warnings if a non-ASCII-string was
 *        submitted as key. FALSE will suppress this check. Default is TRUE.
 * @return string The HMAC-SHA1 of the data.
 * @author Andreas Haerter
 * @link http://en.wikipedia.org/wiki/HMAC
 * @link http://tools.ietf.org/html/rfc2104
 * @link http://blog.andreas-haerter.com/2010/09/30/hmac-sha-1-php
 * @license GPLv2 (http://www.gnu.org/licenses/gpl2.html)
 * @license New/3-clause BSD (http://opensource.org/licenses/bsd-license.php)
 */
function hmac_sha1($str, $key, $warn_nonasciikey = true)
{
	//check: key consists of ASCII chars only?
	//this should prevent unexpected (=not equal results) when mixing this
	//implementation and base64_encode(hash_hmac("sha1", $str, $key, true))
	//regarding different encodings etc.
	if (!empty($warn_nonasciikey)
	    //search for any bytes which are outside the ASCII range...
	    //note: the regex is *REALLY* fast. Even a "quickcheck" with ctype_alnum()
	    //      won't make the things faster but slower on *common* input!
	    && preg_match('/(?:[^\x00-\x7F])/u', $key) === 1) {  //ATTENTION: single quotes are needed here! Otherwise, PCRE is not able to find the ending delimiter!
		//inform developers
		trigger_error(//text
		              __FUNCTION__.":non-ASCII key may lead to unexpected results when switching encodings!",
		              //type
		              E_USER_WARNING);
	}
 
	//use PHP's built in functionality if available (~20% faster than the
	//following script implementation)
	if (function_exists("hash_hmac")) {
		return base64_encode(hash_hmac("sha1", $str, $key, true));
	}
	//create the secret based on the given key
	$key_lenght = strlen($key);
	//key is longer than 64 bytes, use the hash of it
	if ($key_lenght > 64) {
		$key        = sha1($key);
		$key_length = 40;
	}
	//pad secret with 0x0 to get a 64 byte secret?
	if ($key_lenght < 64) {
		$secret = $key.str_repeat(chr(0), (64 - $key_lenght));
	} else {
		//64 bytes long, we can use the key directly
		$secret = $key;
	}
	//hash and return it
	return base64_encode(sha1(//create the string we have to hash
	                          ($secret^str_repeat(chr(0x5c), 64)). //pad the key for inner digest
	                          //subhash
	                          sha1(//create substring we have to hash
	                               ($secret^str_repeat(chr(0x36), 64)). //pad the key for outer digest
	                               $str,
	                               //we need RAW output!
	                               true),
	                          //we need RAW output!
	                          true));
}
 
//example
echo hmac_sha1("this is the data to hash", "my secret key, ASCII only for best compatibility");
 
?>

The source code of this function is dual-licensed under GPLv2 and New/3-clause BSD. Have fun. :-)

10)
see RFC2104 for details

// Fixing the lack of support for transparent PNG images in Microsoft Internet Explorer 6: my favorites

It is an old problem, but still actual: MSIE 5.5/6 does not support alpha channel transparency in PNG (at least in PNG-24). If you google it, you will get many results. The reason why I am blogging about is the different quality and heaviness of the thousands of existing fixes, it is not easy to know which are the good ones if you never used them. Therefore I want to share my personal favorites. I'm creating websites for years now, and there are two freely available fixes which always did the job for me:11)

11)
as long as you as you ignore the flaw that JavaScript has to be active
12)
licensed under LGPL
13)
licensed under GPL

// Microsoft Internet Explorer 8: Fix the weird textarea scrolling bug

MSIE 8 brings some new, weird bugs. One of the most annoying one targets <textarea>s with a percentage value for the width CSS property (ironically in standards mode only, the problem disappears in IE7 compatibility view or quirks mode). When a textarea has got enough content to offer scrollbars and the user already scrolled a little bit, every keystroke will because a disturbing auto-scroll effect (even with flickering scrollbars under certain conditions like onkeyup/down events or border CSS property values). This is a real show-stopper which makes editing longer texts very uncomfortable for IE8 users.

The following file shows the problem. Simply download and open it with IE8.14)

msie8-textarea-bug.html
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en" dir="ltr">
<head>
<meta http-equiv="content-type" content="text/html; charset=utf-8" />
<title>MSIE8 textarea scroll bug/fail demo</title>
</head>
<script type="text/javascript">/*<![CDATA[*/
function checkMode() {
    var standard = false;
    if (document.compatMode) {
        if (document.compatMode === "BackCompat") {
            m = "Quirks";
        } else if (document.compatMode === "CSS1Compat") {
            m = "Standards Compliance";
            standard = true;
        } else {
            m = "Almost Standards Compliance";
        }
        if (standard === false) {
           alert("ATTENTION: The document is being rendered in "+m+" Mode - there will be NO bug!");
        }
        //alert("The document is being rendered in "+m+" Mode.");
    }
}
checkMode();
/*]]>*/</script>
<style type="text/css">
textarea {
    height: 180px;
    width: 50%; /* this will trigger the bug */
}
</style>
<body>
  <form name="foobar" method="post" action="">
    <textarea>
Please scroll down a little bit and try to edit text. E.g.
change the line by clicking into the text, type "asdf",
go to another line, type "asdf" and so on.
 
Lorem ipsum dolor sit amet, consetetur sadipscing elitr,
sed diam nonumy eirmod tempor invidunt ut labore et dolore
magna aliquyam erat, sed diam voluptua.
Lorem ipsum dolor sit amet, consetetur sadipscing elitr,
sed diam nonumy eirmod tempor invidunt ut labore et dolore
magna aliquyam erat, sed diam voluptua.
Lorem ipsum dolor sit amet, consetetur sadipscing elitr,
sed diam nonumy eirmod tempor invidunt ut labore et dolore
magna aliquyam erat, sed diam voluptua.
Lorem ipsum dolor sit amet, consetetur sadipscing elitr,
sed diam nonumy eirmod tempor invidunt ut labore et dolore
magna aliquyam erat, sed diam voluptua.
Lorem ipsum dolor sit amet, consetetur sadipscing elitr,
sed diam nonumy eirmod tempor invidunt ut labore et dolore
magna aliquyam erat, sed diam voluptua.
Lorem ipsum dolor sit amet, consetetur sadipscing elitr,
sed diam nonumy eirmod tempor invidunt ut labore et dolore
magna aliquyam erat, sed diam voluptua.
    </textarea>
</body>
</html>

I don't know how to get rid of the flickering scroll bars,15) but there is a workaround for the automatic scroll effect:

  • The bug is triggered by a percentage value of the CSS width property.
  • To get rid of it, you need to define a fixed px width.
  • If you do not want to loose the possibility to use flexible widths for <textarea>, you can get the needed percentage value through the back-door by using min-width and max-width with the same value afterwards. You may use browser specific hacks to hide/overwrite the fixed width from IE6 which is not affected by this bug but does not understand min/max-width.

Example:

textarea {
    /* width for non-IE browsers */
    width: 50%; 
 
    /* width for IE
       NOTE: - "\9" at the end is a CSS hack to address only IE (all versions).
             - "#" in front is a CSS hack to address IE6/7 */
    width: 500px\9; /* fix the bug */
    /* get the needed percentage value in IE7 and IE8 */
    min-width: 50%\9;
    max-width: 50%\9;
    /* get the needed percentage value in IE6 */
    #width: 50%;
}

Hope that helps. :-)

14)
tested on WinXP SP3 32bit
15)
this is thankfully just a minor, “cosmetic” problem

// goQR.me relaunch - new look and more translations for our QR Code generator

My company is proud to present a new, polished version of goQR.me (a QR Code Generator built around our QR Code API):

We already started to implement the new layout and some new features16) two weeks ago, but the most important point – additional languages – was still missing. However: now it is done. goQR.me is available in German, French and English since yesterday. And I am confident we will see more translations soon. Have fun with it… :-)

BTW: The language is also used to guess to “best” target office of the integrated shopping feature. That is why there are so many flavors of English/German.17) Combined with some browser language detection, it is simply a small shop-optimization to provide faster shipping and known currencies in the shop interface.

16)
e.g. the possibility to buy QR Code Business Cards.
17)
e.g. en-gb – why should we offer an UK user to buy something in a US shop when there is also an UK office?

// Google's Webfont Directory and Font API

Right now, you can't use many fonts for common text if you are running a website. The shared font-set available on most operating systems and devices is small and well known: Arial/Helvetica, Times New Roman, and Courier (New). You even should investigate18) good fallback fonts if you are using Georgia, Verdana or Lucida.

But there is light at the end of the tunnel: modern browsers are supporting font loading techniques. The pitfall is that there is no simple way to serve your font-file. Operating systems are using other file formats than browsers and as bonus, even the major browsers are using two different ones:

Additionally, you have to be alerted to legal issues because you are not only using but distributing the fonts. This means even if you buy a license to use a font for doing webgraphics, you may not be allowed to offer it as .eot/.woff file.

This is where the Google Font API comes into play. It offers an easy way to use some new fonts on your website by including only one CSS file served by Google. The API takes care of browser issues and is serving only open source fonts.19) Just read the instructions and start using it.

But let us talk about the downsides:

  • Your visitors will download data from Google, offering usage statistics to them (e.g. via HTTP referrer). It is another jigsaw puzzle piece for Google to know everything about you, your visitors and your website.
  • No matter how smart the API is, your page rendering speed will get slower.
  • Your visitors have to download more data (→ the font file).

But even if the mentioned downsides are show-stoppers for you, you can learn how to use the new opportunities by investigating how the API is doing its job, e.g. to build an own solution without privacy issues.

18)
there is more than MS Windows. Think about *ix, Mac OS, Android, iPhone etc.
19)
since they're open source, they can be used even for print. However, read the license agreement carefully!

// Little known PHP features: calling echo with multiple parameters

First of all, many PHP newbies do not even know that echo is not a function but a language construct. This means, the following two lines of code do the same:

  echo "Hello world\n"; //because echo is NO function, brackets are not needed.
  echo("Hello world\n");

IMHO, you should use the first variant without brackets to signalize that echo is not a function20).

But even experienced developers do not know the possibility to pass more than one parameter - there is no need to concatenate strings with a dot (which may be useful in some situations). The following code does the same three times:

  $str1 = "one";
  $str2 = "two";
  $str3 = "three\n\n";
 
  //newbie style, most overhead because echo is called more often than needed
  echo $str1;
  echo $str2;
  echo $str3;
 
  //common style with concatenated string (on my machines with PHP 5.2,
  //64bit *ix, this is the fastest)
  echo $str1.$str2.$str3;
 
  //little known: pass more than one parameter (on my machines with PHP <5.1,
  //this is the fastest)
  echo $str1, $str2, $str3;

My personal experience/small note about the performance: the more variables are involved + the bigger their data is, the slower is a concatenated string in comparison to passing the vars as parameter. But the difference is getting really small on PHP >=5.2. Additionally, echo is really fast, no matter if you use concatenation or commas. Just prevent unneeded echo calls and everything is fine. :-)

20)
BTW: same with include[_once] and require[_once]

// Links: development

// Links: webdevelopment accessibility

I'm no native speaker (English)
Please let me know if you find any errors (I want to improve my English skills). Thank you!
Recent Comments
QR Code: URL of current page
QR Code: URL of current page start (generated for current page)