Java Platform, Enterprise Edition

Java EE Journal

Subscribe to Java EE Journal: eMailAlertsEmail Alerts newslettersWeekly Newsletters
Get Java EE Journal: homepageHomepage mobileMobile rssRSS facebookFacebook twitterTwitter linkedinLinkedIn


J2EE Journal Authors: Stackify Blog, Sumith Kumar Puri, Javier Paniza, Yakov Fain, Ken Fogel

Related Topics: MySQL Journal, PHP Developer's Journal

MySQL Journal: Article

Even more stupid PHP tricks

Readers weigh in with clever tips & techniques to help program PHP.

(LinuxWorld) -- I thank the readers who sent in their comments and snippets of code in response to Two stupid PHP tricks and More stupid PHP tricks, a series about what I'm learning while adapting PHP-Nuke for VarLinux.org. I want to share a few letters that include information useful to any PHP user.

If you recall from the first column, the crypt() function can suddenly switch to a different default encryption algorithm depending on how you have your system set up, which can break user password authentication. On my system, the default switched from standard DES to MD5. I fixed the problem by forcing VarLinux.org to use standard DES, as it was the original default. A fellow named Matthew sent in this solution for switching users over to MD5. He uses a bit of code that checks the encrypted password to see what algorithm is being used, and then re-encrypts the plaintext password accordingly for authentication.

function CheckPassword ($plaintext, $password) {

switch (strlen($password)) {

case 34: # MD5 Password $foo = explode("$", $password); $salt = "\$1\$" . $foo[2]; break;

case 13: # Standard DES Password $salt = substr($password, 0, 2); break;

default: $salt = ""; echo "This password is of unknown type<br>\n"; break; }

$new_password = crypt($plaintext, $salt);

return ($new_password == $password);

}

Reader Jason said it doesn't matter very much how good the encryption algorithm is if you're passing plain text over the network. An excellent point. It occurred to me as an afterthought once the column was online, so I added it as a comment at VarLinux.org.

There are at least two solutions for this problem. You can run an SSL version of your Web server, or you can set up your site to encrypt the password at the client using Javascript before it is sent to the server. The latter method is interesting, and I'd like to toy with it. It has two potential problems. First, you'll have to account for the fact that many people turn off Javascript in order to put a stop to pop-up advertisements. (Yes, there are many other ways to stop pop-ups, such as proxies, redirectors, and various browser options. Let's face it: People turn off Javascript.) Second, unless you use SSL, all you've really done is change the information from plaintext to an encrypted string. If someone is clever, they can sniff the encrypted password on the network and use it to log in as you. They don't need to know your plaintext password.

2 cents : "Power of Unix" + PHP
Endless  3 lines of code programs (search engines, log analyzers...)

Example, RTFM;)

<?PHP $fp=popen ("man $man|man2html", "r"); while ( $st=fgets ($fp, 512)) echo " $st "; pclose($fp); ?>

This cute little PHP program allows you to view any Unix manual page (commonly known as man pages) as HTML. KDE does this automatically without using PHP, but it's an excellent example of the incredible power you have at your fingertips using very few lines of code when you combine Unix with PHP.

Why modify PHP-Nuke?

Why bother modifying PHP-Nuke?

  1. I wanted to learn PHP, and I learn best by tinkering.
  2. PHP-Nuke 4.4.1a was broken in several places and I had to fix those problems as they arose.
  3. PHP-Nuke does some things differently than I'd like.

For example, PHP-Nuke blurs the distinction between informants, authors, and administrators. This is natural for a weblog system, but it isn't how I wanted to structure VarLinux.org. It hasn't worked out this way yet, but VarLinux.org was eventually supposed to be more about original content than pointing to existing articles on the Web. I wanted to have only a few designated administrators. Informants would be those people who submitted links, and the authors would be the authors of the articles -- whether original or published on other sites. So I split a few database tables to create this structure and changed the code accordingly.

Another change fixes one of the things I like least about most weblogs. Usually people submit comments about a story online, and include a URL to that story within the comments. They often include links to other resources in their comments, too. It's nice to have those additional links, but it forces me to scan through the comments and guess which link points to the relevant story.

I changed this by adding a storyurl field to the story table. (Warning: We database folk use the terms "field" and "column" interchangeably.) When you submit a story link, you are asked to fill out the URL separately. This way, you can click on the headline for any story instead of searching for the URL in the comments. If it is an original story, it takes you right to the story and comments page. If it's a story off-site, it takes you to there. (It actually runs you through a redirect program so I can count the click-throughs to see which stories people like most.)

I also wanted to move stories up and down the home page so that I could bump an important story up to the top of the page even if it's hours or days old. At first, I did this by changing the story ID number, but that broke links from other sites. I added a TOC (table of contents) field, which is identical to the story ID when you first post a story. After that, you can shuffle the TOC numbers to reorder the stories any way you like.

Finally, I added a lastmod field to keep track of when stories are modified. As an administrator, I have the option of updating this field so that when you visit VarLinux.org you'll see a little graphic that tells you the story has been updated. At this point, I can't resist sharing the code I use to compare the date of the article to the date the user is viewing it to see whether to display the "new" or "updated" graphics. This is a glorious example of the brute-force twisted thinking one comes up with when combining quick-and-dirty with sleep deprivation:

function theme_is_new_story($storytimestamp, $lastvisit) {
    $newstory = 0;
    list($lvdate, $lvtime) = split(" ", $lastvisit);
    list($lvyear, $lvmonth, $lvday) = split("-", $lvdate);
    list($lvhour, $lvmin, $lvsec) = split(":", $lvtime);

list($storydate, $storytime) = split(" ", $storytimestamp); list($storyyear, $storymonth, $storyday) = split("-", $storydate); list($storyhour, $storymin, $storysec) = split(":", $storytime);

if ($storyyear > $lvyear) { $newstory = 1; } else if (($storyyear == $lvyear) && ($storymonth > $lvmonth)) { $newstory = 1; } else if (($storyyear == $lvyear) && ($storymonth == $lvmonth)) { $storydhm = ($storyday * 1440) + ($storyhour * 60) + $storymin + 30; $lvdhm = ($lvday * 1440) + ($lvhour * 60) + $lvmin; if ($storydhm > $lvdhm) { $newstory = 1; } } return($newstory); }

It's a mess, but it works. For 30 minutes after the story goes up (or 30 minutes after your lastvisit cookie has been updated, assuming you have cookies enabled) the story will appear with the "new" tag.

That was probably more detail than I needed in order to lead up to a very simple tip, but the information could be useful to you if you are considering PHP-Nuke and want it to behave more like my site. As I said last week, I wouldn't recommend using my code as-is to start a new site. You could cut and paste some sections of my code into PHP-Nuke and make whatever surrounding changes are necessary as a first step toward adding some of these features.

More stupid MySQL tricks

Each time I made changes to columns, added columns or tables in the PHP-Nuke MySQL database, it was necessary to change or add parameters to PHP functions that used the data. Since I hadn't memorized the whole PHP-Nuke code base, I found myself repeatedly grepping all the PHP files to find every occurrence of the modified function so I could update them all. (The grep command searches files for a string or regular expression pattern.)

This is one of those cases where quick and dirty took precedence over the better way of doing things. Had I learned PHP first and written the software from scratch, I would have passed database values to many of these functions in an array. But I didn't even know at this point how PHP handled arrays, and all I wanted was to get the changes done now.

Then I downloaded the software geeklog, yet another PHP-based weblog, and browsed through its code. When I saw how the geeklog code passed database values in an array, I realized it was such an easy process that it took only a few minutes to implement it for one of the functions in PHP-Nuke.

An example is worth a thousand words. Here are the different ways of handling database values and passing them to other functions. This simple pseudo-program fetches a name and an address from a customer table where the customer ID is equal to 1, and sends these values to a function that echoes the values.

First up is the way PHP-Nuke handles things for the most part, which is on a per-column per-variable basis.

<?PHP
$result = mysql_query("select name, address from customer where cid=1");
list($namevar, $addressvar) = mysql_fetch_row($result);
do_something($namevar, $addressvar);

function do_something($namevar, $addressvar) { echo $namevar . "<BR>"; echo $addressvar . "<BR>"; }

?>

Now here's the way to do the same thing using arrays.

<?PHP
$result = mysql_query("select name, address from customer where cid=1");
$CUST = mysql_fetch_array($result);
do_something($CUST);

function do_something($CUST) { echo $CUST["name"] . "<BR>"; echo $CUST["address"] . "<BR>"; }

?>

In many cases the latter practice is preferable, because you can add a field to the table called zipcode and change only two things -- the query and the function that uses the data. The query would become "select name, address, zipcode" and you could access the value with $CUST["zipcode"] without changing anything about the way the function is called.

Note that the elements of the array are referenced by field name. This means that if the rows in your customer table are not particularly large (which would make this technique a waste of memory), you could also perform the above operation with code like this:

<?PHP
$result = mysql_query("select * from customer where cid=1");
$CUST = mysql_fetch_array($result);
do_something($CUST);

function do_something($CUST) { echo $CUST["name"] . "<BR>"; echo $CUST["address"] . "<BR>"; }

?>

It is sometimes worthwhile to use select * even when you don't need to, because your program will be more forgiving when you add new fields. You can start using them immediately in your function without having had to change the code that calls the function. It doesn't matter that we aren't specifying any field names in our query when we use select * (which means select all fields), because that isn't what PHP uses to discover the field names in order to create references for them. The MySQL functions in PHP will automatically create the array with the proper field name references with the select * query as well.

Remember that it's a mistake to use this technique if you have very large fields in your table that you won't be using in the function, since you'll be sucking up memory passing extra data without need.

More Stories By Nicholas Petreley

Nicholas Petreley is a computer consultant and author in Asheville, NC.

Comments (0)

Share your thoughts on this story.

Add your comment
You must be signed in to add a comment. Sign-in | Register

In accordance with our Comment Policy, we encourage comments that are on topic, relevant and to-the-point. We will remove comments that include profanity, personal attacks, racial slurs, threats of violence, or other inappropriate material that violates our Terms and Conditions, and will block users who make repeated violations. We ask all readers to expect diversity of opinion and to treat one another with dignity and respect.