S2ajax v1.0 connects simply PHP and JavaScript

S2ajaxHere comes S2ajax v1.0!
And it was long overdue. Six months already since I posted S2ajax says “hi()” I can hardly believe it.

What I think of as v1.0’s main feature is that it is now possible to simply export classes in PHP and these classes can be instantiated in JavaScript. Whenever these instances are modified through asynchronous method calls, these modifications are transparently persisted server-side.

The concept

Is it a PHP class? Is it a JavaScript class? Why, it’s both! The class is defined in PHP on the server. Instances of the class are created on demand using JavaScript on the client. Whatever modifications are made to an instance are serialized on the server.
You can create a complex application using as many classes and instances as you need.

100

Under the hood

The PHP class is exported; the proxy JavaScript code is generated.
Whenever the client needs to access one of the class’ properties/methods, the proxy transparently talks to the class; the class lives server-side.

99

The Client’s point of view

An arbitrary number of instances of the class can be created in JavaScript.
The only hint that you are using a client-server architecture is the fact that when invoking a method, its return value is obtained through a callback. This mechanism allows your client interface to remain responsive while the server is preparing a response.

101

The server’s point of view

S2ajax automatically persists your instances’ state and data between consecutive asynchronous calls. You still get the benefits of the “shared nothing” approach of PHP but complex objects can be manipulated through an unlimited number of clients requests.

102

A code sample

Server-side

Let’s create a class that will increment an instance variable every time a method is invoked. Let’s keep it as simple as possible:

class CounterTester
{
    private $counter;
 
    function __construct() {
        $this->counter = 0;
    }
 
    public function increment_counter() {
        $this->counter++;
        return $this->counter;
    }
}

Clearly, every time increment_counter() is invoked, $counter will be incremented and its new value returned.

Client-Side

First, an instance of our class is created. Then, when a user click on the button labeled ‘Increment counter’, the instance’s increment_counter() method will be invoked and the new $counter value returned to our callback and displayed.

?View Code JAVASCRIPT
<script>
function display_result(val) {
    alert(val); // Display new counter value
}
var counter = new CounterTester();
</script>
<button onclick="counter.increment_counter(display_result);">Increment counter</button>

Note that we could create as many instances of our class as we wish and provided we display the matching buttons, we could independently increment multiple counters.

Get it now!

Click our valiant friend “Octocat”, artistically represented below, to go to S2ajax’s Github page. If you just wish to use the library, look for the [Download] button:

Git!

Git!

If you enjoyed this post, make sure you subscribe to my RSS feed!


PHP PDO class and XAMPP/”exotic” MySQL configurations

Last night I was trying to setup a @mail server but the installer kept choking when attempting to connect to my local database.

I am posting here my quick workaround in case you too, dear reader, get a dreaded “PDO” error message complaining about your attempt to “connect to unix://

Here is I how I solved the issue for @mail: I opened library/Zend/Db/Adapter/Pdo/Abstract.php, found the line that creates the PDO object (”new PDO(…“) and, in this example, the first argument passed to the constructor was $dsn.

The problem is that PDO sees that this variables references “localhost” and decides that, since the database is local, it is going to use mysql.sock (hence the unix:// scheme)

This works as long as the file is found in its default location. If it is elsewhere, you are out of luck. This happens, for instance, if you use XAMPP.

Here is my quick fix, inserted right before the creation of the PDO object:

$dsn = str_replace(’host=localhost’, ‘unix_socket=/opt/lampp/var/mysql/mysql.sock’, $dsn);

All done.

Note: I have not investigated enough to know whether this is something missing in the Zend Framework or in @mail itself.

If you enjoyed this post, make sure you subscribe to my RSS feed!


Determining if an IP is within a specific range: redux

Submarine NetI was reading Paul Gregg’s very clear explanation of “classless” ranges comparison when I realized that his code was not as “bare metal” as could be.

So, here is the code I’ve been using in nextBBS.
It only accepts ranges in the form “x.x.x.x/b” but it’s short and all I needed, really.

function isSubnet($subnet, $ip)
{
    // Classless (in more than one way) comparison
    $cursubnet = explode('/', $subnet);
    $longsubnet = ip2long($cursubnet[0]);
    $longip = ip2long($ip);
 
    if(count($cursubnet)<2)
    {
        // Compare IP itself
        return ($longip==$longsubnet);
    }
 
    // IPv4 only!
    $subnetmask = 0xffffffff << (32-$cursubnet[1]);
    return (($longip & $subnetmask) == ($longsubnet & $subnetmask));
}

If you enjoyed this post, make sure you subscribe to my RSS feed!


One-line variables swap in PHP, Ruby, Perl, Python and C

Joy in BlueToday’s fun and games: let’s swap a few variables without using more variables than necessary.

Let me know if you disagree with any of this…

$a = 1;
$b = 2;
list($a, $b) = array($b, $a);
print "a=$a, b=$b\n";
a = 1
b = 2
a, b = b, a
puts "a=#{a}, b=#{b}\n"
my $a = 1;
my $b = 2;
($a, $b) = ($b, $a);
print "a=$a, b=$b\n";
?View Code PYTHON
a=1
b=2
a, b = b, a
print 'a=%i, b=%i' % (a, b)

And now, good old C. Let’s use the only method that does not generate an overflow…first, for integer types:

int a=0, b=27;
a=(a^(b=(a=a^b)^b));
printf("a=%d, b=%d\n", a, b);

“Well,” you may say, “but what about pointers arithmetic? Any solution?”
Why, yes. That’s what I came up with after 15 minutes of fiddling:

char *a = "one", *b = "two";
a=(void *)(((long)a)^(long)(b=(void *)(((long)(a=(void *)((long)a^(long)b)))^(long)b)));
printf("a=%s, b=%s\n", a, b);

Note the use of void *, which allows me to ignore the pointer type. And, yes, I know, a C++ compiler may not really like this syntax. This may be doable using templates but I haven’t looked into that.
Sorry, I haven’t looked into Erlang or Haskell yet…

If you enjoyed this post, make sure you subscribe to my RSS feed!


PHP classes and Javascript: S2ajax says “hi()”

S2ajax LogoSajax is a ‘managed’ AJAX framework that was created by the fine folks at Modern Method a few years ago.
What’s so great about it is the seamless communication between your back-end and the web page itself: you write your PHP code, tell Sajax which functions to export and they are now accessible from Javascript.

For instance — from the ‘example_types.php’ file:

 function return_string() {
     return "Name: Tom / Age: 26";
 }

The corresponding Javascript call would be:

?View Code JAVASCRIPT
<button onclick="x_return_string(display_result);">Return as string</button>

OK so this is a pretty great package, no doubt.

Unfortunately there are exactly three things that bother me here:

  1. The choice to prefix all remote calls with ‘x_’ which feels less natural, even though it is a convenient way to avoid namespace collisions.
  2. More importantly, Sajax does not support PHP classes and I am not comfortable working with strictly procedural code. After all, object-oriented PHP has been around for quite some time now.
  3. Of course, it would seem that the last Sajax release happened sometime in 2006, which would explain #2

Thus, S2ajax was born.

If supports classes and methods, does not require prefixing and the export() calls are now more powerful.
The syntax is still very straightforward and relies on clean Javascript code.
And the license, obviously, is still the very open BSD.

Additionally, this S2ajax can be easily integrated with PHP 5’s magic class and methods loading. For instance, it works with my own PHP framework.

As usual, all this goodness is available at github.com!

If you enjoyed this post, make sure you subscribe to my RSS feed!


ExtPHP now on Github

Day CQ5 - Workflow EditorAbout 10 months ago, I released this tool, allowing developers to handle ExtJS like “managed” code in PHP: ExtPHP.

Shortly thereafter, Jack Slocum changed ExtJS’ licensing model and it all became very muddy but my main question was: “As a commercial user, what would the status of the extensions be?”
It seems that it’s OK to create an extension and not GPL it as long as it doesn’t contain any ExtJS original code. The claim is that most extensions now fall under that category. Of course, there is still the risk of an extension still containing ExtJS code — hint: that’s very likely — and the company who paid for ExtJS commercial licensing is now burdened with…what? De-facto GPL code? Or does the code that was reused considered “commercially licensed” as well? Even though it is part of an open-source extension?

Ten months later, I am not getting a sense that things were clarified well enough. Look at this topic on ExtJS’ forums. It looks like, after September, everybody gave up.

So, what now?

Well, if anyone could point me to a comprehensive answer regarding this issue, that will sure help me decide whether to revisit my decision to give up on ExtJS from a commercial standpoint.

In the meantime, ExtPHP is now available at Github.

If you enjoyed this post, make sure you subscribe to my RSS feed!


How I added real ActiveRecord support to adodb

Dead hard driveFor my new projects, I have decided to use PHP5, mostly because at least a couple projects will be worked on by a team and the learning curve is fairly forgiving.
I decided, however, to follow the model offered by Rails. I looked into a few PHP frameworks, such as Akelos, but realized that they were too constraining for our purpose. That’s when I decided to develop my own thin layer framework.

An excellent productivity tool is the ActiveRecord pattern. After all, it doesn’t matter what it is, that’s being mapped; whether it’s database tables or web services should not be relevant to the controller.
I have, in the past, used adodb successfully and I was happy when I realized that it comes with a ADOdb_Active_Record class.

Unfortunately, that class does a very basic job of mapping one class to a database table and that’s it. Therefore, support for has_many or belongs_to clauses.
I know that AR offers more features that those but I thought that these fit the very minimum requirement for them to be useful.
And that’s how I ended up modifying ADOdb_Active_Record to support these.

This article is mostly a series of listings that show the modifications-a bit-and how to use them-a bit more. First, here is how I am using them in my framework:
Let’s imagine a database that contains songs, artists and genres. Let’s look at the definition of a Song object:

<?php
class Song extends ActiveRecord
{
        function __construct()
        {
                parent::__construct('song');
                $this->belongsTo('artist');
                $this->belongsTo('genre');
        }
}
?>

and an Artist object:

<?php
class Artist extends ActiveRecord
{
        function __construct()
        {
                parent::__construct('artist');
                $this->hasMany('songs');
        }
}
?>

let’s have a look at a very basic controller that will allow us to retrieve our artists. Their songs will also be retrieved, since artists are defined as having many songs:

<?php
 
class ArtistController extends ApplicationController
{
        function index()
        {
                $artist = new Artist();
                $this->artists = &$artist->find(ALL, "artists.id=1", array('loading'=>ADODB_LAZY_AR));
        }
}
?>

Through the magic of my framework, which is outside the scope of this post, we will then be able to display our artists with their respective songs like so:

    <div id="colOne">
 
        <?php
        foreach($artists as $artist)
        {
                print "<h1>{$artist->name}</h1>";
                foreach($artist->songs as $song)
                {
                        print "&nbsp;&nbsp;&nbsp;&nbsp;TITLE:{$song->title}<br />";
                }
        }
        ?>
 
   </div>

Note that, for this example, I removed as many irrelevant pieces of code as possible. For instance, we are always retrieving artist #1. The array that we are passing to the find() statement allows us to configure some of AR’s behaviours. In this example, we are passing ADODB_LAZY_AR, which is a hint that we do not wish to perform massive joins, but retrieve related objects on demand. If we wished to retrieve everything upfront, we could have used ADODB_JOIN_AR instead.

Now, our model classes are subclasses of ActiveRecord, which is another one of my framework classes, which provides a light abstraction on top of ADOdb_Active_Record. The relevant piece, for you, would be this one since we invoke it:

        function find($mode, $condition=null, $extra=array(), $bindArr=false, $pKeyArr=false)
        {
                // id?
                if(ctype_digit($mode))
                        return $this->load($mode);
 
                // return one row
                if(FIRST == $mode)
                        return parent::load($condition);
 
                // Assumption: ALL == $mode - return multiple rows
                return parent::find($condition, $bindArr, $pKeyArr, $extra);
        }

It is interesting because the last line contains the actual call to ADOdb_Active_Record’s find() method.

In adodb itself, two files were modified: adodb-active-record.php and adodb.inc.php.

The former now contains two new structures: _hasMany and _belongsTo. ARs are now aware of the concept of foreign name, which is the name by which this object will be known to another object if a relationship is defined. This allows us, among other things, to naturally inflect tables names.

The latter was modified so that it accepts extra parameters, for instance in GetActiveRecordsClass(), and handle massive joins. Note that joins can be deferred through the use of ADODB_LAZY_AR. In which case I will use the model objects’ __get() method to load missing properties on-demand.

“Buyer Beware”
I hope to publish my full PHP framework in the near future; in the meantime, this hacked version of adodb has been very helpful in my work. I hope you too find it helpful. Beware, though: this is an early work and I would rather offer it to John Lim and let him integrate it in adodb-or can it if he’s too horrified!
I am aware of at least one bug, which may happen when using the join method on belongs_to objects. It could also do more things for you. Definitely not the cat’s meow.
But if you like it and need help, drop me a line.

Download

If you enjoyed this post, make sure you subscribe to my RSS feed!


My dilemma: rewrite and lose features or keep building on old framework?

I just posted the text below at http://www.nextbbs.com/do_topic_title_nextBBS-direction–please-give-your-input_id_1288

I know that a lot of open-source projects have gone through the same dilemma:

Well, what do we do now? Rip apart our existing software and restart with more up-to-date technologies, or keep building on the old workhorse, hoping that nothing will go wrong?
(more…)

If you enjoyed this post, make sure you subscribe to my RSS feed!


ExtPHP: An ExtJS Converter/Wrapper for PHP Developers

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

If you enjoyed this post, make sure you subscribe to my RSS feed!


How To Setup PHP5 with Tomcat 5

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:Tomcat5php directory and unzip the PHP zip file in it.
  4. Rename php.ini-dist, in c:Tomcat5php, to php.ini
  5. Extract php5servlet.dll from the PECL zip file to c:Tomcat5php
  6. Create a directory under c:Tomcat5webapps; in our case: phptest
  7. In c:Tomcat5webappsphptest, create a subdirectory: WEB-INF
  8. In c:Tomcat5webappsphptestWEB-INF, create web.xml with the following content:
    <?xml version="1.0" encoding="ISO-8859-1"?>
    <!DOCTYPE web-app PUBLIC
      "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN"
      "http://java.sun.com/dtd/web-app_2_3.dtd">
    <web-app>
            <servlet>
                    <servlet-name>php</servlet-name>
                    <servlet-class>net.php.servlet</servlet-class>
            </servlet>
            <servlet>
                    <servlet-name>php-formatter</servlet-name>
                    <servlet-class>net.php.formatter</servlet-class>
            </servlet>
            <servlet-mapping>
                    <servlet-name>php</servlet-name>
                    <url-pattern>*.php</url-pattern>
            </servlet-mapping>
            <servlet-mapping>
                    <servlet-name>php-formatter</servlet-name>
                    <url-pattern>*.phps</url-pattern>
            </servlet-mapping>
    </web-app>
  9. Extract/unjar (using jar xvf or WinZip) php5srvlt.jar under c:Tomcat5phptmp
  10. Modify both c:Tomcat5phptmpnetreflect.properties and c:Tomcat5phptmpnetservlet.properties, replacing
    library=phpsrvlt

    with

    library=php5servlet

    and save.

  11. Jar the content of c:Tomcat5phptmp into a new version of php5srvlt.jar
  12. Move php5srvlt.jar to c:Tomcat5commonlib
  13. Copy c:Tomcat5phpphp5servlet.dll and c:Tomcat5phpphp5ts.dll to c:windowssystem32
  14. Create a test page in c:Tomcat5webappsphptesttest.php with this contents:
    <?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.

If you enjoyed this post, make sure you subscribe to my RSS feed!