PHP: A helper function for rendering calendar table layouts

/**
 * Returns the table layout of a given month as an array of rows.
 * 
 * <p>Padding will be added as necessary.</p>
 *
 * <p>Example: Return value for May 2010</p>
 *
 * <pre>
 * array(
 *     array(null, null, null, null, null,    1,    2),
 *     array(   3,    4,    5,    6,    7,    8,    9),
 *     array(  10,   11,   12,   13,   14,   15,   16),
 *     array(  17,   18,   19,   20,   21,   22,   23),
 *     array(  24,   25,   26,   27,   28,   29,   30),
 *     array(  31, null, null, null, null, null, null)
 * )
 * </pre>
 *
 * @param   int $year         Year to generate the layout of.
 * @param   int $month        Month to generate the layout of.
 * @param   int $firstWeekday Weekday of first column. Works like date('w').
 *                            Defaults to monday.
 * @throws  IllegalArgumentException
 * @author  Marc Ermshaus <marc@ermshaus.org>
 * @version 2010-05-13
 * @example http://ermshaus.org/2010/05/php-a-helper-function-for-rendering-calendar-table-layouts
 * @return  array
 */
function getMonthLayout($year, $month, $firstWeekday = 6)
{
    $year         = (int) $year;
    $month        = (int) $month;
    $firstWeekday = (int) $firstWeekday;
 
    if ($month < 1 || $month > 12) {
        throw new InvalidArgumentException(
                '$month has to be between 1 and 12.');
    }
 
    if ($firstWeekday < 0 || $firstWeekday > 6) {
        throw new InvalidArgumentException(
                '$firstWeekday has to be between 0 and 6.');
    }
 
    $data = array();
 
    $dt = new DateTime($year . '-' . $month . '-01');
 
    $t = $dt->format('t');
    $w = $dt->format('w');
    $w = ($w + $firstWeekday) % 7;
 
    // Add padding values to first row
    if ($w == 0) {
        $row = array();
    } else {
        $row = array_fill(0, $w, null);
    }
 
    for ($i = 1; $i <= $t; $i++) {
        $row[] = $i;
        if (($i + $w) % 7 == 0) {
            $data[] = $row;
            $row = array();
        }
    }
 
    // Add padding values to last row
    $k = (7 - (($t + $w) % 7)) % 7;
 
    if ($k > 0) {
        $row =  array_merge($row, array_fill(0, $k, null));
        $data[] = $row;
    }
 
    return $data;
}

The following example renders all months from the year 2010.

<?php
 
$year  = 2010;
$shift = 6; // Set first column to monday
 
$days = array('SU', 'MO', 'TU', 'WE', 'TH', 'FR', 'SA');
 
// Ring shift weekday names according to $shift parameter
for ($i = 0; $i < $shift; $i++) {
    $popped = array_pop($days);
    array_unshift($days, $popped);
}
 
$date = new DateTime();
 
?>
 
<?php for ($month = 1; $month <= 12; $month++):
 
    $data = getMonthLayout($year, $month, $shift);
    $date->setDate($year, $month, 1);
    echo '<p>' . $date->format('F Y') . '</p>';
?>
 
<table border="1">
<tr>
    <th>
        <?php echo implode('</th><th>', $days); ?>
    </th>
</tr>
<?php foreach ($data as $row): ?>
<tr>
    <?php foreach ($row as $day): ?>
        <?php if ($day == null): ?>
            <td>&nbsp;</td>
        <?php else: ?>
            <td><?php echo $day; ?></td>
        <?php endif; ?>
    <?php endforeach; ?>
</tr>
<?php endforeach; ?>
</table>
 
<?php endfor; ?>

May 13 2010 • language=en programming php snippet

PHP: Using XML as a "lightweight" markup language

I have never been a particular fan of lightweight markup languages that introduce their own highly optimized syntax, like Markdown or Textile. Although they should be sufficient in most cases, some of their parsing rules always seemed a bit unstable and ambiguous to me. I would use them for smaller tasks (user comments or simple content editing), but I never found them to be flexible enough for anything more "sophisticated." My major quarrel has always been extensibility. I wanted to have a markup language that is 100 % extensible in an elegant way that seamlessly integrates with the existing syntax.

For quite some time, my answer was a modified version of BBCode that could be transformed into a tag-based tree structure by a custom parser. Using this approach, I was able to define a basic set of tags which could be extended dynamically by any number of new tags designed for different purposes. For instance, apart from the default HTML markup tags like [h1] oder [ul], I created a plugin that added a [youtube] tag to the set of available tags. This tag took a YouTube video id as an attribute and was transformed into the corresponding code for YouTube video embedding during the rendering routine.

Besides: A different, more business-oriented example would be markup like [article id="12345" mode="preview"] that might add a database-driven info box with a nice product image (à la Amazon) to the output. But for the sake of simplicity, we will stick with examples that are easier to implement.

This system worked quite well, but it always bothered me that I had to add a lot of tags to the markup that would be transformed to HTML output just by replacing the framing BBCode square brackets by HTML's angle ones. That felt rather pointless. So, during the last major overhaul of my website, I gave this some thought and finally, after a lengthy conversation with a friend, it became obvious to me that all I ever wanted as a markup language was indeed a custom version of XHTML. All I had to do was to write HTML in its XML-compliant syntax and add custom XML tags to the markup that would be transformed to standard HTML through rules defined in the parser.

The obvious way to perform the actual transformation from a custom XML markup dialect to HTML is via an XSLT stylesheet. Thankfully, this can be implemented pretty easily, because PHP's DOM extension offers a comprehensive set of classes for working with XML trees, for applying XSL transformations, or for running XPath queries. During the remainder of this article, I will give you a simple example on how it might be done.

Something to work with

Let us start with some rather self-explanatory front-end code (index.php):

<!DOCTYPE html>
 
<html>
 
    <head>
        <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
        <title>XML Markup</title>
    </head>
 
    <body>
 
        <?php
        if (isset($_POST['content'])) {
            $output = render($_POST['content']);
            echo '<pre>' . htmlspecialchars($output) . '</pre>';
            echo $output;
        }
        ?>
 
        <form method="post" action="">
            <textarea name="content" cols="80" rows="20"><?php
            if (isset($_POST['content'])) {
                echo htmlspecialchars($_POST['content']);
            } else {
                echo htmlspecialchars("<h1>Hello World!</h1>\n<p>Content goes here</p>");
            }
            ?></textarea>
            <p><input type="submit" value="Go" /></p>
        </form>
 
    </body>
 
</html>

The code creates a page containing a textarea which holds the custom XML code that should be rendered by clicking the submit button. Once that happens, the submitted XML code string will be transformed to HTML via the render function (which we will add in a second) and displayed both in rendered form and in source code form. For convenience, the XML input is again written into the textarea.

Regarding the XSLT stylesheet, the most simple version does nothing but transform the input to itself, e. g. it does not apply any modifications (transform.xsl):

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
                xmlns:php="http://php.net/xsl">
    <xsl:output method="xml" encoding="UTF-8" indent="yes"/>
 
    <!-- The identity template -->
    <xsl:template match="@*|node()">
        <xsl:copy>
            <xsl:apply-templates select="@*|node()"/>
        </xsl:copy>
    </xsl:template>
 
</xsl:stylesheet>

The XSL rule featured in the example is called the "identity template." As I do not intend to go into the details of XSL, please refer to a different resource if you have trouble understanding this or one of the following stylesheets.

The next step is to add the render function at the top of index.php:

<?php
 
// Everybody loves magic quotes
if (isset($_POST['content']) && get_magic_quotes_gpc()) {
    $_POST['content'] = stripslashes($_POST['content']);
}
 
function render($xmlCode)
{
    // XML documents need one distinct root tag
    $xmlCode = '<root>' . $xmlCode . '</root>';
 
    $xmldoc = new DOMDocument();
    $xmldoc->loadXML($xmlCode);
    $xsldoc = new DOMDocument();
    $xsldoc->load('./transform.xsl');
 
    $proc = new XSLTProcessor();
    $proc->importStyleSheet($xsldoc);
 
    $tmp = $proc->transformToDoc($xmldoc);
 
    // Strip <root> tag and return processed XML
    return substr($tmp->saveXML($tmp->documentElement), 6, -7);
}
 
?><!DOCTYPE html>
...

Fire up the example in a browser, type in some HTML code (or leave the default content), and click the submit button. If your PHP distribution is configured correctly, you should see your input as processed by the XSLT stylesheet. For further explanations on how this code works, please consult the corresponding part of the official PHP documentation.

Simple XSL transformations (<youtube> tag)

Custom tags may now be added to the markup by simply appending corresponding transformation rules to the XSLT stylesheet.

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
                xmlns:php="http://php.net/xsl">
    <xsl:output method="xml" encoding="UTF-8" indent="yes"/>
 
    <!-- YouTube tag -->
    <xsl:template match="youtube">
        <object type="application/x-shockwave-flash"
                width="425"
                height="350"
                data="http://www.youtube.com/v/{@id}"
        >
            <param name="movie"
                   value="http://www.youtube.com/v/{@id}&amp;hl=en&amp;fs=0"
            />
        </object>
    </xsl:template>
 
    <!-- The identity template -->
    <xsl:template match="@*|node()">
        <xsl:copy>
            <xsl:apply-templates select="@*|node()"/>
        </xsl:copy>
    </xsl:template>
 
</xsl:stylesheet>

This rule introduces a <youtube id="xyz" /> tag that gets transformed to the correct HTML code for YouTube video embedding by the XSL processor.

Here is a snippet to try it out:

<h1>YouTube tag test</h1>
 
<p>
    <youtube id="4XpnKHJAok8" />
</p>

It should not be hard to see how powerful XSL transformations are even without additional back-end processing. But it gets even more interesting if XSL rules are connected with server-side PHP callbacks.

XSL transformations using PHP callbacks (<php> tag)

To illustrate the idea of PHP callbacks in XSL, we are going to create a <php> tag that is used to display PHP soure code with proper syntax highlighting.

The additional "PHP tag" XSL rule is rather short. Here is the complete transformation stylesheet:

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
                xmlns:php="http://php.net/xsl">
    <xsl:output method="xml" encoding="UTF-8" indent="yes"/>
 
    <!-- YouTube tag -->
    <xsl:template match="youtube">
        <object type="application/x-shockwave-flash"
                width="425"
                height="350"
                data="http://www.youtube.com/v/{@id}"
        >
            <param name="movie"
                   value="http://www.youtube.com/v/{@id}&amp;hl=en&amp;fs=0"
            />
        </object>
    </xsl:template>
 
    <!-- PHP tag -->
    <xsl:template match="php">
        <pre>
        <xsl:copy-of select="php:function('hl', string(.))" />
        </pre>
    </xsl:template>
 
    <!-- The identity template -->
    <xsl:template match="@*|node()">
        <xsl:copy>
            <xsl:apply-templates select="@*|node()"/>
        </xsl:copy>
    </xsl:template>
 
</xsl:stylesheet>

To allow the execution of PHP functions in the stylesheet, registerPHPFunctions needs to be called after the initialization of the XSLTProcessor instance. Additionally, the callback function, called hl (for "highlight"), needs to be defined.

<?php
 
// Everybody loves magic quotes
if (isset($_POST['content']) && get_magic_quotes_gpc()) {
    $_POST['content'] = stripslashes($_POST['content']);
}
 
function hl($s)
{
    $tmp = new DOMDocument();
    $code = highlight_string($s, true);
    // Ignore non-defined entity issues for now
    $code = str_replace('&nbsp;', ' ', $code);
    $tmp->loadXML($code);
    return $tmp;
}
 
function render($xmlCode)
{
    // XML documents need one distinct root tag
    $xmlCode = '<root>' . $xmlCode . '</root>';
 
    $xmldoc = new DOMDocument();
    $xmldoc->loadXML($xmlCode);
    $xsldoc = new DOMDocument();
    $xsldoc->load('./transform.xsl');
 
    $proc = new XSLTProcessor();
    $proc->registerPHPFunctions(); // NEW
    $proc->importStyleSheet($xsldoc);
 
    $tmp = $proc->transformToDoc($xmldoc);
 
    // Strip <root> tag and return processed XML
    return substr($tmp->saveXML($tmp->documentElement), 6, -7);
}
 
?><!DOCTYPE html>
...

The hl function uses PHP's built-in highlight_string function to do the actual highlighting. The return value has to be a DOM node instead of a simple string because it should be added as proper HTML code to the transformed output. Otherwise, tag delimiters would get escaped and the final output would contain the HTML source code used to do the highlighting instead of the rendered highlighting.

An example snippet:

<php><![CDATA[
<?php
function helloWorld()
{
    // Say hello
    echo 'Hello World!';
}
]]></php>

The example is wrapped with a <![CDATA[ ... ]]> container to be able to use < and > in their non-entity form in the source code. As we need to write valid XML code, this is a necessity.

Conclusion

I am quite satisfied with this approach to a custom markup language, although I admit that writing valid XML code can be a bit of a hassle. Nevertheless, XML is a very well-defined and widespread format that can be processed by a lot of existing tools. The syntax is 100 % non-ambiguous, transformable, seamlessly extensible, and rather easy to learn if your users have basic knowledge of HTML or a comparable markup dialect like BBCode. I also assume that some of the JavaScript-based HTML editors can be extended by custom XML tags so that UI-based editing should be a possibility.

Apr 19 2010 • language=en programming php xml dom

There is only one outbox

Mark Pilgrim writes about the impossibility of separating personal and public content on the Internet. I can feel his pain. Some of the comments are worth a read, too.

Apr 6 2010 • lang=en

Please do not be cynical

From Conan O'Brien's final Tonight Show monologue:

Please do not be cynical. I hate cynicism. For the record, it's my least favorite quality. It doesn't lead anywhere. Nobody in life gets exactly what they thought they were going to get. But if you work really hard, and you're kind, amazing things will happen.

Mar 20 2010 • language=en lifeimprovement quotes

PHP: Adding grouping and extended sorting to SPL's ArrayObject

Regarding the frequency of questions about the topic, one thing many programmers seem to have difficulties with is a technique called "control break". Basically, this is a way of displaying data grouped into visually separated hierarchical sections. Examples might be a list of employees grouped by the starting letter of their family names or a list of blog posts grouped first by year and second by month. Every time the index key of one of the sections changes, a visual mark, like a new heading, should be printed. Those changes are defined as control breaks.

Although it's not really a big deal to write a simple algorithm to achieve the desired effect, I thought it might be desirable to have a generic solution to the problem. So I created a helper class containing static methods that would transform an array of entries (homogeneous arrays of key/value pairs) into a grouped array using the unique values of one of the entries' fields as grouping key. That worked quite well but I am not a big fan of calling static class methods if feasible alternatives exist. A more object-centric approach in which the grouping code could be run as an instance method seemed to me to be the superior solution. Following this thought, I wrote an extended version of ArrayObject from the SPL which I'd like to introduce in this post.

Basic grouping (groupBy)

The class I came up with is named Kaloa_Spl_ArrayObject (you can view or download it here). It's designed to be an unobtrusive addition to ArrayObject. In the current version, the constructor from the parent class is overriden but everything else is left intact. In order to show how it works, I'll define some data that might roughly resemble a list of articles from a blogging application.

$items = array(
    array('year' => 2009, 'month' =>  9, 'title' => 'Hello World!'),
    array('year' => 2009, 'month' =>  9, 'title' => 'At the museum'),
    array('year' => 2009, 'month' =>  9, 'title' => 'Godspeed'),
    array('year' => 2009, 'month' =>  9, 'title' => '2010 Olympics'),
    array('year' => 2010, 'month' =>  1, 'title' => 'Tornado season'),
    array('year' => 2010, 'month' =>  1, 'title' => 'Bailout'),
    array('year' => 2010, 'month' =>  2, 'title' => 'Cheers, Ladies!'),
    array('year' => 2010, 'month' =>  2, 'title' => 'Neglected'),
    array('year' => 2009, 'month' => 11, 'title' => 'Ethics probe'),
    array('year' => 2010, 'month' =>  3, 'title' => 'Commitment to security'),
    array('year' => 2010, 'month' =>  3, 'title' => 'Election'),
    array('year' => 2009, 'month' => 10, 'title' => 'Same-sex couples'),
    array('year' => 2009, 'month' => 10, 'title' => 'Junkyard'),
);

The most interesting new method of Kaloa_Spl_ArrayObject, the grouping method, is groupBy. It takes a callback function as argument which is called once for every entry in the original array. The method might be used to group the example data by year and month.

$obj = new Kaloa_Spl_ArrayObject($items);
 
$obj->groupBy(
    create_function(
        '$item',
        'return array($item["year"], $item["month"]);'
    )
);

The return value of the callback function is the key of the group to which the corresponding entry will be assigned. If an array is returned, it will be treated as a multi-dimensional key which translates to a multi-level grouping.

Displaying the content of $obj using var_dump or print_r will result in an array structured like this:

Kaloa_Spl_ArrayObject Object(
    [2009] => Kaloa_Spl_ArrayObject Object(
        [9]  => Kaloa_Spl_ArrayObject Object(...),
        [11] => Kaloa_Spl_ArrayObject Object(...),
        [10] => Kaloa_Spl_ArrayObject Object(...)
    ),
    [2010] => Kaloa_Spl_ArrayObject Object(
        [1] => Kaloa_Spl_ArrayObject Object(...),
        [2] => Kaloa_Spl_ArrayObject Object(...),
        [3] => Kaloa_Spl_ArrayObject Object(...)
    )
)

The third dimension contains a numbered array with all of the original entries that are part of the corresponding group. For instance, the content of $obj[2009][9] would be an array with the four entries from September 2009:

0 => Kaloa_Spl_ArrayObject(
    'year' => 2009,
    'month' => 9,
    'title' => 'Hello World!'
),
1 => Kaloa_Spl_ArrayObject(
    'year' => 2009,
    'month' => 9,
    'title' => 'At the museum'
),
2 => Kaloa_Spl_ArrayObject(
    'year' => 2009,
    'month' => 9,
    'title' => 'Godspeed'
),
3 => Kaloa_Spl_ArrayObject(
    'year' => 2009,
    'month' => 9,
    'title' => '2010 Olympics'
)

As Kaloa_Spl_ArrayObject subclasses ArrayObject, it's already possible to print the data in the desired fashion using nested foreach-loops.

foreach ($obj as $year => $yearContent) {
    echo '<h1>' . $year . "</h1>\n";
    foreach ($yearContent as $month => $monthContent) {
        echo '  <h2>' . $month . "</h2>\n";
        echo "    <ul>\n";
        foreach ($monthContent as $entry => $entryContent) {
            echo '      <li>' . $entryContent['title'] . "</li>\n";
        }
        echo "    </ul>\n";
    }
}

The resulting HTML code:

<h1>2009</h1>
  <h2>9</h2>
    <ul>
      <li>Hello World!</li>
      <li>At the museum</li>
      <li>Godspeed</li>
      <li>2010 Olympics</li>
    </ul>
  <h2>11</h2>
    <ul>
      <li>Ethics probe</li>
    </ul>
  <h2>10</h2>
    <ul>
      <li>Same-sex couples</li>
      <li>Junkyard</li>
    </ul>
<h1>2010</h1>
  <h2>1</h2>
    <ul>
      <li>Tornado season</li>
      <li>Bailout</li>
    </ul>
  <h2>2</h2>
    <ul>
      <li>Cheers, Ladies!</li>
      <li>Neglected</li>
    </ul>
  <h2>3</h2>
    <ul>
      <li>Commitment to security</li>
      <li>Election</li>
    </ul>

Basically, that's all there is to it.

Advanced grouping

In some cases, it might be useful to modify entries before they are added to the resulting data structure. This can be achieved by simply editing or removing fields from the argument passed to the callback function. All arguments, including scalar values, are passed by reference.

This grouping function will remove the fields "year" and "month" from all entries of the resulting array and will change the content of the "title" field to all uppercase letters.

$obj->groupBy(
    create_function(
        '$item',
        '$ret = array($item["year"], $item["month"]);
         unset($item["year"]);
         unset($item["month"]);
         $item["title"] = strtoupper($item["title"]);
         return $ret;'
    )
);

An example using scalar values that will be grouped by the first letter and changed to uppercase:

$items = array('Carl', 'Susan', 'Cindy', 'Peter', 'Steve', 'Patricia', 'Sam');
 
$obj = new Kaloa_Spl_ArrayObject($items);
 
$obj->groupBy(
    create_function(
        '$item',
        '$item = strtoupper($item);
         return substr($item, 0, 1);'
    )
);
 
var_dump($obj);

Output:

object(Kaloa_Spl_ArrayObject)#1 (3) {
  ["C"]=>
  object(Kaloa_Spl_ArrayObject)#4 (2) {
    [0]=>
    string(4) "CARL"
    [1]=>
    string(5) "CINDY"
  }
  ["S"]=>
  object(Kaloa_Spl_ArrayObject)#5 (3) {
    [0]=>
    string(5) "SUSAN"
    [1]=>
    string(5) "STEVE"
    [2]=>
    string(3) "SAM"
  }
  ["P"]=>
  object(Kaloa_Spl_ArrayObject)#6 (2) {
    [0]=>
    string(5) "PETER"
    [1]=>
    string(8) "PATRICIA"
  }
}

Sorting (usort, usortm, uasortm, uksortm)

By now, it might have become apparent that the groupBy method doesn't sort the resulting array in any way. Therefore, I made a second major addition to ArrayObject by adding more sophisticated sorting functionality that is able to realign one or more dimensions of the array. All three multi-dimensional sorting methods are based on the different flavours of PHP's built-in usort function. They each take sorting criteria specified by an anonymous function or an array of anonymous functions as arguments.

Here is an example to illustrate the usage. It works with the data defined in the "Basic grouping" section.

$obj->groupBy(
    create_function(    // Group by year and month
        '$item',
        'return array($item["year"], $item["month"]);'
    )
)->uksortm(
    array(
        create_function(    // Order first dimension descending
            '$a, $b',
            'return $a < $b;'
        ),
        create_function(    // Order second dimension ascending
            '$a, $b',
            'return $a > $b;'
        )
    )
)->usortm(
    array(
        null,    // Skip first and second dimensions, only realign third
        null,    //  (descending by length of an entry's title)
        create_function(
            '$a, $b',
            'return strlen($a["title"]) < strlen($b["title"]);'
        )
    )
);

This notation uses method chaining in order to hint at the fact that I implemented a fluent interface for all new methods (with the exception of the usort method which I threw in because it was the only one missing). This might be split into three parts starting with $obj->, of course.

Besides the groupBy call, there are calls to both uksortm and usortm because the first two dimensions (years and months) have to be sorted by key whereas the third one (the entries) should be sorted by value. (By the way: usortm might be exchanged for uasortm here as well-formed keys are not an issue when iterating the array using foreach.) The differences between all of the usort-like functions are explained in the PHP documentation.

Each of the u*sortm ("m" standing for "multi-dimensional") methods recursively applies the passed functions to the corresponding dimension of the array. From an array of three functions, the first one would be used to sort the years (first dimension), the second one to sort the months (second dimension) and the third one to sort the entries (third dimension). If no function is needed for a specific dimension, null can be passed and the dimension is skipped.

Further documentation about the class may be found in the inline DocBlock comments of the source file. If you try it out and have questions or any remarks or bug reports, please contact me.

Mar 10 2010 • language=en programming php spl arrayobject

Recent work: Meller Tafel e.V.

Page design, CMS integration

Mar 4 2010 • frontpage portfolio

Regina Spektor - Us

»Us« by Regina Spektor. She has quite a voice.

Jan 9 2010 • music language=en type=link youtube video reginaspektor

Reading list 2010

January

  • Maria Barbal: »Wie ein Stein im Geröll«
  • James Jones: »The Thin Red Line«

Jan 9 2010 • type=post language=en 2010 readinglist books lists

Data liberation at Google

This is a really good idea (thx Tim):

The Data Liberation Front is an engineering team at Google whose singular goal is to make it easier for users to move their data in and out of Google products. We do this because we believe that you should be able to export any data that you create in (or import into) a product. We help and consult other engineering teams within Google on how to »liberate« their products.

Sep 15 2009 • language=en type=link thecloud google freedom

Layer 8

Layer 8 is Internet jargon used to refer to the »user« or »political« layer as an extension of the OSI model of computer networking.

Sep 11 2009 • language=en programming type=link layer8

Cover versions

»Classic records lost in time and format, re-emerged as Pelican books. Just for fun.« A set on flickr.

Sep 10 2009 • language=en type=link photography flickr remix pelicanbooks

Introduction to PHP frameworks

Some time ago, IBM published a five part series of articles introducing three major PHP frameworks: Zend, Symfony and CakePHP. The information will be outdated but it might be a good read to get a feeling for the general architecture of each of the frameworks.

Sep 9 2009 • language=en programming php type=link

Unendlicher Spaß -- Infinite Jest

Within six years, David Foster Wallace's »Infinite Jest« has been translated into German. A quote from the publisher, Helge Malchow (KiWi): »It's not in the centre of our revenue expectations.«

- The Amazon page shows the cover (of course). I have mixed feelings about it: The overall idea is okay, though nothing special, but the typography has been done very carelessly. How many surely unintentional (?) words can you make out? (Update: This does look ugly, though.)

- An interview with the translator, Ulrich Blumenbach (in German). (thx David)

Sep 8 2009 • language=en books type=link davidfosterwallace infinitejest unendlicherspaß

The quick brown fox jumps over the lazy dog

I am probably the last one to link this. (via praegnanz)

Aug 1 2009 • language=en humour type=link youtube video typography

Programming cheat sheets

Short syntax reference guides like »Javascript in Ten Minutes« are a pretty useful idea. I quite often think: »Yes, I know how <basic-programming-subject> works, just tell me where I have to put which brackets!«

Jul 24 2009 • language=en programming type=link javascript cheatsheet

Ironic process theory

Wikipedia:

Ironic processing is the psychological process whereby an individual's deliberate attempts to suppress or avoid certain thoughts (thought suppression) render those thoughts more persistent. A classic example is Fyodor Dostoevsky's quote from Winter notes on summer impressions: »Try to pose for yourself this task: not to think of a polar bear, and you will see that the cursed thing will come to mind every minute.«

Jul 24 2009 • language=en type=link psychology

Variations of Incomplete Open Cubes

Another great find by Today and Tomorrow: Sol LeWitt's »Variations of Incomplete Open Cubes«.

Jul 23 2009 • language=en art type=link sollewitt

Alex Jones/The Entertainer mashup

There are many reasons why video mashups were invented. This is one of them.

Update: Here's another good one.The guy with the short temper is this Alex Jones by the way.

Jul 22 2009 • language=en type=link video mashup alexjones

Nami

»Nami«, Japanese for wave, is the title of a photo book by Syoin Kajii. Today and tomorrow shows five beautiful examples.

Jul 20 2009 • language=en art type=link japan nami syoinkajii

Baby photos could help to get a lost wallet returned

From a Times Online article about a study by psychologist Richard Wiseman who »lost« a few hundred wallets with different or no pictures in them:

When faced with the photograph of the baby people were far more likely to send the wallet back, the study found. In fact, only one in ten were hard-hearted enough not to do so. With no picture to tug at the emotions, just one in seven were sent back.

(via 3qd)

Jul 18 2009 • language=en type=link psychology

Broken windows theory

The »broken windows« theory of urban sociology states that people are significantly less likely to break into houses or throw litter on the sidewalk if everything in the neighbourhood is clean and orderly. As soon as there is one broken window or a piece of litter somewhere, things start to get worse. Results from the theory led to New York City's »zero tolerance« strategy of crime prevention in the 1990's that most certainly helped to drop the crime rates consecutively for years.

The theory is probably able to explain comment spam on the Internet, too.

Jul 17 2009 • language=en type=link psychology brokenwindowstheory urbanplanning

MANtage

Don't look now, there's Luke beatin' Mario Bros. – No warps!

This video by Barats & Bereta has got balls.

OT: Why didn't I post for so long, you wonder? Why didn't I read more than five pages of »Infinite Jest«? Good questions.

By the way, I just googled »all good questions« (to check the grammar) and guess what search result #3 is:

Infinite Summer: Is Infinite Jest a New Media Object?

I swear to God, this is purely coincidental. And, come to think about it, somewhat spooky. Guess I'll better start reading.

Jul 17 2009 • language=en type=link video infinitesummer comedy baratsandbereta

Statistics vs. Iran election

From the Washington Post article »The Devil Is in the Digits« about a statistical analysis of the Iran election results:

The numbers look suspicious. We find too many 7s and not enough 5s in the last digit. We expect each digit (0, 1, 2, and so on) to appear at the end of 10 percent of the vote counts. But in Iran's provincial results, the digit 7 appears 17 percent of the time, and only 4 percent of the results end in the number 5. Two such departures from the average – a spike of 17 percent or more in one digit and a drop to 4 percent or less in another – are extremely unlikely. Fewer than four in a hundred non-fraudulent elections would produce such numbers.

Apart from that, there seem to be too many adjacent digits (like 23 or 34, but not 61) in the data so that, as the article concludes, it becomes very likely that the figures have been tampered with if both observations are taken together.

I have no idea whether the interpretation of the data is correct, but it always amazes me what seems to be possible using statistics.

Jun 27 2009 • language=en type=link statistics iran

Infinite Summer kicks off

Infinite Summer, the collective David Foster Wallace / »Infinite Jest« reading attempt, started... yesterday – which means I'm already one day behind which is not good. Anyway, they got Kottke to write an intro post. No surprises there.

Having failed every single scheduled reading event I participated in (half a dozen or so), I am eager to sit this one through. (Yes, I might be kidding.)

They say it'll be fun.

Jun 22 2009 • language=en type=link infinitesummer

Fever released

I have once again madly fallen in love with Shaun Inman. He is a great designer. He is an even better coder. (I wish I could be so pragmatic as to write software with a lower reqs bound of PHP 4.2.3+ and MySQL 3.23+.) He has a sexy voice. – In one word, Shaun Inman is completely overpowered. So go watch the screencast and find yourself a fever.

Okay, to be honest: This is a tool for power users that, as all self-hosted aggregators do, more or less depends on access to cron to update your feeds. So figure it out on your own.

Jun 19 2009 • shauninman language=en type=link fever

Facebook profile URLs

So, Facebook is going to land on the moon in a few hours.

Dave Winer:

But the thing that strikes me as weirdest of all is that after years of insisting that people only use their real names on Facebook, they've now set up a system where it will be virtually impossible for most people to do that, even if they want to.

If I cared more about Facebook, I'd have more to say about this.

I wish this period of the Internet would end, it's so exactly like AOL. I've seen this show before, I know how it ends. Only this time there won't be a Time-Warner to cash them out.

Anil Dash:

June 13, 12:15am: A first wave of »It's alive! Go get your name!« posts go up on various technology blogs, noting that the service is running a little bit slow. None of these posts mention that you can also register a real domain name that you can own, instead of just having another URL on Facebook.

Jun 12 2009 • language=en type=link facebook rants

Transparency

Jun 10 2009 • language=en art type=link photography khristianmendoza

The Interface of a Cheeseburger

The Information Architects like cheeseburgers:

All things have an interface. Shaping interfaces is shaping the character of things. The brand is what transports the character of things. When looking at McDonalds, iPod, Nintendo DS it becomes quite obvious that the interface is the brand.

Jun 9 2009 • language=en type=link design cheeseburgers

AAAAAAAAA!

AAAAAAAAA! AA AA AAAAAAA AA AAAAAAAAAAAA AAAAA AAA AAAAAA A. A AAAA AAAA AA AAAAA AAA AAAAAAA AAAA, AAA AAAA AAA »A« (AA AAA AAAAAAAA).

Jun 8 2009 • language=en type=link aaaaaaaa

Jung Typology Test

I just did the Jung Typology Test and ended up as an ENFP (Extraversion, iNtuition, Feeling, Perception; more here and here). They say that's like Mark Twain, Charles Dickens, Stephen Spielberg or Joan Baez – all of which are/were great computer scientists. The outcome is not a big surprise if you think about it, but I'm kind of surprised nonetheless. Not that I care about this kind of stuff, but GO TAKE THE TEST, it's awesome. (Sorry, trying to stay in character or something.)

Jun 7 2009 • language=en lifeimprovement type=link psychology jungtypologytest