Technosailor.com Readers! Donate today to assist the CHF International Haiti Relief in their efforts.

28 November 2005 30 Comments

Case Study b5Media: Debugging PHP – Part 1

I talked earlier about landing a deal with “b5media”:http://www.b5media.com to implement a migration script to move their 32 new blogs into WordPress. I thought the deal would be straightforward enough but I ran into a number of issues with the importer.

I wanted to give you a window into the process of debugging for one MAJOR issue. For reference, here is “the original nucleus.php file”:http://www.technosailor.com/nucleus.phps I began debugging with this afternoon.

h3. Issue Reported: Not all comments Seemed to be imported

As a first run, we imported a blog called “The Beauty Blog”:http://www.aboutweblogs.com/beauty/. It was noted that it did not appear all comments were imported as there were some missing. As a point of reference, one entry on the original blog entitled “My Solution for Buildup”:http://www.aboutweblogs.com/beauty/?itemid=2608 had 4 distinct comments from 2 users.

However, upon import and viewing in the new WordPress blog, only 2 comments showed up by the same user

h3. How I figured things out

I will let you dissect the script to find out the basis of what happens. However, we know that the problem seemed to be happening on the execution of the

1
import_comments()

function.

From the code, this function looks like this:

[php]function import_comments()
{
// Comment Import
$comments = $this->get_nuc_comments();
$this->comments2wp($comments);

_e(‘<form action=”admin.php?import=nucleus&step=6″ method=”post”>’);
_e(‘<input type=”submit” name=”submit” value=”Import Links” />’);
_e(‘</form>’);
}
[/php]

This bit of code tells us that first we are going to run the

1
get_nuc_comments()

function which will gather all the comment data from Nucleus into an associative array and return the data to a variable

1
$comments

. We will then pass

1
$comments

to

1
comments2wp()

where the data will be passed to the WordPress API and inserted into the new WordPress blog.

We know something is going wrong in this process so let’s start at the top…

1
get_nuc_comments()

. This function looks like this:
[php]
function get_nuc_comments()
{
// General Housekeeping
global $nucdb;
set_magic_quotes_runtime(0);
$nuc_com = array();
$prefix = get_option(‘npre’);
$blog_id = get_option(‘blog_id’);

$storedUsers = $nucdb->get_results(“SELECT cmember FROM nucleus_comment”);

foreach($storedUsers as $su)
{
if(0 d;d; $su->cmember)
{
return $nucdb->get_results(‘SELECT
cnumber,
cbody,
cuser,
cemail,
citem,
ctime,
chost,
cip
FROM nucleus_comment
WHERE cblog = ‘.$blog_id,
ARRAY_A);
}
else
{
return $nucdb->get_results(‘SELECT
cnumber,
cbody,
mname AS cuser,
memail AS cemail,
murl AS curl,
citem,
ctime,
chost,
cip
FROM nucleus_comment, nucleus_member
WHERE cmember=mnumber
AND cblog = ‘.$blog_id,
ARRAY_A);
}
}
return false;
}[/php]

Now, most of this function is direct database queries from the Nucleus database. The schema of the two tables referenced (nucleus_comment and nucleus_member) are as follows:

[code]
CREATE TABLE nucleus_comment (
cnumber int(11) NOT NULL auto_increment,
cbody text NOT NULL,
cuser varchar(40) default NULL,
cmail varchar(100) default NULL,
cmember int(11) default NULL,
citem int(11) NOT NULL default '0',
ctime datetime NOT NULL default '0000-00-00 00:00:00',
chost varchar(60) default NULL,
cip varchar(15) NOT NULL default '',
cblog int(11) NOT NULL default '0',
crating tinyint(4) NOT NULL default '0',
PRIMARY KEY (cnumber),
UNIQUE KEY cnumber (cnumber),
KEY citem (citem),
FULLTEXT KEY cbody (cbody)
) ENGINE=MyISAM DEFAULT CHARSET=latin1 AUTO_INCREMENT=2030 ;

CREATE TABLE nucleus_member (
mnumber int(11) NOT NULL auto_increment,
mname varchar(16) NOT NULL default '',
mrealname varchar(60) default NULL,
mpassword varchar(40) NOT NULL default '',
memail varchar(60) default NULL,
murl varchar(100) default NULL,
mnotes varchar(100) default NULL,
madmin tinyint(2) NOT NULL default '0',
mcanlogin tinyint(2) NOT NULL default '1',
mcookiekey varchar(40) default NULL,
deflang varchar(20) NOT NULL default '',
PRIMARY KEY (mnumber),
UNIQUE KEY mnumber (mnumber),
UNIQUE KEY mname (mname)
) ENGINE=MyISAM DEFAULT CHARSET=latin1 AUTO_INCREMENT=23 ;[/code]

Nucleus has a feature similar to WordPress in that if a member exists as a result of signing up for an account, they are stored in the nucleus_member database. However, having a membership is not required to comment on a Nucleus blog. As a result, Nucleus stores comments with all the standard comment information (email, name, IP address, etc) and stores a 0 in the cmember field if the user is NOT a Nucleus member. However, if the member *is* a member, cmember stores their member ID number and leaves the name and email fields blank because it will get the stored member information in nucleus_member.

Make sense? It did to me too until I started debugging! The

1
get_nuc_comments()

, in theory, worked like this:

# Get the cmember field for all the comments
# Loop through the cmember fields
# If the cmember field was equal to 0 (not a member), then perform a direct query only on the nucleus_comment table
# If the cmember field was NOT equal to 0 (is a member commenting), then perform a query getting the comment data from the nucleus_comment table and the associated member information from the nucleus_member table.
# return the data for use in the

1
comments2wp()

function

Looking over my code for errors, the first thing I noticed was that in my first query, I used a field “cemail” when, from the schema, that field should be “cmail”. I changed the alias name in the second query as well for consistency, but knew that that second query should not fail because we were actually selecting “memail” from the members table and that field _did_ exist!

I figured this was the solution to the problem. This query was failing because the field name was incorrect and somewhere along the line, it was _failing silently!_ Saved the file and re-ran the import. No errors reported, however that post that should have 4 comments, still only had the same 2.

Sigh. Back to the drawing board. Let’s look back at that code.

Ahha! Do you see what I see? I’m

1
return

ing both of those queries. In PHP, Perl, C++ and most languages of similar syntax, a return means that the function is completed and the data that is being returned is what should be kicked back out. Only one query should be getting run, right?

So I made the following change to the code:
[php]
function get_nuc_comments()
{
// General Housekeeping
global $nucdb;
set_magic_quotes_runtime(0);
$nuc_com = array();
$prefix = get_option(‘npre’);
$blog_id = get_option(‘blog_id’);

$storedUsers = $nucdb->get_results(“SELECT cmember FROM nucleus_comment”);

foreach($storedUsers as $su)
{
if(0 == $su->cmember)
{
$com = $nucdb->get_results(‘SELECT
cnumber,
cbody,
cuser,
cemail,
citem,
ctime,
chost,
cip
FROM nucleus_comment
WHERE cblog = ‘.$blog_id,
ARRAY_A);
}
array_push($nuc_com, $com);
else
{
$com = $nucdb->get_results(‘SELECT
cnumber,
cbody,
mname AS cuser,
memail AS cemail,
murl AS curl,
citem,
ctime,
chost,
cip
FROM nucleus_comment, nucleus_member
WHERE cmember=mnumber
AND cblog = ‘.$blog_id,
ARRAY_A);
array_push($nuc_com, $com);
}
return $nuc_com;
}
return false;
}[/php]

This change would assign each query result to a variable,

1
$com

and then use the

1
"array_push()":http://www.php.net/array_push

function to push the resulting array onto the end of the

1
$nuc_com

array.

Save. Load. Execute. Failure.

Now I’m getting pissed. This should work.

Let’s see what the

1
$nuc_com

array contains. Drop this right before the

1
return $nuc_com;

and reload.

[php]
echo’<pre>’;
print_r($nuc_com);
echo’</pre>’;
exit;
[/php]

Kicked out is a long nested array looking similar to (changing details to protect the innocent):
[code]
Array
(
[0] => Array
(
[0] => Array
(
[cnumber] => 860
[cbody] => That is not a bad thing! Brushing or combing wet hair aggressively can be a cause of all kinds of problems, including frizzies. Always treat your hair very gently when it is wet, as it is much more prone to stretching (which will give you "the frizzies") and breakage. Do try that PM The Conditioner--I bet you will find that it helps. But use a regular conditioner as well. In my opinion, you can skimp on the shampoo, but good conditioners are well worth the extra money.
[cuser] => CC Jones
[cemail] => some@email.com
[curl] => http://www.aboutweblogs.com/beauty/
[citem] => 1233
[ctime] => 2005-08-03 07:59:09
[chost] => some-isp-55-55-55-55-agent
[cip] => xxx.xxx.xxx.xxx
)

[/code]

Well this is not very useful on it’s face because I need to know how many of these commenters have a cmember value of 0 or non-zero. This will tell me if only one of the queries is being executed or if both are. I added “cmember” to both of the SELECT queries and re-executed.

[code]
Array
(
[0] => Array
(
[0] => Array
(
[cnumber] => 860
[cmember] => 16
[cbody] => That is not a bad thing! Brushing or combing wet hair aggressively can be a cause of all kinds of problems, including frizzies. Always treat your hair very gently when it is wet, as it is much more prone to stretching (which will give you "the frizzies") and breakage. Do try that PM The Conditioner--I bet you will find that it helps. But use a regular conditioner as well. In my opinion, you can skimp on the shampoo, but good conditioners are well worth the extra money.
[cuser] => CC Jones
[cemail] => some@email.com
[curl] => http://www.aboutweblogs.com/beauty/
[citem] => 1233
[ctime] => 2005-08-03 07:59:09
[chost] => some-isp-55-55-55-55-agent
[cip] => xxx.xxx.xxx.xxx
)
[/code]

Scanning the resulting output, I see that all of the results have non-zero cmember values. Not good. Obviosuly, only the second query is being executed. When this happens, the first place I look to is the conditional — the if/else statement. IF something is true, then run this code, OTHERWISE run that code. In our case _that_ code was running and _this_ code never was.

To be continued…

Pick up your copy of the WordPress Bible, a wildly popular resource for beginners and experts alike.

Popularity: 1% [?]

30 Responses to “Case Study b5Media: Debugging PHP – Part 1”

  1. Crash Test Dummy 28 November 2005 at 10:52 pm #

    You are doing a fantastic job, Aaron–this is very interesting to read your thought processes!

  2. Crash Test Dummy 28 November 2005 at 10:52 pm #

    You are doing a fantastic job, Aaron–this is very interesting to read your thought processes!

  3. Crash Test Dummy 28 November 2005 at 10:52 pm #

    You are doing a fantastic job, Aaron–this is very interesting to read your thought processes!

  4. Crash Test Dummy 28 November 2005 at 10:52 pm #

    You are doing a fantastic job, Aaron–this is very interesting to read your thought processes!

  5. Crash Test Dummy 28 November 2005 at 9:52 pm #

    You are doing a fantastic job, Aaron–this is very interesting to read your thought processes!

  6. Eric Coleman 29 November 2005 at 12:03 pm #

    What do you use on a normal basis for debugging?

    I usually use PEAR’s Log class, and I have xdebug installed (and profiling enabled).

    It’s a great help :)

  7. Eric Coleman 29 November 2005 at 12:03 pm #

    What do you use on a normal basis for debugging?

    I usually use PEAR’s Log class, and I have xdebug installed (and profiling enabled).

    It’s a great help :)

  8. Eric Coleman 29 November 2005 at 12:03 pm #

    What do you use on a normal basis for debugging?

    I usually use PEAR’s Log class, and I have xdebug installed (and profiling enabled).

    It’s a great help :)

  9. Eric Coleman 29 November 2005 at 12:03 pm #

    What do you use on a normal basis for debugging?

    I usually use PEAR’s Log class, and I have xdebug installed (and profiling enabled).

    It’s a great help :)

  10. Eric Coleman 29 November 2005 at 11:03 am #

    What do you use on a normal basis for debugging?

    I usually use PEAR’s Log class, and I have xdebug installed (and profiling enabled).

    It’s a great help :)

  11. Aaron 29 November 2005 at 12:07 pm #

    bq. What do you use on a normal basis for debugging?

    My brain. :-)

  12. Aaron 29 November 2005 at 12:07 pm #

    bq. What do you use on a normal basis for debugging?

    My brain. :-)

  13. Aaron 29 November 2005 at 12:07 pm #

    bq. What do you use on a normal basis for debugging?

    My brain. :-)

  14. Aaron 29 November 2005 at 12:07 pm #

    bq. What do you use on a normal basis for debugging?

    My brain. :-)

  15. Aaron 29 November 2005 at 11:07 am #

    bq. What do you use on a normal basis for debugging?

    My brain. :-)

  16. Eric Coleman 29 November 2005 at 1:58 pm #

    Your a funny one, let me tell ya ;)

    You obviously don’t stare at php code for 60+ hours a week ;P

    BTW, fix those code blocks… the double spacing is making me go blind :P

  17. Eric Coleman 29 November 2005 at 1:58 pm #

    Your a funny one, let me tell ya ;)

    You obviously don’t stare at php code for 60+ hours a week ;P

    BTW, fix those code blocks… the double spacing is making me go blind :P

  18. Eric Coleman 29 November 2005 at 1:58 pm #

    Your a funny one, let me tell ya ;)

    You obviously don’t stare at php code for 60+ hours a week ;P

    BTW, fix those code blocks… the double spacing is making me go blind :P

  19. Eric Coleman 29 November 2005 at 1:58 pm #

    Your a funny one, let me tell ya ;)

    You obviously don’t stare at php code for 60+ hours a week ;P

    BTW, fix those code blocks… the double spacing is making me go blind :P

  20. Eric Coleman 29 November 2005 at 12:58 pm #

    Your a funny one, let me tell ya ;)

    You obviously don’t stare at php code for 60+ hours a week ;P

    BTW, fix those code blocks… the double spacing is making me go blind :P

  21. Eric Coleman 29 November 2005 at 9:55 pm #

    Aaron,

    I get parse errors every time I submit a comment, however they are submitted anyways :)

    – eric

  22. Eric Coleman 29 November 2005 at 9:55 pm #

    Aaron,

    I get parse errors every time I submit a comment, however they are submitted anyways :)

    – eric

  23. Eric Coleman 29 November 2005 at 9:55 pm #

    Aaron,

    I get parse errors every time I submit a comment, however they are submitted anyways :)

    – eric

  24. Eric Coleman 29 November 2005 at 9:55 pm #

    Aaron,

    I get parse errors every time I submit a comment, however they are submitted anyways :)

    – eric

  25. Eric Coleman 29 November 2005 at 8:55 pm #

    Aaron,

    I get parse errors every time I submit a comment, however they are submitted anyways :)

    – eric

  26. Aaron 29 November 2005 at 10:27 pm #

    It’s my way to get you to leave. ;)

    kidding, of course.

    YEah it’s the Subscribe to Comments plugin. I need to address it but, as you pointed out, it doesn’t prevent commenting or subscibing so it’s not at the top of the priority list at the moment. Thanks though.

  27. Aaron 29 November 2005 at 10:27 pm #

    It’s my way to get you to leave. ;)

    kidding, of course.

    YEah it’s the Subscribe to Comments plugin. I need to address it but, as you pointed out, it doesn’t prevent commenting or subscibing so it’s not at the top of the priority list at the moment. Thanks though.

  28. Aaron 29 November 2005 at 10:27 pm #

    It’s my way to get you to leave. ;)

    kidding, of course.

    YEah it’s the Subscribe to Comments plugin. I need to address it but, as you pointed out, it doesn’t prevent commenting or subscibing so it’s not at the top of the priority list at the moment. Thanks though.

  29. Aaron 29 November 2005 at 10:27 pm #

    It’s my way to get you to leave. ;)

    kidding, of course.

    YEah it’s the Subscribe to Comments plugin. I need to address it but, as you pointed out, it doesn’t prevent commenting or subscibing so it’s not at the top of the priority list at the moment. Thanks though.

  30. Aaron 29 November 2005 at 9:27 pm #

    It’s my way to get you to leave. ;)

    kidding, of course.

    YEah it’s the Subscribe to Comments plugin. I need to address it but, as you pointed out, it doesn’t prevent commenting or subscibing so it’s not at the top of the priority list at the moment. Thanks though.