Tuesday, February 28, 2006

http://www.cingo.com/

http://www.cingo.com/

from the web site:

Cingo is a simple, easy and powerful new way to experience the internet and organize your family in one great location!

From the clean, uncluttered home page to feature-rich sections such as News, Movie Listings, and Shared Calendar and To-Do Lists, Cingo helps your family to easily stay connected online. And best of all, Cingo is free!

Open-Source Web Design

http://www.oswd.org/
Open-Source Web Design
...lots of web designs with code and graphics.

ASP (vbscript) to print html form's contents

<% 'using asp (vbscript) to print form variables %>


<table border="2">
<tbody><tr>
<td><b>Form Variable</b></td>
<td><b>Value</b></td>
</tr>
<% Dim Item For Each Item In Request.Form response.write "form value==_____"&Item&amp;" = "&Request.Form(Item)&amp;" " %>
<tr>
<td><span style=""><% = Item %></span></td>
<td><span style=""><% = Request.Form(Item) %> </span></td>
</tr>
<% Next %>
</tbody></table>

<% ' end of printing the Form variables %>

Monday, February 27, 2006

Do good and shop more!

http://www.greatergood.com/cgi-bin/WebObjects/GreaterGood
A nice site that allows you to buy products from major vendors and have upto 30% of your purchases go towards a worthy non-profit organization.

nice .htaccess overview tutorial

http://www.vortexmind.net/index.php/2006-02-26-apache-htaccess-tweaking-tutorial/
covers:
1. Folders Access Control
2. Folder Listing
3. Enable Compression
4. Hide your files
5. Customized HTTP 404 error page
6. Blocking bad referers - No hotlinking
7. Blocking Bad Bots | Fetchers
8. Do not show ‘www’
9. Hide scripting language extension
10. Various Tips & Tricks
11. Password Protection with htpasswd
12. Enabling SSI
13. Changing default page
14. Avoid 500 error
15. CheckSpelling directive
16. Add MD5 Digest
17. Sources
18. Tools

Friday, February 24, 2006

yahoo useful social functions

http://publisher.yahoo.com/social_media_tools/

yahoo created an easy set of commands for adding several useful social functions to your web page: -bookmark
-send by email
-blog
-print

10 mac programs that are worth knowing

click here for the site
a nice list of 10 mac shareware/freeware programs that deserve more attention

Mac RSS reader

http://www.newsfirerss.com/ - an RSS reader for the mac

Thursday, February 23, 2006

new airline ticket web site

http://www.flyspy.com/
a neat little site that helps you find cheap airplane tickets, and calculate what day is best to fly

AJAX Zip-Code Look-up tutorial

http://www.webpasties.com/xmlHttpRequest/

An awesome tutorial about how to install a simple AJAX request into your site. It even incorporates a zipcode lookup service, so it can be used on many different systems.

BackPackIt

http://www.backpackit.com/
a web site to help with organizing your everyday tasks. This is the version for individuals. For large groups on a project, you can use their other web site, Basecamp.com


from the web site:

Make a page out of an idea

Backpack makes it easy to flesh out your ideas. Start with a a title: "My trip to Paris" or "Furniture I eventually want to buy" or "Things I want to do this summer" or "My favorite quotes" or "Ideas for the bathroom renovation" or "People we need to interview for the job".

Then add free-form text, to-dos, notes, photos, files

After you've created a page, you can add a to-do list, or notes, or photos, or attach files, and more. You can even send an email to the page and it will automatically be posted to the page.

Share pages with other people

Want to collaborate with someone? With 10 people? No problem. Create a page and share it with your friends or co-workers. Get things done together on your own private shared web page. You can also publish pages for anyone in the world to see.

Set email and mobile phone reminders so you don't forget

Tell Backpack to remind you about something tomorrow morning, or next Monday, or in a couple of weeks, or at an exact time. Backpack will send you (or even your cell phone) an email so you don't forget.

USPS Zip Code Web Service

http://www.usps.com/webtools/address.htm
The USPS offers a web service for looking up zip code information

http://script.aculo.us/

http://script.aculo.us/

from the web site:

script.aculo.us

In an attempt to consolidate into one place all the scripts that happened to come into existence over the last few months, I've finally managed to come up with this site. Hope you like it.

Yahoo! PHP Developer Center

http://developer.yahoo.net/php/

Welcome to the PHP Developer Center

From simple scripts to enterprise-class web applications, PHP is one of the most popular programming languages in the world. This site is your source for information about using PHP with Yahoo! Web Services APIs. Here you'll find:

  • HOWTO Articles to help you understand our technologies and how you can use them better with PHP.
  • Code Samples you can play with. Use them as a starting point for your own applications or study them for subtle nuances.
  • Other Resources out on the Web to help you use PHP and the Yahoo! APIs to their fullest.
  • Community Resources where you can join our mailing list and discuss the Yahoo! APIs with us and with other PHP developers.

Wednesday, February 22, 2006

css style might be nice to incorporate into other concepts

http://www.summeratdelphi.org/

online book for business

http://www.brucejudson.com/frombook.html
book about how to build your own business

mac speed improvements

http://www.macworld.com/2006/02/features/softwarespeed/index.php
mac tune-up tips

online business tips

Tuesday, February 21, 2006

tutorial on backups with cron, rsync, and ssh

tp://www.jdmz.net/ssh/
tutorial on backups with cron, rsync, and ssh

RSS Feed introduction

http://blogs.chicagotribune.com/news_columnists_ezorn/2006/02/23_real_simple_.html

web design development online magazine (e-zine)

http://www.digital-web.com/

php classes that adjust or bend at run-time

http://www-128.ibm.com/developerworks/opensource/library/os-php-flexobj/?ca=dgr-lnxw01DynamicPHP

Monday, February 20, 2006

CSS layout tutorial

http://www.subcide.com/tutorials/csslayout/

php live search code

http://orderedlist.com/articles/howto-animated-live-search/

free computer books online

http://maththinking.com/boat/hardwareBooksIndex.html

Friday, February 17, 2006

MAMP

...a similar application for Mac OS X called "MAMP". (Macintosh, Apache, Mysql and PHP.) You can download it for free at:
http://www.mamp.info/

MAMP puts everything you need in an easy to double-click application. This is great if you need to work on a web project for only a short time -- simply drag the app to your trash to delete (Apache, MySQL & PMA).

new web start-up formula?

http://www.microisv.com/
something about micro businesses (1-5 people, self-funded, web-based new business)

mac backups

http://www.digital501.com/2006021110/mac-backup-osx/
some info on unix commands that are available on the mac to automate backups

--------

"My method is a terminal job that runs at login, which is a simple saved rsync command. I just back up my user folder, but in principle this could be extended to the whole drive (I assume). Rsync has the advantage that it only moves those files which have changed - usually the script is done in a couple minutes.

The command takes the form of

sudo rsync -rlptv –delete /Volumes/(internal hard drive)/Users/ /Volumes/(external hard drive)/Users/

I just save that command as a .term file and add it to my login items."

---------------


Another alternative is to use rsync (or rsyncX) to create a clone without copying every file, every time.

Also, instead of using cron, an daily backup command can simply be added to /etc/daily.local. This will include “custom” commands in the pre-existing scheduled process. Results will be written to /var/log/daily.out.

----------

Try this :


#!/bin/sh

echo "################################################################"
echo "### Server backup"
echo "### `date`"
echo " "

if [ -d "/Volumes/Mac OS X 1" ] ; then
echo "!!! Error : Something went wrong the last time"
echo "### "
echo "### `date`"
echo "### Backup failed"
echo "################################################################"
echo " "
exit 1
fi

if [ -d "/Volumes/Sauvegarde" ] ; then
echo "### destination volume /Volumes/Sauvegarde found"
else
echo "!!! Error : Destination volume absent"
echo "### "
echo "### `date`"
echo "### Backup failed"
echo "################################################################"
echo " "
exit 1
fi

/usr/sbin/asr -erase -noprompt -source /Volumes/Mac\ OS\ X -target /Volumes/Sauvegarde

/usr/sbin/diskutil rename /Volumes/Mac\ OS\ X\ 1 Sauvegarde

echo "### `date`"
echo "### End of backup"
echo "################################################################"
echo " "

You have to rename the disk at the end, because asr does a plain clone, including the volume name.

The check for Mac OS X 1 is because one day something went wrong in the middle of the backup, and the machine rebooted. As there were two Volumes named Mac OS X , one of them was labelled Mac OS X 1 internally. AND IT WAS THE BOOT VOLUME !!! I could get it fixed before my script would have renamed the internal disk to “Sauvegarde” and backed up the bacup to the internal disk at the next run.
This problem is mainly because my backup-disk is firewire, and I have two of them (even and odd days) and therefore I can’t use /dev/diskxx sthle addressing, because it’s never the same address when I swap disks.

----------------

open a terminal and type “man asr”. This will show the documentation for the “asr” command. Disk Utility is a GUI for the asr command. You can script the asr command.



PHP MVC (part 3 of 3) - from ONLamp

Implementing MVC in PHP: The View

by Joe Stump
01/26/2006

This is the third article in a series about understanding MVC in PHP. The first article explained basics of MVC programming in PHP. The second article showed the implementation of the Controller in MVC.

The presentation layer, as I call it, is the View, in common MVC terms. Its sole responsibility is to display information. It could care less about authenticating users, what the data is or, for the most part, where it came from. The only thing it has to worry about is how to render it and where to send it once rendered.

By default, the framework uses Smarty to render the framework. I'm not here to argue semantics, but your presentation layer should consist of a template engine of some sort and a few supporting presentation layers.

The idea is that, after the Model runs, the framework hands it off to a child of the FR_Presenter_common class. Actually, the framework uses the FR_Presenter::factory() to create the presenter. Each presenter should have a display() method that does the actual rendering. When the factory creates the presenter, it passes the presenter the instance of the model class. The presenter then gets the model's data using its getData() method. From there, the presenter is free to present that data however it sees fit.

FR_Presenter_smarty

The way I've created my Smarty presenter is a hybrid of two templates. I create a Smarty template, and the outer page template includes the model's template. The model class's $pageTemplateFile can request a particular outer template. If it does not, the default is tpl/default/templates/page.tpl. The page.tpl template then uses the {$modulePath} and {$tplFile} directives to include the model's template. All model templates should reside in modules/example/tpl/.

After assigning the variables, the controller runs Smarty's display function to render the templates. With little modification, you could wrap these calls with Smarty's built-in caching as well. By using Smarty, you could enable an output modifier to output gzipped code instead of plain HTML.


/**
* FR_Presenter_smarty
*
* @author Joe Stump
* @copyright Joe Stump
* @license http://www.opensource.org/licenses/gpl-license.php
* @package Framework
* @filesource
*/

require_once(SMARTY_DIR.'Smarty.class.php');

/**
* FR_Presenter_smarty
*
* By default we use Smarty as our websites presentation layer (view). Smarty
* is a robust compiling template engine with an active community.
*
* @author Joe Stump
* @package Framework
* @link http://smarty.php.net
*/
class FR_Presenter_smarty extends FR_Presenter_common
{
private $template = null;
private $path = null;

public function __construct(FR_Module $module)
{
parent::__construct($module);
$this->path = FR_BASE_PATH.'/tpl/'.FR_TEMPLATE;
$this->template = new Smarty();
$this->template->template_dir = $this->path.'/'.'templates';
$this->template->compile_dir = $this->path.'/'.'templates_c';
$this->template->cache_dir = $this->path.'/'.'cache';
$this->template->config_dir = $this->path.'/'.'config';
}

public function display()
{
$path = FR_BASE_PATH.'/modules/'.$this->module->moduleName.'/tpl';;
$tplFile = $this->module->tplFile;

$this->template->assign('modulePath',$path);
$this->template->assign('tplFile',$tplFile);
$this->template->assign('user',$this->user);
$this->template->assign('session',$this->session);

foreach ($this->module->getData() as $var => $val) {
if (!in_array($var,array('path','tplFile'))) {
$this->template->assign($var,$val);
}
}

if ($this->module->pageTemplateFile == null) {
$pageTemplateFile = 'page.tpl';
} else {
$pageTemplateFile = $this->module->pageTemplateFile;
}

$this->template->display($pageTemplateFile);
}

public function __destruct()
{
parent::__destruct();
}
}

?>
PHP Hacks

Related Reading

PHP Hacks
Tips & Tools For Creating Dynamic Websites
By Jack Herrington

Table of Contents
Index

Read Online--Safari
Search this book on Safari:


Code Fragments only



Other Presenters

You can create other presenters, as well. I've created one called debug.php that simply displays various debugging information. You could change your model class's $presenter to debug and it would render completely differently.

Additionally, you could create a presentation layer called rest.php that outputs the model class's $data variable as well-formed XML. If your model detected a REST request, it would switch the presenter by assigning rest to $this->presenter.


/**
* FR_Presenter_rest
*
* @author Joe Stump
* @copyright Joe Stump
* @license http://www.opensource.org/licenses/gpl-license.php
* @package Framework
* @filesource
*/

require_once('XML/Serializer.php');

/**
* FR_Presenter_rest
*
* Want to display your module's data in valid XML rather than HTML? This
* presenter will automatically take your data and output it in valid XML.
*
* @author Joe Stump
* @package Framework
*/
class FR_Presenter_rest extends FR_Presenter_common
{
// {{{ __construct(FR_Module $module)
/**
* __construct
*
* @author Joe Stump
* @access public
* @param mixed $module Instance of FR_Module
* @return void
*/
public function __construct(FR_Module $module)
{
parent::__construct($module);
}
// }}}
// {{{ display()
/**
* display
*
* Output our data array using the PEAR package XML_Serializer. This may
* not be the optimal output you want for your REST API, but it should
* display valid XML that can be easily consumed by anyone.
*
* @author Joe Stump
* @return void
* @link http://pear.php.net/package/XML_Serializer
*/
public function display()
{
$xml = new XML_Serializer();
$xml->serialize($this->module->getData());

header("Content-Type: text/xml");
echo ''."\n";
echo $xml->getSerializedData();
}
// }}}
// {{{ __destruct()
public function __destruct()
{
parent::__destruct();
}
// }}}
}

?>

In the REST presentation layer I use the PEAR package XML_Serializer to output the FR_Module::$data array as valid XML. It's not extremely intuitive, but it does allow me to output my module in valid XML. I use this REST presentation layer later on in one of my applications.

Conclusion

You get the idea. The presentation layer is an extremely flexible way of displaying the model. To make things even better you can dynamically switch the presenter in the model before the controller renders the module class via the presentation layer.

Before I move on, I'd like to plant the seed for another presentation layer. How about using htmldoc in a presenter named pdf to render your module class as a PDF document?

Up Next

The next article will covering the model portion of the MVC framework, to which my framework also refers as "modules" and "module classes" up to this point. My example model will be a simple module to log people in and out of the system. After that you'll be on your own to build up my little framework into something useful!

Joe Stump is currently the technology manager for eNotes.com.


Return to the PHP DevCenter.

PHP MVC (part 2 of 3) - from ONLamp.com


In the first part of this series, I covered the basics of MVC programming in PHP and created most of the base classes. In Part 2, I will be covering the controller and the presentation layer. (Part three, Implementing the View in PHP MVC is also available.)

The Controller

Quite simply, the controller handles incoming requests. It uses input, in this case from the URI, to load a module and refresh/render the presentation layer. The controller for the aptly named Framework 1.0 uses a few GET arguments to figure out which module to load.

Before I get to the code, consider a possible request that the controller is going to have to be able to handle.

http://example.com/index.php?module=login

That looks simple enough. However, seeing that the code now runs inside a framework, things are not as simple as they may seem. Here is a simple list of arguments that the controller understands and what they do.

  • module defines the basic module that the user is requesting. For instance, you may choose to create a module named users that stores your code for logging in, logging out, and registering.
  • class defines the actual class the controller will load. For instance, in your users module you might have classes named login, logout, and register. If you don't specify a class, the controller will attempt to load one with the same name as the module provided.
  • event defines which method to run after the controller has authenticated the user. By default, the controller will look for and run the __default() method of your class.

A more complex example of what the controller might handle is:

http://example.com/index.php?module=users&class=login

This tells the controller to locate the module users, load the class login, and, because there is no event defined, run login::__default().

The code


/**
* index.php
*
* @author Joe Stump
* @copyright Joe Stump
* @license http://www.opensource.org/licenses/gpl-license.php
* @package Framework
*/

require_once('config.php');

// {{{ __autoload($class)
/**
* __autoload
*
* Autoload is ran by PHP when it can't find a class it is trying to load.
* By naming our classes intelligently we should be able to load most classes
* dynamically.
*
* @author Joe Stump
* @param string $class Class name we're trying to load
* @return void
* @package Framework
*/
function __autoload($class)
{
$file = str_replace('_','/',substr($class,2)).'.php';
require_once(FR_BASE_PATH.'/includes/'.$file);
}
// }}}

if (isset($_GET['module'])) {
$module = $_GET['module'];
if (isset($_GET['event'])) {
$event = $_GET['event'];
} else {
$event = '__default';
}

if (isset($_GET['class'])) {
$class = $_GET['class'];
} else {
$class = $module;
}

$classFile = FR_BASE_PATH.'/modules/'.$module.'/'.$class.'.php';
if (file_exists($classFile)) {
require_once($classFile);
if (class_exists($class)) {
try {
$instance = new $class();
if (!FR_Module::isValid($instance)) {
die("Requested module is not a valid framework module!");
}

$instance->moduleName = $module;
if ($instance->authenticate()) {
try {
$result = $instance->$event();
if (!PEAR::isError($result)) {
$presenter = FR_Presenter::factory(
$instance->presenter,$instance
);

if (!PEAR::isError($presenter)) {
$presenter->display();
} else {
die($presenter->getMessage());
}
}
} catch (Exception $error) {
die($error->getMessage());
}
} else {
die("You do not have access to the requested page!");
}
} catch (Exception $error) {
die($error->getMessage());
}
} else {
die("An valid module for your request was not found");
}
} else {
die("Could not find: $classFile");
}
} else {
die("A valid module was not specified");
}

?>

After looking over the code, you might notice a few things. Here's a walk through the second example URI from above to thoroughly explain things.

  1. Include config.php
  2. Define the __autoload() function. Because all the classes are named in a structured manner, this function can easily include them when necessary. The __autoload() function is new to PHP 5 and provides a method to load classes dynamically. This eliminates the need to have the controller require every single library needed to function.
  3. If there is a module argument, the controller needs to start working on loading the module. The next few lines set up the defaults that I discussed earlier. Once $module, $event, and $class are defined, the controller can move on to loading the module.
  4. The next few lines have to do with loading and verifying the requested module and class. The controller loads the module's config.php and the class file, which in this example is users/login.php. Next, the controller checks to make sure the required file it needs exists and that the requested class is actually defined.
  5. Don't blink! On the next line I used the wonders of variable functions to instantiate the module. It's very important to note that the controller runs the class's constructor before it authenticates the user. Due to the class hierarchy, it would be impossible to authenticate before running the constructor. Also, note that the constructor can throw exceptions, which are new to PHP 5, and the controller will handle them appropriately.
  6. Now that the controller has a class, it runs the inherited method authenticate(), which should return a Boolean value. If the function returns true, then the controller continues running the module's event handler; if false, then the controller exits out. This would be a good place for the controller to redirect to a login form.
  7. The next few lines run the given event, which for the example is login::__default(). The event handler can either throw an exception or return a PEAR_Error, which tells the controller that something deadly has happened.
  8. Finally--yes, finally--it loads the presentation layer based on what the class has defined. By default, it uses the FR_Presenter_smarty presentation layer. You may not like Smarty, which is fine. Just create a new presentation class and use that instead. If there isn't anything wrong with the requested presentation layer, the controller finally runs the display() method, which does the heavy lifting of rendering the module. Notice how I pass the instance of the module class to the presentation layer.

For being under 100 lines of code, the controller sure does a lot! The beauty of MVC programming is that the controller is dumb to what is going on. Its sole purpose is to do simple validation on the request, load up the request, and hand off everything to the presentation layer to render the request.

Working within this structure can seem somewhat rigid at first, but once you realize how much more quickly you are able to create large applications and leverage the existing code, you can easily work around the perceived rigidity.

One of the biggest advantages of MVC programming I have found is that once my foundation is rock solid, I rarely have to worry about bugs related to the basics of my site. This allows me to focus more on the application I'm programming, rather than whether my database connection is working or the user is being properly authenticated. In my own framework, I've found that there are files and classes that I haven't touched since first coding them (three years and counting). In addition to reducing the time you spend debugging on mundane features (such as authentication), working within a framework allows you to add features that propagate downstream and fix bugs in centralized locations.

Pretty URLs

Do the URLs in my example make you cringe? They make me cringe too, which is why mod_rewrite exists. Below is an example of some rewrite rules I created to work with the framework.

RewriteEngine On

# Change the URI here to whatever you want your homepage to be
RewriteRule ^/$ /index.php?module=welcome [L,QSA]

# Changes /index.php?module=welcome to /welcome
RewriteCond %{DOCUMENT_ROOT}/%{REQUEST_FILENAME} !-d
RewriteCond %{DOCUMENT_ROOT}/%{REQUEST_FILENAME} !-f
RewriteRule ^/([^/]*)$ /index.php?module=$1 [L,QSA]

# Changes /index.php?module=users&class=login to /users/login
RewriteCond %{DOCUMENT_ROOT}/%{REQUEST_FILENAME} !-d
RewriteCond %{DOCUMENT_ROOT}/%{REQUEST_FILENAME} !-f
RewriteRule ^/([^/]*)/([^/]*)$ /index.php?module=$1&class=$2 [L,QSA]

# Changes /index.php?module=users&class=login&event=foo
# to /users/login/foo.html
RewriteCond %{DOCUMENT_ROOT}/%{REQUEST_FILENAME} !-d
RewriteCond %{DOCUMENT_ROOT}/%{REQUEST_FILENAME} !-f
RewriteRule ^/([^/]*)/([^/]*)/([^/]*).html$ /index.php?module=$1&class=$2&event=$3 [L,QSA]

Now those are some pretty URLs! One item to note is that you don't need to worry about GET arguments with mod_rewrite. It ignores GET arguments and passes them on to the real script.

Extending the Controller

The nice thing about having a controller is that you can easily make changes in a single place to add features that will then be instantly available to all of your applications. You could easily add several features to the controller to enhance your applications.

  • You could automatically detect whether the request is a SOAP request by looking at raw post data. Once you had determined the incoming request was a SOAP request, you could use PHP's new SoapServer to turn your module class into a SOAP server.
  • You could also use your controller to sanitize GET and POST input. This would include escaping variables, possibly removing malicious HTML code, and so on. The only drawback could be that you sanitize data that isn't truly harmful (such as data from an admin form).
  • The controller could instantly recognize various presentation layers and switch the module class's presentation layer. This means that the presentation layer would look at the request, notice ?view=pdf, and switch your module class's presentation layer to the PDF presenter instead of the default presenter.
  • You could add caching directly into your controller. That way you could use the URI to create cache files. Obviously, you'd need some additional checking to make sure caching was done intelligently, but this is another great example of how MVC programming makes life easier. If your site is bogged down and you don't have money for new hardware, you could--globally in the controller--turn on caching with little effort.

Whatever you decide to do with your controller, make sure that the changes are ambiguous enough to be useful for all applications, regardless of what they might be used for. For instance, stripping all HTML from POST input might not be such a good idea, as many administrative forms might need to add/edit/update data in the database that contains HTML.

Up Next

In the next part of this series, I will cover the presentation layer (the view). By using the factory method, I can easily switch the presentation of my applications to the users.

Return to the PHP DevCenter.

PHP MVC basics (part 1 of 3) - from ONLamp.com

Understanding MVC in PHP

by Joe Stump
09/15/2005

This article series (continued in Implementing MVC in PHP: The Controller and Implementing MVC in PHP: The View) demonstrates how to build an MVC web framework using PHP 5. This article covers the basics of MVC web frameworks, building the foundation classes for a framework that the other three articles in this series will build.

With the introduction of PHP 5 and its new OOP features developers can now seriously talk about building solid APIs and more complex MVC frameworks for the web in PHP. This was possible before, but the new features in PHP 5 make it easier to integrate more advanced features into MVC frameworks, such as SOAP and WSDL.

In this article I assume that you have a solid understanding of object-oriented programming and that you have at least scanned the upcoming changes to the OOP structure of PHP in PHP5.

What is MVC?

MVC is the idea that you have three different pieces that work in unison to form a complex application. A car is a good real-world example of MVC. With a car you have two views: the interior and the exterior. Both take input from the controller: the driver. The brakes, steering wheel and other controls represent the model: they take input from the controller (driver) and hand them off to the views (interior/exterior) for presentation.

Related Reading

PHP in a Nutshell

PHP in a Nutshell
By Paul Hudson

Table of Contents
Index
Sample Chapter

Read Online--Safari Search this book on Safari:


Code Fragments only

MVC on the Web

The ideas behind MVC frameworks are quite simple and extremely flexible. The idea is that you have a single controller (such as index.php) that controls the launch of applications within the framework based on arguments in the request. This usually includes, at a minimum, an argument defining which model to invoke, an event, and the usual GET arguments. From there the controller validates the request (authentication, valid model, request sanitization, etc.) and runs the requested event.

For instance, a request for /index.php?module=foo&event=bar might load a class called foo and run foo::bar(). The advantages of this method include:

  • A single entry point for all applications.
  • Removing the headaches involved with maintaining numerous scripts, each with their own relative paths, database connections, authentication, etc.
  • Allowing the consolidation and reuse of code.

Why Create My Own MVC Framework?

This article doesn't really advocate "You should write your own MVC web framework!" as is tries to explain "This is how MVC web frameworks work in theory, and why they are so great."

As of this writing, there are very few true MVC frameworks written in PHP. In fact, there is only one that I know of, Solar, that is entirely pure PHP 5 code. Another one out there is Cake, which is trying to be the "Ruby on Rails of PHP." I, personally, have a few problems with both of these frameworks. Both Solar and Cake fail to leverage existing code in PEAR, Smarty, etc. Cake appears a bit disorganized at the moment. Finally, Solar is the work of mostly a single person (not that Paul isn't a great coder or person, but there is only a single gatekeeper at the time of this writing). These may not be issues that concern you, and if they don't concern you, by all means check these two out.

The Old Way

If I could go back in time and look at code I wrote in early 2001, I would find a file called template.txt that looked something like:


require_once('config.php'); // Other requires, DB info, etc.

$APP_DB = 'mydb';
$APP_REQUIRE_LOGIN = false; // Set to true if script requires login
$APP_TEMPLATE_FILE = 'foo.php'; // Smarty template
$APP_TITLE = 'My Application';

if ($APP_REQUIRE_LOGIN == true) {
if (!isset($_SESSION['userID'])) {
header("Location: /path/to/login.php");
exit();
}
}

$db = DB::connect('mysql://'.$DB_USER.':'.$DB_PASS.'@localhost/'.$APP_DB);
if (!PEAR::isError($db)) {
$db->setFetchMode(DB_FETCHMODE_ASSOC);
} else {
die($db->getMessage());
}

// Put your logic here

// Output the template
include_once(APP_TEMPLATE_PATH.'/header.php');
include_once(APP_TEMPLATE_PATH.'/'.$APP_TEMPLATE_FILE);
include_once(APP_TEMPLATE_PATH.'/footer.php');

?>

Oh man, just looking at this code makes me cringe now. The idea with this approach was that every application fit into this set approach and I could just copy template.txt to myapp.php, change some of the variables, and then voila, it would work. However, this top-down approach has some serious flaws.

  1. What if my boss wanted me to change myapp.php to output a PDF in some cases, HTML in others, and SOAP if the request posted XML directly?
  2. What if this app required IMAP or LDAP authentication?
  3. How would I go about handling various modes in the script (including edit, update, and delete)?
  4. How would I handle multi-level authentication (admin versus non-admin)?
  5. How would I turn on output caching?



The New Way

By bringing everything into an MVC framework, I could make my life a lot easier. Compare the following code:


class myapp extends FR_Auth_User
{
public function __construct()
{
parent::__construct();
}

public function __default()
{
// Do something here
}

public function delete()
{

}

public function __destruct()
{
parent::__destruct();
}
}

?>

Notice that this code has no apparent concern with connecting to a database, verifying the user is logged in, or outputting anything. The controller handles all of this.

If I wanted to authenticate against LDAP, I could create FR_Auth_LDAP. The controller could recognize certain output methods (such as $_GET['output']) and switch to the PDF or SOAP presenter on the fly. The event handler, delete, handles only deleting and nothing else. Because the module has an instance of the FR_User class, it's easy to check which groups that user is in, etc. Smarty, the template engine, handles caching, of course, but the controller could also handle some caching.

Switching from the old way to the MVC way of doing things can be a completely foreign concept to some people, but once you have switched, it's hard to go back. I know I won't be leaving the comforts of my MVC framework anytime soon.

Creating the Foundation

I'm a huge fan of PEAR and the PEAR_Error class. PHP 5 introduced a new class, Exception, which is almost a drop-in replacement for PEAR_Error. However, PEAR_Error has a few extra features that make it a more robust solution than Exception. As a result, the framework and foundation classes will use the PEAR_Error class for error handling. I will use Exception, however, to throw errors from the constructors, as they cannot return errors.

The design goals of the foundation classes are:

  • Leverage PEAR to quickly add features to the foundation classes.
  • Create small, reusable abstract foundation classes that will enable developers to build applications quickly within the framework.
  • Document all foundation classes using phpDocumentor tags.
  • Prepend all classes and global variables with FR to avoid possible variable/class/function collisions.

The class hierarchy will look something like this:

  • FR_Object will provide the basic features that all objects need (including logging, generic setFrom(), toArray()).
    • FR_Object_DB is a thin layer to provide child classes a database connection, along with other functions such classes might need.
      • FR_Object_Web is a thin layer that provides session and user information for web-based applications.
        • FR_Module is the base class for all applications (AKA "modules," "model," etc.) built in the framework.
          • FR_Auth is the base authentication class, which will allow for multiple authentication mechanisms.
            • FR_Auth_User is an authentication class to use in modules that require a valid, logged-in user.
            • FR_Auth_No is a dummy authentication class used for modules that require no authentication.
    • FR_Presenter is the base presentation class (the view) that will handle loading and displaying the applications after they have run.
      • FR_Presenter_smarty: the presentation layer will include the ability to load different drivers. Smarty is a great template class that has built in caching and an active community.
      • FR_Presenter_debug is a debugging presentation layer that developers can use to debug applications.
      • FR_Presenter_rest is a REST presentation layer that developers can use to output applications in XML.

Looking at the foundation classes, you can start to see the separate parts of the MVC framework. FR_Module provides for the basic needs of all of the modules (Model), FR_Presenter provides a way to display applications arbitrarily in different formats (Views). In the next part of this series I will create the controller, which will bring all of our foundation classes together in a single place.



Coding Standards

Before you start coding a cohesive framework, you might want to sit down with your team (or yourself) and talk about coding standards. The whole idea of MVC programming revolves around reusable and standardized code. I recommend talking about, at least:

  • What are your coding standards regarding variable naming and indentation? Don't start a holy war, but hammer out the basics and stick to them, especially when it comes to your foundation classes.
  • Decide on a standard prefix for your functions, classes, and global variables. Unfortunately, PHP does not support namespaces. As a result, it might be a good idea to prepend your variables to avoid name collisions and confusion. Throughout this article, I've prepended my global variables, functions and classes with FR_, so as to distinguish core foundation code from simple application code.
  • I highly recommend using phpDocumentor to document your code as you actually code it. I will document all of the core foundation classes as well as my initial applications in this article. At my own place of employment, I run phpDocumentor via a cron job to compile documentation frequently from my code repository.

Coding the Foundation

With all of that theory out of the way, here are the foundation classes. Be sure to read the comments for my reasonings, ideas, and implementation details. I'm presenting a combination of things I've done in the past that work for me, and the results of a few years of trial and error. By no means is this the only way to program an MVC framework, but I think it provides a good overview of how things should work.

Filesystem Layout

The basic layout is simple and somewhat strictly defined. There is a directory for includes, which will follow a specific pattern to make it easy to use PHP's new __autoload() function. Another directory is for modules, which will have their own layout. The hierarchy looks like:

  • /
    • config.php
    • index.php
    • includes/
      • Auth.php
      • Auth/
        • No.php
        • User.php
      • Module.php
      • Object.php
      • Object/
        • DB.php
      • Presenter.php
      • Presenter/
        • common.php
        • debug.php
        • smarty.php
      • Smarty/
    • modules/
      • example/
        • config.php
        • example.php
        • tpl/
          • example.tpl
    • tpl/
      • default/
      • cache/
      • config/
      • templates/
        • templates_c/

You're probably thinking that's a lot of code! It is, but you'll get through it. At the end of this article and the series, you'll see that MVC programming will make your life a lot easier and speed up development time.

In the filesystem structure, all of the foundation classes live inside of includes/. The example laid out a sample module, as well. Each module has its own configuration file, at least one module file, and one template file. All modules reside in modules/. I've become accustomed to wrapping my modules in an outer-page template, which is what the tpl/ directory is for. Each "theme" or template group has its own template directory. For now, I'm going to use default/ as my outer-page template. Later I'll show how to create a presentation layer for modules that want to render themselves.



config.php

config.php provides a centralized location for global configuration variables, such as the DSN and log file location. Also, notice that I dynamically figure out the installation location on the file system. This will make installing and migrating your code simple if you use FR_BASE_PATH in your own code.

index.php

This is the controller. I will cover this in depth in the next article.

Object.php

This is the base class for all of the foundation classes. It provides some basic features that most, if not all, classes will need. Additionally, the child class FR_Object_DB extends this object and provides a database connection.

The idea is that, by having all children extend from a central object, all of the foundation classes will share certain characteristics. You could put the database connection directly into FR_Object, but not all classes need a database connection. I will talk about FR_Object_DB later.



require_once('Log.php');

/**
* FR_Object
*
* The base object class for most of the classes that we use in our framework.
* Provides basic logging and set/get functionality.
*
* @author Joe Stump
* @package Framework
*/
abstract class FR_Object
{
/**
* $log
*
* @var mixed $log Instance of PEAR Log
*/
protected $log;

/**
* $me
*
* @var mixed $me Instance of ReflectionClass
*/
protected $me;

/**
* __construct
*
* @author Joe Stump
* @access public
*/
public function __construct()
{
$this->log = Log::factory('file',FR_LOG_FILE);
$this->me = new ReflectionClass($this);
}

/**
* setFrom
*
* @author Joe Stump
* @access public
* @param mixed $data Array of variables to assign to instance
* @return void
*/
public function setFrom($data)
{
if (is_array($data) && count($data)) {
$valid = get_class_vars(get_class($this));
foreach ($valid as $var => $val) {
if (isset($data[$var])) {
$this->$var = $data[$var];
}
}
}
}

/**
* toArray
*
* @author Joe Stump
* @access public
* @return mixed Array of member variables keyed by variable name
*/
public function toArray()
{
$defaults = $this->me->getDefaultProperties();
$return = array();
foreach ($defaults as $var => $val) {
if ($this->$var instanceof FR_Object) {
$return[$var] = $this->$var->toArray();
} else {
$return[$var] = $this->$var;
}
}

return $return;
}

/**
* __destruct
*
* @author Joe Stump
* @access public
* @return void
*/
public function __destruct()
{
if ($this->log instanceof Log) {
$this->log->close();
}
}
}

?>



Auth.php

This is the base class for authentication. It extends from the FR_Module class from Module.php. Its major function is to define how a basic authentication class should behave.

An alternate approach is to define this as a variable in the module and then have the controller create the authentication module through a factory pattern. However, this way works too (and is simpler to explain).

Child classes should override the authenticate() method. The controller will use this method when determining if a user has access to the given module. For instance, the FR_Auth_No class simply returns true, which allows you to create modules that require no authentication.



abstract class FR_Auth extends FR_Module
{
// {{{ __construct()
function __construct()
{
parent::__construct();
}
// }}}
// {{{ authenticate()
abstract function authenticate();
// }}}
// {{{ __destruct()
function __destruct()
{
parent::__destruct();
}
// }}}
}

?>

Module.php

This is the heart of all of the modules. It extends the FR_Object_DB class and provides all of its children with database access and an open log file.

Additionally, it defines the default presentation layer, the default template file for the module, default page template file, and a few other variables that the controller and presentation layer use.

The class also provides the basic structure of what each module must possess as far as functions. The function set() abstracts the method of setting data into a centralized place, which the getData() function then hands off to the presentation layer for rendering.



abstract class FR_Module extends FR_Object_Web
{
// {{{ properties
/**
* $presenter
*
* Used in FR_Presenter::factory() to determine which presentation (view)
* class should be used for the module.
*
* @author Joe Stump
* @var string $presenter
* @see FR_Presenter, FR_Presenter_common, FR_Presenter_smarty
*/
public $presenter = 'smarty';

/**
* $data
*
* Data set by the module that will eventually be passed to the view.
*
* @author Joe Stump
* @var mixed $data Module data
* @see FR_Module::set(), FR_Module::getData()
*/
protected $data = array();

/**
* $name
*
* @author Joe Stump
* @var string $name Name of module class
*/
public $name;

/**
* $tplFile
*
* @author Joe Stump
* @var string $tplFile Name of template file
* @see FR_Presenter_smarty
*/
public $tplFile;

/**
* $moduleName
*
* @author Joe Stump
* @var string $moduleName Name of requested module
* @see FR_Presenter_smarty
*/
public $moduleName = null;

/**
* $pageTemplateFile
*
* @author Joe Stump
* @var string $pageTemplateFile Name of outer page template
*/
public $pageTemplateFile = null;
// }}}
// {{{ __construct()
/**
* __construct
*
* @author Joe Stump
*/
public function __construct()
{
parent::__construct();
$this->name = $this->me->getName();
$this->tplFile = $this->name.'.tpl';
}
// }}}
// {{{ __default()
/**
* __default
*
* This function is ran by the controller if an event is not specified
* in the user's request.
*
* @author Joe Stump
*/
abstract public function __default();
// }}}
// {{{ set($var,$val)
/**
* set
*
* Set data for your module. This will eventually be passed toe the
* presenter class via FR_Module::getData().
*
* @author Joe Stump
* @param string $var Name of variable
* @param mixed $val Value of variable
* @return void
* @see FR_Module::getData()
*/
protected function set($var,$val) {
$this->data[$var] = $val;
}
// }}}
// {{{ getData()
/**
* getData
*
* Returns module's data.
*
* @author Joe Stump
* @return mixed
* @see FR_Presenter_common
*/
public function getData()
{
return $this->data;
}
// }}}
// {{{ isValid($module)
/**
* isValid
*
* Determines if $module is a valid framework module. This is used by
* the controller to determine if the module fits into our framework's
* mold. If it extends from both FR_Module and FR_Auth then it should be
* good to run.
*
* @author Joe Stump
* @static
* @param mixed $module
* @return bool
*/
public static function isValid($module)
{
return (is_object($module) &&
$module instanceof FR_Module &&
$module instanceof FR_Auth);
}
// }}}
// {{{ __destruct()
public function __destruct()
{
parent::__destruct();
}
// }}}
}

?>



Presenter.php

This is the foundation for the presentation layer. It uses the factory design pattern to create the presentation layer. FR_Module::$presenter defines which presentation layer to use, which the controller will then create via the factory method. Once the controller has a valid presentation layer, the only thing left to do is to run the common display() function, which presentation classes inherit from FR_Presenter_common.



class FR_Presenter
{
// {{{ factory($type,FR_Module $module)
/**
* factory
*
* @author Joe Stump
* @access public
* @param string $type Presentation type (our view)
* @param mixed $module Our module, which the presenter will display
* @return mixed PEAR_Error on failure or a valid presenter
* @static
*/
static public function factory($type,FR_Module $module)
{
$file = FR_BASE_PATH.'/includes/Presenter/'.$type.'.php';
if (include($file)) {
$class = 'FR_Presenter_'.$type;
if (class_exists($class)) {
$presenter = new $class($module);
if ($presenter instanceof FR_Presenter_common) {
return $presenter;
}

return PEAR::raiseError('Invalid presentation class: '.$type);
}

return PEAR::raiseError('Presentation class not found: '.$type);
}

return PEAR::raiseError('Presenter file not found: '.$type);
}
// }}}
}

?>

Up Next

So far I have covered why using MVC frameworks make sense and coded the foundation classes. The next article will cover the controller. The third part will cover the view, or presentation layer. The final part of this series will show the creation of the first application built using the framework, the Model.

Example code for this article: framework-0.2.tar.gz

Joe Stump is currently the technology manager for eNotes.com.


Return to the PHP DevCenter.

sql datetime selection

select Convert(varchar(20), mydatefield, 101) from mytable

gives a list like
01/24/2007
01/26/2007
01/27/2007

takes a datetime field, pulls out the date and then you can use it as you wish. This would come in handy when you use a "between date1 and date2". The "date2" might account for the time 00:01 on that date, so if you have something saved for 10:05 on that date, it would not correctly appear when you execute the between statement. So we use the convert (see above) to chop the time off, so we're doing pure date comparisons and tests.

funny tv advertisements

http://www.bestadsontv.com/

SQL server datetime datatype - seperating date and time

copied from: http://weblogs.sqlteam.com/jeffs/archive/2004/12/02/2954.aspx
I've reprinted the article only so that I could do a search on my blog and find it. I am not printing this to take credit for it. It was written by the author at the url specified above.
---------------------------------------------------------

I don't like storing dates along with the time portion in my database tables.

Sure, I use the datatype, but I wish SQL provided a “Date” datatype and a “Time” datatype that were separate. It really sometimes requires too much work in T-SQL to separate the date portion from the time portion, and often in a WHERE clase you don't care about the time, you just want data for a single day. A common question asked at SQLTeam is:

Why doesn't the condition WHERE DateTimeColumn = '1/1/2004' return any results? I can see there is definitely data in that table for Jan 1st, 2004 !

The answer, of course, is because “DateTimeColumn” contains a time portion as well. Some solutions that are given often look like this:

A) WHERE DateDiff(dd, DateTimeColumn, '1/1/2004') = 0

B) WHERE Convert(varchar(20), DateTimeColumn, 101) = '01/01/2004'

C) WHERE DateTimeColumn LIKE '1/1/2004%'

D) WHERE Year(DateTimeColumn) = 2004 AND Month(DateTimeColumn) = 1 and Day(DateTimeColumn)=1

I don't really like any of those, to be honest. Many rely on system settings for date formats. Others rely on conversions to varchars. None are able to make use of any indexes on the DateTimeColumn so they will not be as efficient as possible.

The best solution in terms of performance isn't even really that good, because it requires a range even though we wish to return data just for a particular day:

E) WHERE DateTimeColumn >= '1/1/2004' AND DateTimeColumn < '1/2/2004'

If you encounter this situation often, here's an idea:

Don't store the time with the date in your database! Keep them in separate columns. You can always combine them extremely easily just by adding them together to recreate your original DateTime value. But for all those other times when you wish to just filter for a particular day, you can use a quick and efficient = or BETWEEN comparison on the date only.

To do this, you need to :

1) Create two columns instead of one -- a Date column and a Time column

2) Enforce that the Date column never has a time stored in it:

DateCol datetime check (dateAdd(dd,datediff(dd,0,DateCol),0) = DateCol)

3) Enforce that the Time column never has a date portion that is a date other than the “base date” (which is the datetime that the numeric value 0 converts to):

TimeCol datetime check (datediff(dd,0,TimeCol) = 0))

Once that is done, any time you wish to return the Date along with the Time, you can just add them together! That's right, just SELECT DateCol + TimeCol as DateTimeVal FROM YourTable.

The key here is now you can index your DateCol and filter off of it directly, without worrying about conversions or time issues, which results in efficient execution plans. With the constraints, you are guaranteed that only dates are stored there, so you never have to worry about it. And, you can effortlessly retrieve the original DateTime value with a simple addition of the two columns (no conversions needed!).

If you like, you can create a View of your table and have that view return your DateTime column as well as the Date and the Time broken out if you like. You can even allow for this View to be updateable so that client applications don't have to worry about manually breaking out the Date and the Time themselves. See the code below for an example of this trigger, along with the constraints and some sample data.


-- Here's our sample table; just an ID column with a Date and a Time.

-- Note the CHECK constraints on the datetime columns:

create table Test_table

(ID int primary key,

TransDate datetime

check (dateAdd(dd,datediff(dd,0,TransDate),0) = TransDate),

TransTime datetime

check (datediff(dd,0,TransTime) = 0)

)

go

-- Here's our view of the table which presents a DateTime column

-- that looks “normal“, along with the date and the time broken out

create view Test_View as

select ID,

TransDate,

TransTime,

TransDate + TransTime as TransDateTime

from

Test_Table

go

-- Here's our trigger for when rows are added to the view;

-- you can do a similiar thing for an UPDATE trigger as well.

create trigger test_view_ins on Test_View

instead of insert

as

begin

insert into

Test_table (ID, TransDate, TransTime)

select

ID, JustDate, TransDateTime - JustDate

from

(

select ID, dateAdd(dd,datediff(dd,0,TransDateTime),0) as JustDate,

TransDateTime

from

inserted

) a

end

go

-- Insert some sample data using the View; the trigger

-- will break out the date from the time:

insert into Test_View (ID, TransDateTime)

select 1, getdate() union

select 2, '12/19/1972 10:00 AM' union

select 3, getDate() - 1.1 union

select 4, getdate() + 2.2

-- Let's see what we've got:

select * from Test_View

select * from test_Table

-- Clean it up:

go

drop trigger test_view_ins

drop view Test_View

drop table Test_Table


A couple of notes:

1) This does, of course, require more memory since you now require twice as much storage for your datetime values. You might wish to consider using the smalldatetime datatype to avoid this problem, if you can.

2) If, on occasion, you do wish to SELECT from this table and filter by a specific date and time range, then the view will not be especially efficient if you simply use:

WHERE DateTimeCol BETWEEN @StartDateTime AND @EndDateTime

This is because now DateTimeCol is now a formula. You can either make use of Indexed Views to index this column, or you can use what I call an efficiently redundant WHERE clause like this:

WHERE DateCol BETWEEN (@StartDateTime-1) AND (@EndDateTime+1) AND
DateTimeCol BETWEEN @StartDateTime AND @EndDateTime


That will allow SQL Server to use the index on the DateCol for the initial filter, and then from there, the second part of the WHERE clause will have many fewer rows to scan.

mac osx tips and tricks

mac security tips

list of web2.0 sites

a nice list of web 2.0 sites
http://web2.wsj2.com/the_most_promising_web_20_software_of_2006.htm

and some tech sites that keep an eye on web2.0 ideas
http://techcrunch.com/
http://www.emilychang.com/go/ehub/

online IM acronyms

a list of some online IM acronyms
http://www.netlingo.com/emailsh.cfm

web site analysis tools

http://www.conversionrater.com/index.php/2006/02/15/a-complete-guide-to-web-analytics-solutions/
-a list of various web analysis tools and program. decent overview of the popular programs. good for search engine optimization analysis to see where your visitors are going and how they visit your site

Thursday, February 16, 2006

Rainforest Alliance

http://www.rainforest-alliance.org/index.cfm
The mission of the Rainforest Alliance is to protect ecosystems and the people and wildlife that depend on them by transforming land-use practices, business practices and consumer behavior.

(also for keyword search: rain forest )