CMS Expo Presentations
Session 1: JavaScript and jQuery
This session will begin with a survey of JavaScript usage. We will then cover jQuery in some detail. From there we will move on to a more general discussion of how CMS systems can benefit from...
IE XMLHttpRequest, RSS feeds, and fixing it with Apache mod_rewrite
On occasion I have run into a strange problem, both with the RSS JavaScript widget downloadable from aleph-null.tv and with the code I wrote for Drupal 6 JavaScript and jQuery: Under certain conditions, the script simply does not work on IE 6, and IE 7. Firefox, Safari, and such don't seem to have...
Deploy: Move Drupal content from server to server in real time
The typical enterprise-grade publishing model for web sites typically has two or three tiers. Content is created and edited on a staging server, where it is carefully reviewed before publishing it to the live server. Additional development may even happen on a third ("development") server.
<!--break...
Flashy module: 100% open source Flash movie player for Drupal
Yesterday, Crell and I released the Flashy module (http://drupal.org/project/flashy). This module provides Drupal with a fully open source Flash video player. Building on our previous work, we created Flashy using the SWF Embed module.
Interested in just the flash video player? It's also licensed...
jQuery plugin and Drupal module for embedding Flash files
Today, Palantir.net is releasing several module that we built as part of our client work. One of these modules is the SWF Embed module. With this module, developers can create tools that include flash objects.
This module makes use of both PHP code and JavaScript code in order to provide robust Flash...
Precaching images in jQuery: A (slightly) better way
Matt Farina has suggested one method of precaching images using jQuery. But in some applications, this will not give the necessary cache lifetime (at least not in FF3) to warrant the extra network requests. Here, I suggest a slight modification that will make the cache last longer. <!--break--> The...
Debugging your PHP Code: XDebug on MAMP with TextMate and MacGDBp Support
xdebug.so
file to the correct location within MAMP:
~~~
$ cp 5.2/xdebug.so /Applications/MAMP/bin/php5/lib/php/extensions/no-debug-non-zts-20050922/
~~~
Now we have XDebug's shared object file in the correct place. The next step is to configure it.
Configuring XDebug
Next, configure PHP to load the xdebug module in the PHP ini file (php.ini
). This file is
located in /Applications/MAMP/conf/php5/
.
Near the end of the file, you will need to add a couple of lines like this:
~~~ ini
[xdebug]
zend_extension=/Applications/MAMP/bin/php5/lib/php/extensions/no-debug-non-zts-20050922/xdebug.so
xdebug.file_link_format="txmt://open?url=file://%f&line=%1"
~~~
This defines a new extension (xdebug
) and points PHP to the extension's shared object file.
The last line of the code above is optional. It tells xdebug to use TextMate to open files for viewing.
UPDATE: As sdboyer points out in the comments below, the Zend Optimizer, turned on by default in MAMP, must be disabled for XDebug to function correctly. Comment out the following lines in php.ini
~~~ ini
;zend_optimizer.optimization_level=15
;zend_extension_manager.optimizer=/Applications/MAMP/bin/php5/zend/lib/Optimizer-3.3.3
;zend_optimizer.version=3.3.3
~~~
Restart MAMP. The debugger should now be installed. The next time you get an error, XDebug will display a message that looks something like this:
In just a moment, we will take a detailed look at such errors.
Using XDebug
XDebug provides a number of facilities that you may find useful. It can produce code coverage reports, performance analyses, and detailed debugging messages.
But the first thing you are likely to notice is XDebug's stack trace messages.
Once you have XDebug installed as described above, the next time a PHP error occurs on your server you will notice something new. The old-style PHP errors and warnings are gone. Instead of seeing "PHP Error: Some message in somefile.php" you will get a detailed stack trace.
Let's take a look at an example. Here is a broken PHP script:
<?php
require 'tweet/QueryPath/QueryPath.php';
qp(QueryPath::HTML_STUB, 'body')->append('<p>Test</b>');
?>
The error in the script above is that the HTML passed into the append()
function has mismatched tags. (Visit QueryPath.org for more info on the QueryPath library.)
Here's a partial view of wheat XDebug generates when the above script is run:
This colorful table provides a wealth of information about the error. At the top, it shows the error message. Then it shows the stack trace, which is (roughly speaking) the list of functions from outermost to innermost that were currently being called when the script erred.
In other words, we can tell from the stack trace that {main} (the main script) was executing. It called QueryPathImpl->append()
at line 4, which in turn called QueryPathImpl->prepareInsert()
at line 416 of QueryPathImpl.php. That, in turn, called DomDocumentFragment->append()
on line 650 of QueryPathImpl.php.
Using this information, we can pinpoint where the error happened. The code caused an error when DomDocumentFragment->append()
parsed the broken piece of HTML. By following the stack trace from top to bottom, we can pinpoint (in our code) what the cause of these circumstances was. In our case, of course, it was our passing of a badly formed XML fragment.
Stack traces can provide a greater level of detail, making many bugs much easier to find. But sometimes you need (or want) to know more about what is going on behind the scenes. That's where a client-side debugger can really come in handy.
Hooking XDebug to a GUI Debugger
Many PHP IDEs provide integration with the XDebug debugger. But to use such debuggers, you will need to use the IDE for your projects. But sometimes a hefty IDE is not the best application development environment. Some developers (myself included) prefer lighter-weight editors like vi
, TextMate, Coda, and BBEdit. In these cases, an integrated IDE may not be an attractive or realistic proposition. Fortunately, there is a solution that fits this problem.
There are also stand-alone clients that provide simple debugging interfaces. In this section, we will look at the MacGDBp debugger, a simple tool for debugging.
MacGDBp provides a basic debugging interface. It does not provide performance testing or coverage analysis. Rather, it simply provides a front-end for stepping through PHP code as it executes. Of course, this is the most commonly used feature of a debugger. It provides a visual interface for viewing code and setting/clearing breakpoints, as well as common debugging features. Later, we will look at the interface in more detail.
You can download the latest version of MacGDBp at http://www.bluestatic.org.
When a debugging client is used with XDebug, there is some extra configuration which must be done. XDebug must be configured to communicate with an external debugging client. And, of course, the client must be configured to communicate with XDebug. Let's take a look at this configuration, which is particularly easy for MacGDBp and XDebug.
Configuring the Server
The first step is to configure the php.ini
file to allow XDebug to connect to debugging clients. We will need to revisit the same section of php.ini
that we created above. What we need to do there is tell the debugger that we now want it to send debugging messages to MacDBGp.
Here's the relevant section of the php.ini
file:
[xdebug]
zend_extension=/Applications/MAMP/bin/php5/lib/php/extensions/no-debug-non-zts-20050922/xdebug.so
xdebug.remote_enable = On
xdebug.remote_autostart = 1
The first two lines remain the same. But we add two new parameters:
xdebug.remote_enable
: This tells the PHP Apache module that we want to use remote debugging.xdebug.remote_autostart
: This tells PHP that we want it to immediately try to connect itself to a debugger as soon as it initializes.
The second directive is not necessary, and MacGDBp can be used without it. But in my experience, it performs better with auto-start turned on. Do not do this on a production server. This configuration should only be used on a development server on a secure network.
With this configuration, XDebug will attempt to connect to a debugger running on port 9000 of the localhost.
There are other configuration options for XDebug. You may want to check out the XDebug manual to learn about other supported configuration options. But what we have enabled here is sufficient for general debugging on a local workstation running MAMP and MacGDBp. This configuration will support HTTP POST operations.
Make sure you restart MAMP so that these changes take place.
Configuring MacGDBp
Configuring MacGDBp is even easier than the PHP configuration.
Once you have MacGDBp installed, simply open it up. You may want to change the IDE key (a shared key that the debugging server and debugging client both use). To do this, go to the MacGDBp > Preferences menu and change the key there. I will be using the default key, macgdbp
.
That's all there is to it. The defaults for MacGDBp should be sufficient for our needs.
Starting a Debug Session
Now that we have a configured server and a listening client, we are ready to give this a test run. I will use the same script I began with:
<?php
require 'tweet/QueryPath/QueryPath.php';
qp(QueryPath::HTML_STUB, 'body')->append('<p>Test</b>');
?>
In my browser, I will type in the appropriate URL: http://localhost:8888/err.php
(Note: If you do not turn on xdebug.remoteautostart
in php.ini
, you will have to add the URL parameter: ?XDEBUGSESSION_START=macgdbp
to get it to start.)
The page will not immediately load. In fact, the browser will sit there waiting for the server until it times out. How come? Because the server is waiting on the debugger.
When debugging code, the server awaits the instructions of the debugging client. After loading the code, it will not begin executing until the debugger sends it an instruction telling it to.
Looking at the debugger, we should be able to see a screen that looks something like this:
This is the main debugger window. At the top are the buttons used to control the debugging process. Beneath the button bar are two panes. The one on the left displays all of the variables currently in scope. As you progress through a debugging session, these values will change. You can watch them to see what is happening as you go.
The right pane shows the call stack. This provides a quick way of correlating where we are in the program's execution with locations in the source code.
Beneath these two panes is the main code window. This displays the source code that is currently being executed. The line about to be executed is highlighted in red.
To begin the debugging process, let's take a look at the button bar.
From left to right, the buttons are:
- Step into: Clicking this will advance the debugger one step and, if necessary, go "into" the function, class, file, etc. By clicking this button repeatedly, you can step through every part of the process.
- Step out: This will move up a level. For example, if you are mid-way through a function and you step out, the debugger will advance to the next part of the code, skipping the remainder of the function.
- Step Over (Skip): This will skip examining the next step. For example, if the current line is pointing to a function, and you do not want to see the function execute, you can skip it with this button. Clicking this will simply advance to the next line in the current scope.
- Continue (Play): Continue execution until either the next breakpoint or the end of the script.
- Reset: Remove the current debugging session and wait for the next request from the server.
Using these buttons, you can navigate through the execution of a script. While this will give you a detailed step-by-step analysis of a program as it executes, it can often be overkill. More often, you will want to analyze just a small part of your script. That is best accomplished with breakpoints.
A breakpoint is a marker that tells the debugger to pause when the location is reached. Using breakpoints, you can set the debugger to play through most of the code, pausing only when it gets to the portion of interest.
To set breakpoints in MacGDBp, navigate to the Windows menu and click on Breakpoints. There you can view and edit breakpoints.
To add a new breakpoint, click on the + button in the lower-left and then select the desired file from within MAMP's htdocs directory. Once you are viewing the file, you can set a breakpoint by clicking on a line number. This will overlay a blue arrow on top of the line number. (Clearing the breakpoint is done by clicking on the arrow.)
You can set as many breakpoints as you want.
Once breakpoints are set, clicking on the Continue button during a debug session will cause the code to execute until it hits the next breakpoint. This method can be much faster than stepping through the code.
Once you have finished executing a script, the Reset button will be activated. You will not be able to start another debugging session until you have reset the debugger.
Conclusion
That is all there is to configuring and using XDebug with MAMP, TextMate, and MacGDBp.
But we have come nowhere near exhausting the capabilities of XDebug. With profiling and cache grinding, you can better understand how long your program takes, and what areas are bottlenecks. With coverage analysis (in XDebug 2), you can determine how much of the code is being exercised -- an invaluable tool for automated testing. In fact, in XDebug 2, you can even interact with the debugger directly.
For now, though, the basics are covered. You should be able to install XDebug on MAMP, configure it to use TextMate and print stack traces, and also set it up to send debugging information to MacGDBp.
PHP 5 Runkit for MAMP 1.7.2
Ever tried to get PHP's Runkit PECL extension running on the popular MAMP stack for Mac OS X? If you have tried, you will understand why it is difficult. There are two roadblocks that must be overcome before Runkit can be installed.
The first has to do with MAMP itself. While MAMP provides most of...
Drupal QueryPath 1.1 Module Released
Today the QueryPath 1.1 Drupal module has been released. This module provides Drupal developers with access to the QueryPath library. In addition, it integrates Drupal's database library with QueryPath, making it possible to execute Drupal database queries and feed the results directly into QueryPath...
Twitterpated, TweetStock updated
Today I uploaded a new version of Twitterpated to the QueryPath.org server. This new version is smaller in (network) size, and has a few minor bug fixes. Also released along with it is TweetStock. TweetStock is a Twitter search client for an iPhone. It's actually a very simple overlay on the official...