DOTVOID.COM
Latest articles
- Aspect Oriented Programming and javascript
- Remote Scripting (AJAX) framework
- Awstats with virtual hosts on Apache
- Remote scripting with SRSS
- MySQL 4, Apache 1.3 and PHP 4.3 on Solaris x86
- ODBC with PHP on RedHat 7.3
- PHP5 Overview
- Putting XSL and PHP to work
- Remote scripting with javascript
- Quick and dirty XSLT Tutorial
External links
Other stuff
Custom Search Engine Marketing
Archivospc - Download from a collection of tested, rated and reviewed freeware, shareware and others in spanish.
Software Australia
Research papers - Superiorpapers.com is a high-class educational advisory service which delivers high-level consultations on essay writing techniques, editing, and referencing.
Eating Disorder Treatment
| Specter AB |
| Proact |
| Capgemini |
| RIW Software Technology AB |
| SweSeek |
Projects I work on
översikt.se
Swedish TV listings
Svenska stadsportaler
TV-guide på svenska
Mesh - webbutveckling
Nordica Rentals, Marbella
Claddagh jewellers
Gunnel's Zuecos
Setting up a development environment with apache-2.2.6
Written by Danne Lundqvist - 2007-11-20 00:16
I recently bought a new laptop as my new development box. A nice 17" screen with 1920*1200. So now I was to setup a PHP development environment for all the projects I'm working on. I downloaded Apache 2.2.6, PHP 5.2.4 and MySQL 5.0.45. I compiled and installed them and finally added a few virtual hosts. None of the vhosts worked. They all gave me
"client denied by server configuration: ..."
I had missed that apache now ships with a slightly different configuration for the / directory to
<Directory />
Options FollowSymLinks
AllowOverride None
Order deny,allow
Deny from all
</Directory>
The Order deny,allow and Deny from all makes the virtual hosts inaccessible by default. When I googled it I saw many forum and blog posts asking about this issue.
To fix it you can either remove/change the lines. But that is probably not a good idea. Better is to explicitly specify which directories that apache are allowed to serve. So for me and my project setup it was as simple as adding a new directory directive opening up my www directories for all the projects.
<Directory />
Options FollowSymLinks
AllowOverride None
Order deny,allow
Deny from all
</Directory>
<Directory "/home/myusername/Projects/*/www">
Order deny,allow
Allow from all
</Directory>
I hope this short explanation helps a few people looking for a solution to the problem.
read full post
0 comments on this post
International PHP conference in Frankfurt 2007
Written by Danne Lundqvist - 2007-11-05 12:27
Yesterday was the first day of the International PHP Conference. I listened to Lars Jankowfsky in his session "Practising Agile Development". Altough different methodoligies were mentioned it was mainly a one day session on how Extreme programming works. The session had a good mix of fun och seriousness. One of the reasons I wanted to go to Frankfurt this year was the mix between technical and non technical sessions. I have to say that Lars one day session on XP was a very good start. As always me and others that do not use xdebug and unit tests frequently got a lot of well deserved bashing...
"Using your brain while developing is really helpful" - Lars Jankowfsky. Maybe I should stop the bad habit of lazy coding while watching TV...
One thing that makes me happy is that they have added a session on Zend Framework. I look forward to that as I have begun to rely on Zend Framework quite a lot.
IPC 2007 and Ajax In Action
Lars Jankowfsky during his session
read full post
0 comments on this post
Reordering nested sets using PHP and Javascript
Written by Danne Lundqvist - 2007-09-14 12:29
The adjancency method
Representing a tree of nodes, for example product categories, in a relational database is not hard. The most common way of doing it is to store a parentid with each node. This is also known as the adjacency list model. It is sometimes also referred to as the recursive model. Whatever the name it is easy to grasp. It is very simple to insert and move nodes around but it is not an optimal solution if you often select the whole tree from the database for displaying on a web page as you need to recursively select all children of nodes.
The nested set model
A much better solution is the nested set model. In this model trees are represented as nested sets. Instead of using a parentid you have a left and right value for each node expressing the relationship to other nodes. A tree of nodes can look like this.
34
|
+--36
| |
| +--46
| |
| +--47
|
+--38
|
+--39
The same data can be viewed more graphically as nested sets. This is also the way they are stored in the database. Notice how the left and right values are numbered in order from the outermost left to the outermost right.
id:34
+----------------------------------------------------+
| id:36 id:38 |
| +------------------------+ +--------------+ |
| | id:46 id:47 | | id:39 | |
| | +-----+ +-----+ | | +------+ | |
1| 2| 3| |4 5| |6 |7 8| 9| |10 |11 |12
| | +-----+ +-----+ | | +------+ | |
| +------------------------+ +--------------+ |
+----------------------------------------------------+
In the database this is stored as in the following table.
+----+-----+-----+
| id | lft | rgt |
+----+-----+-----+
| 34 | 1 | 12 |
| 36 | 2 | 7 |
| 46 | 3 | 4 |
| 47 | 5 | 6 |
| 38 | 8 | 11 |
| 39 | 9 | 10 |
+----+-----+-----+
This allow you to select the full tree with only one select statement. Normally you select the full list of nodes including the depth of each node as shown below in the small table containing id and depth. It is then easy to loop over the data in PHP to produce a nice tree in HTML/CSS.
The data below can be displayed as the the tree on right. The depth is in parenthesis.
+----+-------+ 34 (0)
| id | depth | |
+----+-------+ +--36 (1)
| 34 | 0 | | |
| 36 | 1 | | +--46 (2)
| 46 | 2 | | |
| 47 | 2 | | +--47 (2)
| 38 | 1 | |
| 39 | 2 | +--38 (1)
+----+-------+ |
+--39 (2)
Here is a more thorough article on how you use MySQL with nested sets.
On to the problem
Last night I was working on an application that display a full tree where the user must be able to to drag and drop nodes to reorder the tree. The problem is that it is much more difficult to insert or reorder the tree using the nested set model.
For the actual html I produced nested ordered lists using the OL and LI html element so that it was easy to use with the excellent MooTree script based on MooTools. (It does seem to have trouble with the latest version of MooTools though.) After reordering the structure it was easy to extract the tree list including the depth of each node. I sent this to the PHP backend to be handled there. The text data I sent to the PHP backend then look like below.
34,0
36,1
46,2
47,2
38,1
39,2
As you can see it looks exactly like the data I selected from the database previously. So I had to create a function in PHP that took this indata and produced a list of nodes with the correct left and right values. This list is then looped over to update all the nodes in the database.
function depth2nestedset($data)
{
$lines = explode("\n", $data);
$rows = array();
$stack = array();
$lft = 0; // Left value
$rgt = 0; // Right value
$plvl = -1; // Previous node level
foreach($lines as $line) {
list($id, $lvl) = explode(',', $line);
// Skip empty/faulty lines
if (trim($id) == '') {
continue();
}
if ($lvl > $plvl) {
$lft++;
$rgt = 0;
array_push($stack, $id);
}
else if ($lvl == $plvl) {
$pid = array_pop($stack);
$rows[$pid][2] = $rows[$pid][1] + 1;
$lft = $lft + 2;
$rgt = 0;
array_push($stack, $id);
}
else {
$lft = $lft + ($plvl - $lvl) + 2;
$diff = $plvl - $lvl + 1;
for($n = 0; $n < $diff; $n++) {
$pid = array_pop($stack);
$rows[$pid][2] = $lft - $diff + $n;
}
array_push($stack, $id);
}
$rows[$id] = array($id, $lft, $rgt);
$plvl = $lvl;
}
$plvl++;
$cnt = count($rows) * 2;
$leftovers = count($stack);
for($n = 0; $n < $leftovers; $n++) {
$pid = array_pop($stack);
$rows[$pid][2] = $cnt - $plvl-- + $n;
}
return $rows;
}
The resulting associated array that is returned looks like below.
Array
(
[34] => Array
(
[0] => 34
[1] => 1
[2] => 12
)
[36] => Array
(
[0] => 36
[1] => 2
[2] => 7
)
[46] => Array
(
[0] => 46
[1] => 3
[2] => 4
)
[47] => Array
(
[0] => 47
[1] => 5
[2] => 6
)
[38] => Array
(
[0] => 38
[1] => 8
[2] => 11
)
[39] => Array
(
[0] => 39
[1] => 9
[2] => 10
)
)
That makes the circle complete. From left/right values in the database to a node tree based on depths that is easy to manipulate in html and then back to left/right values. Hopefully this makes sense. Do you have a better solution or more examples on applications that do this I would love to hear about it.
read full post
0 comments on this post
PHP Conference
Written by Danne Lundqvist - 2007-09-05 16:28
I have been to the International PHP Conference in Frankfurt a couple of times. Last year I didn't go as the quality of the conference 2005 wasn't what I think one should expect.
This year seems to be different though. A whole slew of interesting sessions on PHP mixed with a few sessions on agile development. Sounds just about perfect to me. I am especially interested in the one PHP 6 session as I have not had the time to follow what is happening in regards to next major version of PHP. I'm definitely going to Frankfurt this November. There are still too many sessions in German if you ask me - but I guess there are quite a few Germans going to the conference.
read full post
0 comments on this post
Generating Excel files with PHP
Written by Danne Lundqvist - 2007-07-10 11:10
I'm on this project at work where we need to create an excel file and send it via email or ftp to a recipient. The normal answer to this is to create a comma separated file and name it .xls and excel will work it out. However, that only works if you open it directly through an http request and are able to set the http headers correctly. I'm not going to elaborate on the requirements but they want an excel file generated and sent to them. They don't want to and can't download the file themselves.
Naturally I went to the almighty Google for the answer. There are a few excel writers written out there. I found a tutorial on using PEAR Spreadsheet_Excel_Writer and an MS-Excel Stream Handler class to mention two solutions.
I found one piece of code floating around numerous places that I fell for. I am not sure about the original source for this code though. Extremely simple.
function xlsBOF() {
return pack("ssssss", 0x809, 0x8, 0x0, 0x10, 0x0, 0x0);
}
function xlsEOF() {
return pack("ss", 0x0A, 0x00);
}
function xlsWriteNumber($Row, $Col, $Value) {
return pack("sssss", 0x203, 14, $Row, $Col, 0x0)
.pack("d", $Value);
}
function xlsWriteLabel($Row, $Col, $Value ) {
$L = strlen($Value);
return pack("ssssss", 0x204, 8 + $L, $Row, $Col, 0x0, $L)
.$Value;
}
I liked it because it did what I wanted with a minimum of fuss. I was happy until I realized I don't understand it enough to be able to set the character set. Right now question marks appear in the texts instead of national Swedish characters as å, ä and ö.
read full post
0 comments on this post
SVN hosting options
Written by Danne Lundqvist - 2007-05-10 09:48
At work we still use CVS. We even have PVCS sitting on an old Tru64 machine actively used in one last project that hasn't converted to CVS. I have looked at subversion/SVN and I use it for a few smaller projects. I host the repositories myself which is not the right option in every situation. And for some projects it would sometimes be better to host them somewhere else. This is especially true for many open source projects. Yesterday I found a good subversion hosting overview over at Snook.ca.
However, before I decided to host a software project somewhere else I would thoroughly investigate how easy it is to export the whole repository with version history intact.
read full post
0 comments on this post
PostNuke and PHP 5
Written by Danne Lundqvist - 2007-05-09 01:46
In an earlier blog post I wrote about how I think companies, and open
source projects, will loose business if they don't start the
upgrade path to PHP 5. With PHP 6 in the works it is only a matter of
time before most people will consider PHP 4 applications legacy. Now
that there is a clear message that no new versions of PHP 4 will be
released after December 31st, 2007 this will go much faster.
In the long run I think that it is not enough to just be PHP 5 friendly while staying backwards compatible.
There is so much added benefit in using PHP 5 and probably PHP 6 later
on that projects not taking advantage of new features will eventually
be left behind. New developers will more often than not start with PHP
5 when learning the language. I think many open source projects will
have difficulties in attracting new developers if they don't actively
promote using new features in the language. Some projects will most likely fork. A fork is not always a good solution with all the problems and politics that usually comes with it. It would be stupid not to
prepare for new PHP versions in advance and avoid all the problems.
The other day I had a conversation with an industry collegue from back home working on a poker site using the PostNuke CMS.
He is not very technical but still has many itches to scratch. Most of
the issues he aired was mostly due to a lack of specific functionality
he needed though. He was forced to create many
pages, for example a listing of poker sites, manually. This he admitted might just be due to the fact that PostNuke is the wrong system for what he is doing. We had a very interesting discussion regarding PHP CMS applications and functionality.
But after our discussion and after reading "The state of the PHP5 CMS..." by Lukas Smith
I thought it would be interesting to have a closer look at PostNuke,
being a well known and widely used PHP application. If I searched google
for "drop support for php 4" I get about 11 million hits. I guess a lot of the hits aren't really relevant but still. If I add the word "PostNuke"
to the search I can't find one relevant hit in the search result. So
what is a project as PostNuke doing, if anything, with PHP 5?
read full post
0 comments on this post
Problem sending mail with PHP mail function
Written by Danne Lundqvist - 2007-04-17 11:47
Occasionally I have had trouble sending emails using the builtin mail() function in PHP. Sometimes emails never reached their intended destination. Naturally I have assumed that there might be a problem with some spam filters used. However, lazy as I am, I have not given it a second thought. Instead I have used a PHP class that allows me to send emails using a remote smtp server using an account on that server. This has been a good solution for my setup anyways. A few days ago a friend of mine was asked to investigate the very same problem for a client.
The problem seems to be that PHP use the ini directive sendmail_from to set the from email address in the SMTP protocol. If this is not correctly set, or if it does not match the from header in the email headers, the email is caught by spam protection software.
The simplest solution is to set the directive during execution:
ini_set("sendmail_from", $email_from);
$headers = "From: $email_from";
mail($to, $subject, $message, $headers);
The problem as well as the solution was already known by others. The operating system this time was windows and I know there are differences in the implementation between the windows and linux version of mail(). I am not sure if the problem exist on both platforms.
Still I bet there are lots of people out there with this problem without them knowing it. It could be a good idea to include more detailed information about this ini entry and its implications in the actual mail() documentation. Sending emails from web pages is, to say the least, a very common task.
read full post
0 comments on this post
The nested set model - hierarchical data in MySQL
Written by Danne Lundqvist - 2007-03-20 01:37
I'm working on a small PHP project handling data which is organized in a hierarchical fashion. This is a common task and I have done it before creating forums and the like. This time no different than any other I was swearing over the rather ugly and most of all inefficient code needed for fetching a full hierarchy from the database and displaying it nicely. Vaguely I remembered reading something about a rather different approach.
Searching Google I finally found a MySQL article on the nested set model which is a lot more efficient. The algorigthm basically skips the whole parent/child relationship between nodes. Instead you work with what is best described as "neighbouring" nodes. This allows you to retrieve a fully ordered hierarchical tree, including the level/depth of each node in the tree, using only one simple sql statement.
Those that are not familiar with the nested set model should definitely read the article.
read full post
0 comments on this post
Zend Feed for a Swedish web development blog aggregator
Written by Danne Lundqvist - 2007-03-11 20:09
Lately I have begun to get more and more annoyed with my feed reader. I use a simple feed reader which lack most features except for subscribing to and reading feeds. The one thing that annoys me the most is that it can't aggregate several feeds into one feed. Yesterday I finally decided to scratch that itch.
What I want to aggregate are Swedish web development and web entrepeneur blogs. I like the planet-planet concept that for example planet-php use. (Though I don't think planet-php use python...) Conveniently I had this idn domain, översikt.se, lying around which I haven't used up until now. As is normal nowadays (for me at least) I used Zend Framework to build the site. It was the first time I used Zend_Feed class. I works like a charm.
The whole website logic (both model and controller) is about 200 lines of code. And the main logic of fetching the feeds are really nice and short.
foreach($urls as $url) {
try {
$feed = Zend_Feed::import($url['feedurl']);
}
catch(PDOException $ex) {
error_log($ex->getMessage());
continue;
}
$feedTitle = $feed->title;
$feedLink = $feed->link;
$title = '';
$link = '';
$desc = '';
$pub = '';
foreach ($feed as $item) {
if (is_a($feed, "Zend_Feed_Rss")) {
$title = $item->title();
$link = $item->link();
$desc = $item->description();
$publ = ($item->pubDate()) ? $item->pubDate() : $item->date();
}
else if(is_a($feed, "Zend_Feed_Atom")) {
$title = $item->title();
$link = $item->link('alternate');
$desc = $item->content();
$publ = ($item->issued()) ? $item->issued() : $item->published();
}
else {
error_log("Feed <$feedid> is an unsupported format");
continue;
}
// Parse and normalize date and check if new
$time = strtotime($publ);
$publ = date("c", $time);
// Execute the previously prepared sql insert statement
$result = $sti->execute(array(
'feedid' => $url['feedid'],
'title' => $title,
'link' => $link,
'publ' => $publ,
'desc' => $desc));
}
}I skipped database exception and error handing in the above code to make it even more readable. Zend_Feed have failed me only once when trying to read and parse an old weird rss format. Wonderful.
(For those that don't have browsers that support idn-domains I linked to the punycode variant of the domain name översikt.se, www.xn--versikt-80a.se, above. But mostly because my damn editor refuses to use the Swedish letter "ö" in the href attribute.)
read full post
2 comments on this post
Losing market share with PHP 4
Written by Danne Lundqvist - 2007-02-13 10:34
It looks like PHP 4 is still going strong as a worried Clay Loveless write on his blog. Ivo Jansch have an older article, PHP 5 adoption - a summary, on the subject. It is true that the PHP 5 uptake has been slow. Many internet service providers as well as many developers are reluctant to switch. This is probably, as others have stated, a circular dependency. When lots of popular open source applications still only work with PHP 4, ISP:s are reluctant to upgrade. As ISP:s are reluctant to upgrade the popular open source projects are hesitant to upgrade. I still think the wrong people are worried. Still PHP 5 is increasing it's share and finally the day will come when version 4 will be considered legacy. Hopefully before PHP 6 is here but not necessarily.
PHP 5 is not all about objects as some developers seem to think. New features in the language itself as well as modern frameworks like Zend Framework written completely in PHP 5 makes it easier and faster to produce quality software. Even though people - surprisingly - think that todays situation is set in stone and that things never will change they will. Popular open source applications written in PHP 4 will be overrun by new fresh applications that fully make use of all the new features. These applications are developed faster with better quality. If the service providers do not upgrade they will soon not be able to attract new customers. Eventually they will even start losing customers.
So if open source projects want to stay competetive, the project leaders - if any - would do good in thinking hard on switching before it is too late. The ISP:s would also do good in planning ahead. The new fresh applications of tomorrow (and today) won't work on their servers. If they want the new customers they need to adopt PHP 5 soon. I think that the early adopters, that struggle today, may soon be the winners.
read full post
0 comments on this post
Parsing the user agent string using PHP
Written by Danne Lundqvist - 2007-01-29 15:26
Recently I experimented a bit with an Apache log file analyzer written in PHP. It's not all that difficult were it not for trying to parse the browser, or user agent, string. There are in fact two RFC documents, RFC 1945 and RFC 2068, that define how a user agent string should be written. Still many does not adhere to these standards and many write the interesting details in the comment field only. There is a good article at texSoft.it on how to identify the user agent and I have tried to steal bits and pieces of my time to implement the algorithm.
For my purposes I don't care much for the operating system details. This is the result so far. I'm still not
very satisfied but I thought maybe other people might be interested and maybe help out. Maybe there is something better out there? I'd be happy for any input.
function parseUserAgent($ua)
{
$userAgent = array();
$agent = $ua;
$products = array();
$pattern = "([^/[:space:]]*)" . "(/([^[:space:]]*))?"
."([[:space:]]*\[[a-zA-Z][a-zA-Z]\])?" . "[[:space:]]*"
."(\\((([^()]|(\\([^()]*\\)))*)\\))?" . "[[:space:]]*";
while( strlen($agent) > 0 )
{
if ($l = ereg($pattern, $agent, $a))
{
// product, version, comment
array_push($products, array($a[1], // Product
$a[3], // Version
$a[6])); // Comment
$agent = substr($agent, $l);
}
else
{
$agent = "";
}
}
// Directly catch these
foreach($products as $product)
{
switch($product[0])
{
case 'Firefox':
case 'Netscape':
case 'Safari':
case 'Camino':
case 'Mosaic':
case 'Galeon':
case 'Opera':
$userAgent[0] = $product[0];
$userAgent[1] = $product[1];
break;
}
}
if (count($userAgent) == 0)
{
// Mozilla compatible (MSIE, konqueror, etc)
if ($products[0][0] == 'Mozilla' &&
!strncmp($products[0][2], 'compatible;', 11))
{
$userAgent = array();
if ($cl = ereg("compatible; ([^ ]*)[ /]([^;]*).*",
$products[0][2], $ca))
{
$userAgent[0] = $ca[1];
$userAgent[1] = $ca[2];
}
else
{
$userAgent[0] = $products[0][0];
$userAgent[1] = $products[0][1];
}
}
else
{
$userAgent = array();
$userAgent[0] = $products[0][0];
$userAgent[1] = $products[0][1];
}
}
return $userAgent;
}
read full post
0 comments on this post
PHP 5.2 ajaxified
Written by Danne Lundqvist - 2006-11-28 01:07
PHP 5.2.0 was released a few weeks ago. Apart from the usual bigger, better badder there are two small additions that I think are worth mentioning.
- A new extension for JSON decoding and encoding enabled by default.
- Hooks for tracking file uploads.
These features aren't competing for the heavy weight title in the release notes. Still, having these implemented in PHP makes it a lot easier to develop modern, more responsive, web based applications. JSON encoding have never been very hard but it makes sense to have native support in PHP. I have not tested the file uploads yet but being able to correctly display progress bars when uploading large files is definitely important when working with web applications.
read full post
0 comments on this post
New help desk application using Zend Framework
Written by Danne Lundqvist - 2006-11-03 01:36
Every now and then I sit down to take a closer look on various PHP frameworks to see if it is something I would want to use. For some reason I have never actually used any of the frameworks I have investigated. Too stubborn I guess. A while ago, when I was working on an old web application, I realized I was spending time on way too many things that was not really part of the application logic. Not very productive at all.
I decided that it was time to really make the effort and test a framework in a real project. I had a look around and decided to use the brand new Zend Framework as the base for a hosted help desk solution. I need a help desk solution myself to handle customer support in my company and fail to find something I like. It seems help desk applications are either to complicated (packed with CRM, CM and help desk features), or just too ugly (in my opinion). So all in all a perfect project that would fill a real need.
Why Zend Framework over more mature frameworks then? It is still brand new and very much in development. Zend Framework Preview 0.2.0 was released only a couple of days ago. The reason I chose this framework over others was first of all simplicity. But no less important is the fact that it has no legacy - there are no PHP 4 backwards compatibility workarounds. This means that it can fully take advantage of PHP 5.
I have been working with the framework for a couple of weeks now and I must say that I really like the simple MVC implementation in Zend Framework. I have started using only the built in "PHP template" solution but it would be easy to switch to Smarty or any other template engine. The help desk solution is coming along nicely and should soon be ready for a public demo/beta. I just need to decide on a name and domain where I should host it.
Viewing a ticket
read full post
0 comments on this post
New conference coming up
Written by Danne Lundqvist - 2006-10-23 19:16
Expo-C in Karlskrona, Sweden, have always been a treat. The last conference was held last spring and focused on agile principles and test (behaviour) driven development. Language wise it was great. Java, Ruby, C#, Python and even Visual Basic had their slots. One thing was missing though. My favourite language PHP. After the conference I spoke to Anki, one of the organisors about it and I promised to get back to her before the next spring conference and discuss what we could do about it. Unfortunately I had no idea that they would also have an autumn conference this time. So there will be no speakers from the PHP community this time either. I still will try to "help" them get a PHP speaker for the spring conference. I'll talk to her when I meet her in november.
It would be really fun to try and organise a small Swedish or even a Nordic PHP conference.