Mar 04

ExtPHP LogoIt is something that I had to think about in my day job, because my team is migrating to PHP for web development and I believe that we simply do not have enough time for them to learn JavaScript’s intricacies, I needed to be the one person who would have to wrestle JavaScript when problems happened. I therefore needed a way to insulate them from the gory details, which is why I created ExtPHP.
As you may have guessed from subtle hints, such as this entry’s 12-feet tall header, ExtPHP creates a PHP wrapper for ExtJS.

ExtPHP In ActionI noticed, at dzone.com, that the last time someone created a wrapper for JavaScript, many readers complained about how intrusive his approach was. Well, be assured that ExtPHP does not foil ExtJS’ non-intrusive take. Of course, with ExtJS itself, it’s up to the developer to decide what kind of style they wish to adopt, and ExtPHP follows suit.

ExtPHP Doc ScreenshotI guess the introduction I wrote in ExtPHP’s documentation explains fairly clearly what the idea is: “ExtPHP is a wrapper for ExtJS. This is version 0.1, so I expect that a lot of things can be improved upon and your feedback is greatly appreciated. ExtPHP can be used to write both intrusive and non-intrusive Javascript, just like ExtJS itself. Use it responsibly. One of the many advantages of this design is that unknown/misspelled/misused methods are detected in your PHP editor rather than forcing you to debug your JavaScript code in your web browser. ”

Documentation? Indeed, I took some time to write a much-needed PDF document. Let me know how I can improve it, I am sure that you will find it lacking - because it is.

Anyway, I am releasing this as a “Technology Preview” and I will greatly appreciate your help beta-testing it.

Cheers.

Download

Sphere: Related Content

Feb 15

PHP ScrewsSometimes, you want to run PHP with Tomcat. Why? Well, you may have a legacy product, for instance, that will require servlets for many more years. Or you may be using this gigantic Java program and are only interested in adding a tiny PHP piece on the side.

There are many guides showing how to do this available, but they become outdated almost as soon as they are published. So, it’s my turn to write a short-lived guide, this time for PHP 5.2.5 :)
Note thas this post relies greatly on information found here. Too bad even that guide got old so fast!

  1. Go to http://www.php.net/downloads.php and download the current version. I am going to do the setup on a Windows machine here, so I can simply download the binaries. On *nix, you will need to compile PHP. I know I will have to, anyway…
  2. You also need to download the corresponding PECL modules.
  3. Let’s assume that your current Tomcat install can be found in c:\Tomcat5\. Create a c:\Tomcat5\php\ directory and unzip the PHP zip file in it.
  4. Rename php.ini-dist, in c:\Tomcat5\php\, to php.ini
  5. Extract php5servlet.dll from the PECL zip file to c:\Tomcat5\php\
  6. Create a directory under c:\Tomcat5\webapps\; in our case: phptest
  7. In c:\Tomcat5\webapps\phptest\, create a subdirectory: WEB-INF
  8. In c:\Tomcat5\webapps\phptest\WEB-INF\, create web.xml with the following content:
    ini
    1. <?xml version="1.0" encoding="ISO-8859-1"?>
    2. <!DOCTYPE web-app PUBLIC
    3.   "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN"
    4.   "http://java.sun.com/dtd/web-app_2_3.dtd">
    5. <web-app>
    6.         <servlet>
    7.                 <servlet-name>php</servlet-name>
    8.                 <servlet-class>net.php.servlet</servlet-class>
    9.         </servlet>
    10.         <servlet>
    11.                 <servlet-name>php-formatter</servlet-name>
    12.                 <servlet-class>net.php.formatter</servlet-class>
    13.         </servlet>
    14.         <servlet-mapping>
    15.                 <servlet-name>php</servlet-name>
    16.                 <url-pattern>*.php</url-pattern>
    17.         </servlet-mapping>
    18.         <servlet-mapping>
    19.                 <servlet-name>php-formatter</servlet-name>
    20.                 <url-pattern>*.phps</url-pattern>
    21.         </servlet-mapping>
    22. </web-app>
  9. Extract/unjar (using jar xvf or WinZip) php5srvlt.jar under c:\Tomcat5\php\tmp\
  10. Modify both c:\Tomcat5\php\tmp\net\reflect.properties and c:\Tomcat5\php\tmp\net\servlet.properties, replacing
    ini
    1. library=phpsrvlt

    with

    ini
    1. library=php5servlet

    and save.

  11. Jar the content of c:\Tomcat5\php\tmp\ into a new version of php5srvlt.jar
  12. Move php5srvlt.jar to c:\Tomcat5\common\lib\
  13. Copy c:\Tomcat5\php\php5servlet.dll and c:\Tomcat5\php\php5ts.dll to c:\windows\system32\
  14. Create a test page in c:\Tomcat5\webapps\phptest\test.php with this contents:
    PHP
    1. <?php phpinfo(); ?>
  15. Start Tomcat and go to http://localhost:8080/phptest/test.php

It should work. If it doesn’t, you can always post the stack trace here.

Sphere: Related Content

Feb 08

JSONJSON, or JavaScript Object Notation, is fairly popular.
This is just my modest take on a ‘PHP Object Notation’ implementation.
Note that it is meant to follow how your mind works rather than being syntactically correct; therefore, associative arrays are used in a loose manner where you have to worry about associative syntax as little as possible.
Basically, type away until your object is fully described.

Here is a notation sample:

PHP
  1.         ‘root level’ => array(
  2.                 ’sublevel 1′ => array(
  3.                         ’sublevel 2′ => ’sublevel 3′,
  4.                 ),
  5.         )
  6. );

.
This syntax can then be used the same way JSON is used, using eval. Here is how and you will immediately notice how the eval() syntax has to differ from the JavaScript one:

PHP
  1. $remote_str = <<<EOB
  2.     array(
  3.         ‘root level’ => array(
  4.                 ’sublevel 1′ => array(
  5.                         ’sublevel 2′ => ’sublevel 3′,
  6.                 ),
  7.         )
  8. );
  9. EOB;
  10. // …
  11. eval(‘$local_str=’.$remote_str.‘;’);

.
Feels a bit clumsy. Fortunately, starting with PHP4, if you are not too sad about introducing a statement in your remote string, you can rewrite it like this:

PHP
  1. $remote_str = <<<EOB
  2. return array(
  3.         ‘root level’ => array(
  4.                 ’sublevel 1′ => array(
  5.                         ’sublevel 2′ => ’sublevel 3′,
  6.                 ),
  7.         )
  8. );
  9. EOB;
  10. // …
  11. $local_str = eval($remote_str);

.
Better, isn’t it?

In this last listing, you will find the very simple code I wrote to traverse the object. Note that I invoke a callback for every element, otherwise this code would not be very helpful.

Note that this is just a concept for something I needed to throw together quickly therefore there are some limitations; for instance, you cannot have numeric keys since in this context their “keyness” is ignored and even feared.

PHP
  1. <?php
  2. function traverse_tree($callback, $curlevel, $curdepth, $uid)
  3. {
  4.         $depthstr = ‘——————————————————————————’;
  5.         $padding = substr($depthstr, 0, $curdepth);
  6.         if(!is_array($curlevel))
  7.         {
  8.                 $callback($curlevel, $padding, $uid);
  9.                 return;
  10.         }
  11.         foreach($curlevel as $level=>$children)
  12.         {
  13.                 if(!is_numeric($level))
  14.                 {
  15.                         $my_uid = $callback($level, $padding, $uid);
  16.                         traverse_tree($callback, $children, $curdepth + 2, $my_uid);
  17.                 }
  18.                 else
  19.                 {
  20.                         $callback($children, $padding, $uid);
  21.                 }
  22.         }
  23. }
  24.  
  25. function do_something($name, $padding, $uid)
  26. {
  27.         $iid = 0; // Bogus value
  28.         print $padding.$name." ($iid)\n";
  29.         return $iid;
  30. }
  31.  
  32. // ———————————————————–
  33. // Here we go
  34. // ———————————————————–
  35. if(count($argv) != 2)
  36.         die("\nSyntax: ".$PHP_SELF." ‘root_node_name’\n\n");
  37. $rootnodename = &$argv[1];
  38.  
  39. $INS = array(
  40.         $rootnodename => array(
  41.                 ‘Bikes’ => array(
  42.                         ‘Yamaha’ => ‘Fz’,
  43.                         ‘Honda’,
  44.                         ‘Norton’
  45.                         ),
  46.                 ‘Trikes’,
  47.                 ‘Cars’ => array(
  48.                         ‘Chevrolet’ => array(
  49.                                 ‘Corvette’ => array(‘Z06′, ‘Convertible’, ‘Coupe’),
  50.                                 ‘Camaro’,
  51.                                 ‘Jimmy’
  52.                                 ),
  53.                         ‘Ford’ => array(
  54.                                 ‘Mustang’ => array(‘GT’, ‘Premium’, ‘Shelby’, ‘Other’=>‘Roush’),
  55.                                 ‘Explorer’,
  56.                                 ‘Crown Victoria’
  57.                                 ),
  58.                         ‘Chrysler’ => array(
  59.                                 ‘Dodge’ => ‘Charger’,
  60.                                 ‘300X’,
  61.                                 ‘Le Baron’
  62.                                 ),
  63.                         )
  64.         )
  65. );
  66.  
  67. traverse_tree(do_something, $INS, 0, 1);
  68.  
  69. print "DONE\n\n";
  70. ?>

.
Invoke with:

  1. php my_php_script.php "Vehicles"

.
“What is this $iid variable?” you may ask.
You will notice that this piece of code is particularly convenient if you want to add a whole tree structure to your database. Say the you are using MySQL and want to create categories and sub-categories, using the column ‘pid’ as a category’s parent id. You would rewrite do_something:

PHP
  1. function do_something($name, $padding, $uid)
  2. {
  3.         mysql_query("INSERT INTO my_cat_table(pid, title) VALUES({$uid}, ‘{$name}’)");
  4.         $iid = mysql_insert_id();
  5.         print $padding.$name." ($iid)\n";
  6.         return $iid;
  7. }

Voila!

Sphere: Related Content

Dec 26

SQLEvery now and then, a developer makes a post on their blog that, to the unsuspecting novice, seems like common sense.
Beware, though. If the post is less than comprehensive or accurate, it better not be about security matters or that newly acquired peace of mince may be quickly shattered.

Exhibit A: This post on the topic of PHP and SQL injections. It’s not like there is a lack of information already freely available on the web.
The author even references this excellent material at the end of his post. It is too bad that his own article actually contains less relevant information than the original post.

For instance, he recommends the use of mysql_real_escape_string().

  • Observation #1: this implies that you are using mysql as your database of choice. Granted you may use this method before sending a SQL query to Postgresql, but then there is no guarantee that mysql functions were compiled in the current php library.
  • Observation #2: mysql_real_escape_string() does nothing more than escape quotes. From the original article: “Be aware that “sanitizing the input” doesn’t mean merely “remove the quotes”, because even “regular” characters can be troublesome.

He recommends validating for the proper input, which is good practice. So, brownie points for that. But it wouldn’t hurt to have, for instance, mentioned the use of intval() to enforce that integer values are nothing but that. Integer values. I would say that it’s advice just as important as escaping input strings.

Now, the part that I found horrifying, but it’s just me, I’m a stickler: the author encourages you to code your HTML forms so that they will not accept too many characters. I see here some confusion: this is good usability advice, granted, but as far as security it is misguided.

The golden rule is simple: Always perform input validation server-side, where the user cannot ‘fake’ the values they are sending to your application.
Never, ever accept data “as-is” if it came through a path that allowed it to be tampered with.

Two other equally important points I wish he had mentioned are:

  • Configure error reporting so that your server does not display these “helpful” error messages that he mentions and attackers are delighted to find
  • A good SQL query is one cautiously put together, but a great SQL query relies on prepared statements. There are cases when you are after raw speed and direct queries feel more ‘natural’ -I know, I use them a lot- but whenever possible, use prepared statements, since the user is then not given a chance to “write” your query string himself.
Sphere: Related Content

Sep 09

RedirectDo you have any idea how much disregarding basic SEO (Search Engine Optimization) rules can cost you? I have the answer and it’s “a lot“. And take my word for it: I am not an SEO consultant and have nothing to sell, here.

Up until last year, one of my sites was wildly popular: militate.com. Note that after achieving success through word of mouth, it plateaued and never exceeded 300 simultaneous users. It even started a slow descent that would end up in its much smaller audience today.

What was the horrible mistake that lead to that, then?

Simple.

Rule #1 of SEO: when you’re getting good Google juice through heavy pages indexing, do not, under any circumstance, turn your site into a dead links farm.

And that’s exactly what I did: at first people could access the site under a directory labeled /forums; after its first overhaul it became /site; later on I changed the domain name. And finally I changed /site to simply /

This, alone, is no crime. But I never told Google where to find the pages that were being relocated.

As a result, a web site that had steadily grown to more than 600,000 topics suddenly stalled and withered. OK, there are more factors: the site team was losing interest in its main topic, among many. But even when this happens, you can keep a niche site likes this one through sheer popularity. You really have to be a hairless monkey to mess that up.

So, how do you avoid such an unfortunate situation?

In my case, here is what I should have done. This relies entirely on issuing a status ‘301′, which search engines understand to mean “This is my new home. Follow me!”

Solution #1: use mod_rewrite Redirect
This is the usual answer and it works fairly well. Let’s see how we do it for our move from forums/ to site/

1. Create a file called .htaccess at the root of your old directory ( “forums” ) and put the following inside:
RewriteEngine on
RewriteBase /
RewriteRule /forums/(.*) /site/$1 [R=301,L]

Oh, wait: it is now as simple as

RedirectMatch 301 /forums/(.*) /site/$1

2. That’s it. Make sure that .htaccess has the correct access rights.

Well, that was easy.

Now, let’s say that you are looking for a more advanced solution; for instance you change your CMS/Forum Software and what used to be /forums/index.php?act=topic&page=105&p=1 now becomes /site/index.php?act=topic&n=1&p=1 because your old software’s topics started at number 105 but now that you imported them in your new software, they were renumbered and start at 1.

Here is a simple solution, that will also work if you do not have mod_rewrite (sorry, only a php example for now; I may write a Ruby example as well if requested):

1. Create a file called notarealpage.php; again at the root of your old directory:

  1. [?
  2. $directory = preg_replace(’#^/forums/#’, ‘’, $_SERVER[’REDIRECT_URL’]); // Remove original directory
  3. $querystr = $_SERVER[’REDIRECT_QUERY_STRING’];
  4. if(empty($querystr))
  5.         $qm = ‘’;
  6. else
  7. {
  8.         $qm = ‘?’;
  9.         // Renumber
  10.         $querystr = preg_replace_callback(
  11.                 ‘#&amp;id=([0-9]+)#’,
  12.                 create_function(
  13.                         ‘$matches’,
  14.                         ‘return "&amp;n=" . ($matches[1]-104);’),
  15.                 $querystr);
  16. }
  17. $newurl = ‘/site/’ . $directory . $qm . $querystr;
  18. print $newurl;
  19. ?]

2. In your .htaccess file, simply put:

ErrorDocument 404 /forums/notarealpage.php

Voila! Simple as that.

A note: again, I recommend that you look at the ‘Plain Code’ since the highlighter plug-in translates all html entities. I have to take this plug-in apart someday…

Sphere: Related Content

Aug 02

Sandro Groganz gives an interesting response to Matt Mullenweg’s taking PHP 5 and Zend to task.
I find his post interesting because he compares Php5 to Java, unlike the rest of us who are focused on Ruby and other sexy beasts.
As a Java programmer myself -and one of the many Java people dazzled by Ruby- I have a lot of sympathy for his take. After all, from where I stand, Php5 is simply an attempt at replicating everything that Zend likes about Java. I wonder if the idea was to attract Java programmers but if so, it shows a serious lack of understanding of what we like. Java developers are not looking for a laundry list of features; if we were simply looking for a lightweight version of Java, Groovy is all we need, thank you. Rails, on the other hand, really appeals to a professional developer’s mind with its elegant constructs such as built-in iterators and its community.

I am among the people who believe that Php5 is a mistake. Php4 was perfect to develop lightweight projects that require good performance while maintaining an iterative development model. I also think of myself as a Php4 developer when necessary just like I know that I can whip up a shell script when I need something done very quickly.

I have used Php4 for years. Then, Php5 came along, making promises of object orientation that would allow me to write code about as complex as my Java code. OK, so what benefit am I getting from using this new language? (From Matt Mullenweg’s post: “I wonder if PHP 5+ should be called something other than PHP” - aye!)

I use Php a lot, for Clic!Dev, nextBBS and other very demanding projects. Sorry to say, but the last thing I need is an interpreted object-oriented language. If I am forced to move to Php5, one of two things will happen:
1. I will code in Php5 the exact same way I am coding right now in Php4, ie using a minimum of object orientation
2. Or I will decide to bite the bullet and recode everything using a language that doesn’t suffer an identity crisis

I wish Drupal and other members of the ‘Pure Php5 Movement’ good luck and I think that it’s a good idea for projects this size to implement the best development practices, however I cannot help but think that the only reason why they are doing so in Php is mainly because nobody wants to can thousands of lines of legacy code.

Your feedback is welcome. Actually I would be more than happy to be proven wrong on this topic!

Sphere: Related Content

Dec 31

They are everywhere: protopage, pageflakes, netvibes et al are free, easy to use -as long as you have a powerful browser- and moderatly eye-pleasing.

SO?

A couple months ago, I wondered how long it would take me to build my own ‘WebTop’ (You can play with it here). The challenge would be to get it to a satisfactory state over a week-end.
Of course, I decided to use existing open-source code for the applications’ primary needs.
Continue reading »

Sphere: Related Content