The Observer Pattern in PHP: Refactored

November 22nd, 2008 by Aaron

You may remember the article I wrote about the observer pattern in php - but it lacked some of PHP’s advanced features.

In this next example, I’m not going to explain the logic as much - read the original post for more - but I did comment it pretty thoroughly. Here are the things that I added, however:

  • Type hinting in functions
  • Abstract classes
  • Interfaces
  • A registry of observers

So, here is the code:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
<?php
/**
 * twitter transport from "library" - on successful tweet will print it out 
 */
class twitterTransport
{
    public function __construct()
    { /** logic here **/ }
 
    public function tweet(twitterMessage $object)
    { /** logic here **/  print $object->message . ' was just tweeted'; }
}
 
/**
 * url shortener from "library" - just replaces [url] with [u] in a string
 */
class urlShortener
{
    public function shorten($message)
    {
        return str_replace('[url]', '[u]', (string) $message);
    }
}
 
/**
 * twitter message class - very simple - just holds the message inside itself as a string
 */
class twitterMessage
{
    public $message = '';
 
    public function __construct($message)
    {
        $this->message = (string) $message;
    }
}
 
/**
 * Observer for shortening URLs
 *
 * This class gets envoked when there is a PREPOST action, and invokes
 * the urlShortener::shorten() against it
 * @see iObserver
 */
class urlShortenerObserver implements iObserver 
{
    /**
     * Tells the type of observing this will do
     * @return string
     */
    public static function getType()
    {
        return 'PREPOST';
    }
 
    /**
     * The notification method - is called when a PREPOST is done. shortens url
     * @param twitterMessage $object
     */
    public function notify($object)
    {
        $urlShortener = new urlShortener();
        $object->message = $urlShortener->shorten($object->message);
    }
}
 
/**
 * The twitter message sender, is observable, sends a message with the postMessage
 * function
 * @see observable
 */
class twitterTransportObservable extends observable
{
    /**
     * post a message to twitter, notifying any observers
     * @param twitterMessage $object
     * @see twitterTransport
     */
    public function postMessage(twitterMessage $object)
    {
        $this->_notify('PREPOST', $object);
 
        $sender = new twitterTransport();
        $sender->tweet($object);
 
        $this->_notify('POSTED', $sender);
    }
}
 
/**
 * abstract observable class - extended for all observable items, contains the array
 * of observers, the register and the notify commands
 */
abstract class observable
{
    /**
     * @var array the observer classes
     */
    protected $_observers = array();
 
    /**
     * used for registering observers, or adding them to the array
     *
     * Keep in mind, this adds them in the same order as they're added to
     * the array, so that may affect the final outcome
     *
     * @param string $type The type of observer, hook name
     * @param object $observer The observer class
     */
    public function registerObserver($type, iObserver $observer)
    {
        if (empty($type)) throw new exception("type was empty when registering " . get_class($observer));
        if (!isset($this->_observers[$type])) $this->_observers[$type] = array();
        $this->_observers[$type][] = $observer;
    }
 
    /**
     * used to notify self of actions of a certain type, launches observers
     *
     * @param string $type The Type of observer, the hook
     * @param object $object The observer object
     */
    protected function _notify($type, $object)
    {
        if (isset($this->_observers[$type])) {
            foreach ($this->_observers[$type] as $observer) {
                $observer->notify($object);
            }
        }
    }
}
 
/**
 * interface for any observer classes
 */
interface iObserver
{
    public function notify($object);
    public static function getType();
}
 
/**
 * launching code
 */
 
/**
 * global observers is an array of items which are shared in all launching software
 * tells which observers are associated with with observable
 */
$globalObservers = array('twitterTransportObservable'=>array('urlShortenerObserver'));
 
 
$tweeter = new twitterTransportObservable();
 
/**
 * assign all observers from our globalObservers
 */
if (isset($globalObservers['twitterTransportObservable'])) {
    foreach ($globalObservers['twitterTransportObservable'] as $observer) {
        $tweeter->registerObserver(call_user_func(array($observer, 'getType')), new $observer);
    }
}
 
$message = new twitterMessage("this is my message [url]");
 
$tweeter->postMessage($message);

How custom passphrases/pictures still don’t protect against phishing

November 20th, 2008 by Aaron

As you probably remember, I have lots of interest in phishing techniques (I talked about one here, and preventing them here). I’ve noticed a new trend: a dual stage login form with a custom picture or passphrase. Users are to gain trust in the login page because their custom configured option is displayed. The more I started thinking about this, however, I kept seeing an issue - this still can be easily phished! I’m going to demonstrate a method of phishing the passphrase version. I don’t want to do a picture example because it a) takes more code and b) more people have moved to that thinking it is more secure. Lets go:


First off, all phishing starts with getting the user to a login page not at the respected domain. So, lets just skip that step, and examine our login page. This will be a duplicate of our real site’s login page - note the reminder that they will have to verify their passphrase.

login.php @ fakedomain.com

1
2
3
4
5
<form action="login2.php" method="post">
    <label>Username: <input name="username" /><br />
    <em>Remember, you will be asked to verify your passphrase on the next page.</em><br />
    <input type="submit" value="Login" />
</form>

Very simple login which sends it to another page - hopefully named the same as the real domain’s login page.

Lets look at the page we’ll be submitting to:

login2.php @ fakedomain.com

1
2
3
4
5
6
7
8
9
10
11
12
13
14
    /** cutting out a lot of code - make sure its not empty, etc **/
    $args = array ('username'=>$_POST['username']);
    $uri = 'http://realdomain.com/login.do.php';
     $opts = array('http'=>array('method'=>'POST', 'header'=>'Content-Type: application/x-www-form-urlencoded', 'content'=>http_build_query($args)));
     $context = stream_context_create($opts);
    $page_with_phrase = file_get_contents($uri, false, $context);
 
    $doc = new DomDocument();
    $doc->loadHTML($page_with_phrase );
 
    $passphrase = $doc->getElementById('passphrase_node')->nodeValue;
 
    /** next login form page actually shows the $passphrase phrase and asks for password **/
    include('next_login_form.php');

Ok, first off, you’ll see we create a nice post with our stream context creation (detailed here) - so we basically send the username to the real domain as they had logged in. (Depending on the target site, you might also have to send referrers, cookies, etc - but we’re making it a really simple example here.)

We retrieve the page after a successful post of the username. This content should now contain the custom passphrase somewhere. For our example, there is a nicely named div or span with an id of ‘passphrase_node’. Probably, in real life, you’d have to use a complex xpath to get the actual value.

From then on, we just include our ’second’ login page which shows the passphrase, and then requests the password from the user. From there, you can do whatever you want.

Ok so…
Its nice to see that people are trying to eliminate phishing - but there still is only one real solution IMHO - and that is to educate users on the address bar (or get them to install a plugin that validates the page they’re on.).


Unofficial xdebug ini - with comments!

November 18th, 2008 by Aaron

I found a great article about the xdebug ini file - someone went through and added comments - much like the apache conf files. Amazingly well written.


Understanding the Observer Pattern in PHP

November 17th, 2008 by Aaron

For a while, I’ve been looking at plugin systems, but not really fully understanding the pattern behind them. Don’t get me wrong, I see how they work, but I didn’t know the reason why - the theory or pattern behind it. Well turns out, generally, they’re based upon the observer pattern. I decided to write my own observer pattern demonstration here.

Our example is going to be very simple: post a message to twitter. We’re not going to work with any credentials or anything, just want to post a message. I do want to add an observer that will shorten any url however. In this example, we’ll be making the logic classes stubs (you can create these later), and using ‘[url]‘ to stand for an URL we might replace.

Lets start in:

Our two logic classes

Remember, we’re just going to have some blank stub logic classes here. They are for demonstration purposes only.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
class twitterTransport
{
    public function __construct()
    { /** logic here **/ }
 
    public function tweet($object)
    { /** logic here **/ print $object->message . ' was just tweeted'; }
}
 
class urlShortener
{
    public function shorten($message)
    {
        return str_replace('[url]', '[u]', $message);
    }
}

Pretty simple, the first class all it does is post to twitter with a public method called tweet(). This accepts an object of the twitter message (which we’ll list next!). It prints out the message so you know what we would have sent to twitter. The url shortening class - all it is is your logic to shorten urls inside of a message. In this case, pretty simple.

Ok - as promised, here is our twitter message class:

1
2
3
4
5
6
7
8
9
class twitterMessage
{
    public $message = '';
 
    public function __construct($message)
    {
        $this->message = $message;
    }
}

The actual launching code

We’re going to jump a head here and show what code we’ll be using to add the url shorterner as well as post the message. It’s really short - but it’ll give us an idea of what class we need to create next:

1
2
3
4
$tweeter = new twitterTransportObservable();
$tweeter->registerObserver('PREPOST', new urlShortenerObserver());
$message = new twitterMessage("this is my message [url]");
$tweeter->postMessage($message);

Ok good. First off, we create a new instance of twitterTransportObservable. By the keyword Observable, we can tell that this class is something that will “do something we can watch” or observe. Any time a class is Observable, it has to have a method to add watchers to itself - or registerObserver(). In our example, we’re sending in a type - “PREPOST” - so before we post the message, and a new object.

The new object is of type urlShortenerObserver(). We can see that this will be a ‘watcher’ by the name. No more details are given here, so its methods must be used/exposed inside of the Observable class.

Next, we’re just making a new twitter message object, pretty simple.

Finally, we’re calling postMessage() sending in our twitter message. Remember, $tweeter is an instance of twitterTransportObservable, so there must be a method called twitterTransportObservable::postMessage().

So far so good.

Looking at the Observable Class

So now we know we need to build twitterTransportObservable. I’m going to post the code here, but don’t worry, we’ll take it apart, step by step:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
class twitterTransportObservable
{
    protected $_observers = array();
 
    public function registerObserver($type, $observer)
    {
        if (!isset($this->_observers[$type])) $this->_observers[$type] = array();
        $this->_observers[$type][] = $observer;
    }
 
    public function postMessage($object)
    {
        $this->_notify('PREPOST', $object);
 
        $sender = new twitterTransport();
        $sender->tweet($object);
 
        $this->_notify('POSTED', $sender);
    }
 
    protected function _notify($type, $object)
    {
        if (isset($this->_observers[$type])) {
            foreach ($this->_observers[$type] as $observer) {
                $observer->notify($object);
            }
        }
    }
}

Ok - pretty big - lets go slow:

First off, we have the $_observers. Since this class is of type observable, we know it has watchers. Well, it has to be aware of its watchers, because it registers them… so we need an array to hold all of our watchers, or $_observers.

The first method is registerObserver(). You’ll see this takes in a variable called $type and a variable called $object. Well, we saw this used in our launching code. It appears that this was started with ‘PREPOST’ as the $type and a new urlShortenerObserver as the $object. Moving along, the $_observers array is keyed by $type - so we just did some good programming: if the key is not set, set it by creating an empty array. Finally, the next line grabs that array, and adds the passed in $object to the internal array of $_observers. So now, our observable class has its first observer. An important thing to note is that the order you add them using registerObserver(), is the order they will remain in the array in the Observable class.

Quick reminder: Remember, objects are passed by reference!

Next, we have the postMessage() function - which takes in an object of a twitter message. The first thing the function does is notify our self that we’re PREPOST, while passing in the $object to that notify call. Think of this as the ‘hook’ - or someone yelling at the watchers saying “Anyone of type PREPOST, I’ve got this $object for you to deal with!”. Next, this function creates a new twitterTransport and tweets the object. Remember, the $object has now returned from the notify call and may be changed. Finally, there is another call to _notify with “POSTED” as the type. This is just for example, our example doesn’t really need this. But, imagine you created an observer which logged the output of twitter’s response to your post? This would be perfect for that hook.

Ok, so the last thing we have to look at is the _notify() function - which we’ve called a few times during our postMessage(). This simply looks to see if there is an observer that we’ve been storing locally keyed on the $type key. If there is a key of this $type, we loop through each observer of that $type, and pass in our object to its notify() function. OK - don’t get confused, that notify() function is different than our _notify() function. It belongs to the observer (in our example, urlShortenerObserver::notify()). So basically, it calls all the observer’s notify() with a reference to the object, and its done.

Whew, that was a lot - but we have one more part left:

The Observer class

We have another class that is used to observe or watch the observable classes. In this case, we wanted to have any URLs shortened before we posted a message to twitter… so we registered this observer with PREPOST. During the Observable’s _notify() function, we called this observerable class’s notify() method. So, lets finally take a look at the code:

1
2
3
4
5
6
7
8
class urlShortenerObserver
{
    public function notify($object)
    {
        $urlShortener = new urlShortener();
        $object->message = $urlShortener->shorten($object->message);
    }
}

Pretty simple class. It has only one method, called notify() which accepts an object - of type twitterMessage. The first line just creates a new urlShortener() - you remember from way up top? Just a quick str_replace type method. Then, the next line accesses the urlShortender::shorten() method - by passing in the public $message variable of the twitterMessage. The return value is assigned to the twitterMessage::$message var. And remember, since objects are passed by reference, when the next line of the the observable’s class is called, the object will now be modified.

Wrapping Up

Ok - well this was a pretty simple example of this behavior. There are definitely more complex ways and more business logic intense scenarios to use the observer in. Another thing we didn’t do is use many of PHP’s OO properties - but we could always refactor and do that in the future.

All the code

In case you want to run it yourself:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
<?php
class twitterTransport
{
    public function __construct()
    { /** logic here **/ }
 
    public function tweet($object)
    { /** logic here **/ print $object->message . ' was just tweeted'; }
}
 
class urlShortener
{
    public function shorten($message)
    {
        return str_replace('[url]', '[u]', $message);
    }
}
 
 
class twitterMessage
{
    public $message = '';
 
    public function __construct($message)
    {
        $this->message = $message;
    }
}
 
class urlShortenerObserver
{
    public function notify($object)
    {
        $urlShortener = new urlShortener();
        $object->message = $urlShortener->shorten($object->message);
    }
}
 
class twitterTransportObservable
{
    protected $_observers = array();
 
    public function registerObserver($type, $observer)
    {
        if (!isset($this->_observers[$type])) $this->_observers[$type] = array();
        $this->_observers[$type][] = $observer;
    }
 
    public function postMessage($object)
    {
        $this->_notify('PREPOST', $object);
 
        $sender = new twitterTransport();
        $sender->tweet($object);
 
        $this->_notify('POSTED', $sender);
    }
 
    protected function _notify($type, $object)
    {
        if (isset($this->_observers[$type])) {
            foreach ($this->_observers[$type] as $observer) {
                $observer->notify($object);
            }
        }
    }
}
 
$tweeter = new twitterTransportObservable();
$tweeter->registerObserver('PREPOST', new urlShortenerObserver());
$message = new twitterMessage("this is my message [url]");
$tweeter->postMessage($message);

Posting Requests in PHP without CURL

November 14th, 2008 by Aaron

Can it be done? YES! Luckily, functions like file_get_contents() support stream contexts.

In this example, I want to post to my form my login credentials of username “aaron” and password “chicken”. This will be posting to the URL of http://test.com/login.do.php. I’ll show the code first, and then lets talk about what it does.

1
2
3
4
5
6
7
8
9
10
$args = array ('username'=>'aaron', 'password'=>'chicken');
$uri = 'http://test.com/login.do.php';
 
$opts = array('http'=>array('method'=>'POST', 'header'=>'Content-Type: application/x-www-form-urlencoded', 'content'=>http_build_query($args)));
 
$context = stream_context_create($opts);
 
$result = file_get_contents($uri, false, $context);
 
print $result;

Lets disect line by line:

The first line dealing with $args is setting up our post parameters. The next line is our uri target. If this was an HTML form, it might look like this:

1
2
3
4
5
<form action="http://test.com/login.do.php" method="POST">
Username: <input name="username" /><br />
Password: <input name="password" /><br />
<input type="submit" />
</form>

The next line is the $opts array. This will be the options that we send to the stream context. The array is keyed by the type of stream we’re creating here - in this case ‘http’. This points to an array of options. First, the method of the request, in this case “POST”. Next, the header that must be sent in order to submit the request. For the most part, your browser handles sending this - but we have to specify it here. It simply is keying the request to let it know that its a form submission. The final key is the content key - which is what is submitted in a typical request below the headers. Here we’re using PHP’s http_build_query() to save ourselves some time.

Moving on, we create a new context using stream_context_create(), assign that to $context using $opts as our parameter. Think of $context not as a value, but as a handle - similar to an fopen or other resource handle.

Finally, we retrieve the contents of our request using file_get_contents(). Do note: you must have fopen_url = true in your php.ini. This allows us to retrieve content via an external URL. We pass the location of our post request, false because we don’t want send any additional flags, and a pointer to our stream context.

After this is complete, we should have the output in the $result variable.


How to throw an AMAZING meeting

November 13th, 2008 by Aaron

I’ve been to far more meetings than any one on earth should ever have had to by the time they’re 25. With that experience, however, I can start to pick out key points of running a great meeting or demonstration. I know this is a different type of post for this blog, but I think its important. There may be times that you’re called on to conduct a meeting or demonstration, as a technical resource. Follow these tips and your meeting will go along smooth, effeciently and successfully.

Planning

Have an Outline

Outline the points you’re going to cover. Provide more elaboration on an outline that you refer to as your Internal outline. Examples of this include writing a more thorough document for yourself or using the notes section for your powerpoint presentation (simply print out the slides with notes for yourself, give everyone else the slides only.)

Send your outline out before the event. Gauge the busyness of your audience to figure out when you should send it out. Don’t send it out 10 minutes before the meeting if you have people who are traveling or may be in other meetings. Conversely, don’t send it out too many days in advance - it may get lost in the pile of other things your atendees have to review.

Test Technical Items

You should run through any technical demonstration at least once before you create the presentation. Everyone remembers Bill Gate’s famous BSOD during his demonstration of Windows - and I’m sure that was even a rehearsed demonstration. Try to avoid situations like this by testing your technical aspects ahead of time.

Arrival

Arrive Early

If you are either facilitating the meeting or participating in it, make sure to get there early. We’re not talking hours early - but you should aim to be the first person there. This will help you build confidence in arriving parties: they know you’re there, prepared, in control and ready to present to them. It can be an uncomfortable experience to arrive at a meeting when there is no one else in the room. Attendees might question that they’re in the right room, if they have the right time, etc. This also provides you time to verify that any presentation aides are available.

Intro on Time

Generally, when sending out a meeting invite, there is a concise summary of what the meeting is about. When the meeting is scheduled to begin, begin your introduction. This does two useful things for you: first, it reminds attendees who may be hopping from meeting to meeting what the content of this meeting will be. Second, it sends a message that you are in control of the meeting, and that attendees can trust that you will end the meeting on time - and that their time is not being wasted. Sometimes people take this to an extreme and start the content right at the time. Don’t do this! Sometimes things happen - allow for a little leeway - but make sure that the time counts. Your intro may be 1 to 2 minutes starting exactly at the meeting start time. Enough time for those who are trying to make it in on the wire to attend.

Present

Provide easy ways of feedback

Some attendees may feel too nervous to shout out a question during your presentation. Start out by telling them that you can either stop you with a question or get my attention by waving your hand or directing it at you. You may want to give a demonstration of casually getting someone’s attention. Then, be attentive! Sometimes your best questions will come from people who are too meek to make a huge presentation.

Ask Questions

Along the way, its fine to ask questions - or better yet - encourage questions. Summarize a point and ask if there is any clarification needed on that point. Its useful to remind people that they can ask questions - that this is an interactive presentation. Don’t be surprised if someone asks a questoin about the last point. Sometimes its easy to become presentation-tranced and forget to ask the question.

“No” Questions vs “Yes” Questions

This is particularly useful on telephone conversations - where you can’t see any visual cues. Try phrasing your questions to elicit answers only if the conditions are not satisfactory. So, for example, instead of saying “Does everybody understand what was just demonstrated?” - and waiting for people to overlap and possibly not answer or interupt each other, rephrase: “Is there anyone that does not understand what was just demonstrated? We can demonstrate it again.” You’ve provided an opening to receive only feedback from those who need it - while framing the question into a positive situation. An attendee might be scared to say that they missed something - but would be willing to agree with your suggestion to do the demonstration again.

Finishing

One more time - questions?

Ask for questions. Attendees may have been writing down questions, intent on not interupting your demonstration.

Thank them

Thank your attendees for their time. While you may have spent more time preparing and presenting, you did interupt their day to present your content. Presenting and serving someone else is a highly regarded activity - so thank them for the opportunity by recognizing their important contribution and time.

Explain and Send Followup

If any other materials were created during the presentation, or if it was recorded, tell your attendees about this. Make sure that they know that you will be sending it to them. Give a timeline and then stick with it!

Well that about sums up my tips I try to follow when organizing a meeting. Any others?


|
©2008 102 Degrees LLC - All Rights Reserved Home Services Products Network Blog Open Source Learning Contact