Archive for the ‘PHP’ Category

Design Patterns Reference: Proxy

Monday, November 29th, 2010

The Proxy Design Pattern buils an object that is positioned transparently within two other objects in order to intercept or proxy the communication or access.

 

class CD
{
protected $_title = ”;
protected $_band = ”;
protected $_handle = null;

 

public function __construct($title, $band)
{
$this->_title = $title;
$this->_band = $band;
}

 

public function buy()
{
$this->_connect();

 

$query = “update CDs set bought=1 where band='”;
$query .= mysql_real_escape_string($this->_band, $this->_handle);
$query .= “‘ and title='”;
$query .= mysql_real_escape_string($this->_title, $this->_handle);
$query .= “‘”;

 

mysql_query($query, $this->_handle);
}

 

protected function __connect()
{
$this->_handle = mysql_connect(‘localhost’, ‘user’, ‘pass’);
mysql_select_db(‘CD’, $this->_handle);
}
}

 

// CD class simply takes a band and title, updates the DB, and completes the sale
$externalTitle = “Waste of a Rib”;
$externalBand = ‘Never Again’;

 

$cd = new CD($externalTitle, $externalBand);
$cd->buy();

 

// A new store in another city will leverage this now via Proxy
// simply by overwriting the protected connect method of the CD class

class DallasNOCCDProxy extends CD
{
protected function __connect()
{
$this->_handle = mysql_connect(‘dallas’, ‘user’,’pass’);
mysql_select_db(‘CD’);
}
}

 

$externalTitle = “Waste of a Rib”;
$externalBand = ‘Never Again’;

 

$cd = new DallasNOCCDProxy($externalTitle, $externalBand);
$cd->buy();

 

source: http://www.wiley.com/WileyCDA/WileyTitle/productCd-0470496703,descCd-DOWNLOAD.html

 

 

PHP Ternary Conditionals quick reference

Monday, November 29th, 2010

with variable:

 

$greeting = (date(“G”) < 12) ? ‘Good morning’ : ‘Good afternoon’;
echo $greeting;

 

without:

 

echo (date(“G”) < 12) ? ‘Good morning’ : ‘Good afternoon’;

 

another great example
courtesy of:

http://www.addedbytes.com/php/ternary-conditionals/
alternate color with ternary and modulus:

 

$i = 1;
echo ‘<table>’;
while ($data = mysql_fetch_array($result))
{
echo ‘ <tr>’;
echo ‘ <td bgcolor=”‘;
echo (($i % 2) == 0) ? ‘#eee’ : ‘#ddd’ ;
echo ‘”>’;
echo $data[‘field’];
echo ‘ </td>’;
echo ‘ </tr>’;
$i++;
}
echo ‘</table>’;

 

/* another basic usage */
courtesty of:
http://davidwalsh.name/php-shorthand-if-else-ternary-operators

 

$message = ‘Hello ‘.($user->is_logged_in() ? $user->get(‘first_name’ )  :  ‘Guest’ ) ;

 

also see:
http://php.net/manual/en/language.operators.comparison.php
for more examples,
search the page (F3 in FF) for ternary

 

another nice example from:
http://deadlytechnology.com/web-development-tips/php-ternary-syntax/

 

instead of:

 

$bTest1 = false;
$bTest2 = false;

 

if ($bTest1) {
if ($bTest2) {
echo ‘test 1 true, test 2 true’;
}
else {
echo ‘test 1 true, test 2 false’;
}
}
else {
if ($bTest2) {
echo ‘test 1 false, test 2 true’;
}
else {
echo ‘test 1 false, test 2 false’;
}
}

 

better:

 

echo $bTest1 ? ( $bTest2? ‘test 1 true, test 2 true’ : ‘test 1 true, test 2 false’ ) : ( $bTest2 ? ‘test 1 false, test 2 true ‘ : ‘test 1 false, test 2 false ‘
) ;

Design Patterns Reference: Prototype

Sunday, November 28th, 2010

“In situations where a resource intensive object needs to be created often, the Prototype Pattern provides a welcome route to faster execution.”

 

“The Prototype Design Pattern creates objects in such a way that an initial object or prototype can be copied and cloned more efficiently than creating a new instance.”

 

class CD
{
public $band = ”;
public $title = ”;
public $trackList = array();

public function __construct($id)
{
$handle = mysql_connect(‘localhost’, ‘user’, ‘pass’);
mysql_select_db(‘CD’, $handle);

$query = “select band, title, from CDs where id={$id}”;

$results = mysql_query($query, $handle);

if ($row = mysql_fetch_assoc($results)){
$this->band = $row[‘band’];
$this->title = $row[‘title’];
}
}

 

public function buy()
{
// cd buying magic here
var_dump ($this);
}
}

 

class MixtapeCD extends CD
{
public function __close()
{
$this->title = ‘Mixtape’;
}
}

 

$externalPurchaseInfoBandID = 12;
$bandMixProto = new MixtapeCD($externalPurchaseInfoBandID);

 

$externalPurchaseInfo = array();
$externalPurchaseInfo[] = array(‘brrr’, ‘goodbye’);
$externalPurchaseInfo[] = array(‘what it means’, ‘brrr’);

 

foreach ($externalPurchaseInfo as $mixed) {
$cd = clone $bandMixProto;
$cd->trackList = $mixed;
$cd->buy();
}

 

“When working with objects whose creation is expensive and whose initial configuration stays relatively the same through new instances, using duplicate classes made with the Prototype Design Pattern is best practice.”

 

source: http://www.wiley.com/WileyCDA/WileyTitle/productCd-0470496703,descCd-DOWNLOAD.html

 

 

Using folder structure, URL, instead of parameters, setup a virtual host, apache httpd-vhosts.conf, and then grab the url via PHP

Wednesday, November 17th, 2010

This post is about creating a small application in a folder, that behaves like Zend, or you could also say that it behaves like a service, in that it uses (converts) the folder structure of the url for the application’s use, rather than passing it url parameters. Another common example of such a system is employed by WordPress when “clean urls” is turned on.

 

Instead of this: http://alexyz.com?someparameter=something

We want this: http://alexyz.com/something

 

PHP then acquires that last value (call it a “command” or an “action” or whatever you’d like) and proceeds…

 

First, setup an apache virtual host, so that everything after the folder your app will live in is redirected back to that folder’s index along with any following parameters.  You do this via httpd-vhosts.conf

 

example contents of httpd-vhosts.conf (there are several virtual host projects in this example, for independant Zend applications, the code relevant to this lesson is red):

 

# Setup Listening Port
NameVirtualHost *:80

# Ensure “localhost” is preserved
<VirtualHost *:80>
ServerName localhost
DocumentRoot “C:\xampp\htdocs”

<Location /html/bonus>
RewriteEngine On
RewriteCond %{REQUEST_FILENAME} -s [OR]
RewriteCond %{REQUEST_FILENAME} -l [OR]
RewriteCond %{REQUEST_FILENAME} -d
RewriteRule ^.*$ – [NC,L]
RewriteRule ^.*$ /html/bonus/index.php [NC,L]
</Location>

</VirtualHost>

# Setup “components” Virtual Host
<VirtualHost *:80>
ServerName components
DocumentRoot “C:\xampp\htdocs\components\public”

<Directory “C:\xampp\htdocs\components\public”>
Options Indexes FollowSymLinks Includes
AllowOverride All
Order allow,deny
Allow from all
</Directory>
RewriteEngine off

<Location />
RewriteEngine On
RewriteCond %{REQUEST_FILENAME} -s [OR]
RewriteCond %{REQUEST_FILENAME} -l [OR]
RewriteCond %{REQUEST_FILENAME} -d
RewriteRule ^.*$ – [NC,L]
RewriteRule ^.*$ index.php [NC,L]
</Location>

</VirtualHost>

# Setup “myzendresource” Virtual Host
<VirtualHost *:80>
ServerName myzendresource
DocumentRoot “C:\xampp\htdocs\myzendresource\public”
<Directory “C:\xampp\htdocs\myzendresource\public”>
Options Indexes FollowSymLinks Includes
AllowOverride All
Order allow,deny
Allow from all
</Directory>
</VirtualHost>

# Setup “datamodels” Virtual Host
<VirtualHost *:80>
ServerName datamodels
DocumentRoot “C:\xampp\htdocs\datamodels\public”
<Directory “C:\xampp\htdocs\datamodels\public”>
Options Indexes FollowSymLinks Includes
AllowOverride All
Order allow,deny
Allow from all
</Directory>
</VirtualHost>

 

So, any Url after /bonus, in this example, like: http://www.alexyz.com/bonus/something

will be pointed back to /bonus/index.php by apache for us.

 

Next, we simply grab that last part of the url in our index.php (in this example it’s the value “something”).  There are many ways we could do this, the example here is a very basic implementation of one way we might grab that value and proceed…

 

< ? php

$parameters = explode(“/”, $_SERVER[“REQUEST_URI”]);
foreach($parameters as $param){
if($param != NULL) { // This won’t fire if there is a terminating slash, we don’t want to set the parameter to empty!

$bonus_parameter = $param;

}
}

 

// now we can proceed with index.php just as though we’d done this, but we haven’t…:

 

$param = $_GET[‘parameterName’];

 

 

Design Patterns Reference: Observer

Sunday, November 14th, 2010

The Observer Design Pattern facilitates the creation of objects that watch the state of a target object and provides state targeted functionality that is uncoupled from the core object.

The most obvious example, applications that support some type of plugin system.  Another example, cache systems, or message notification (example, members are notified when an item is in stock, to add that members may also be notified when it’s out of stock, simply add another observer, or perhaps another that texts them rather than emailing them…and so on).

When adding features to software that are activated by an action or state change but are loosely coupled, objects based on the Observer Design Pattern should be created.

MyObject is the Observable object.  It contains a protected array of observers. A public method addObserver() takes an instance of an observer and stores it in the array.

A public method doSomething() applies a state change to MyObject, whose notify() public method then loops through the array of observers.

Each such MyObjectObserver has a public method change(), that accepts an instance of MyObject, which modifies said object via a notify() method of MyObject that calls MyObjectObserver’s change() method directly as it’s encountered in the array of observers.

class CD
{
public $title = ”;
public $band = ”;
protected $_observers = array();

public function __construct($title, $band)
{
$this->title = $title;
$this->band = $band;
}

public function attachObserver($type, $observer)
{
$this->_observers[$type][] = $observer;
}

public function notifyObserver($type)
{
if(isset($this->_observers[$type])){
foreach($this->_observers[$type] as $observer)
{
$observer->update($this);
}
}
}

public function buy()
{
// stub actions of buying
$this->notifyObserver(‘purchased’);
}
}

class buyCDNotifyStreamObserver
{
public function update(CD $cd)
{
$activity = “The CD named {$cd->title} by “;
$activity .= “{$cd->band} was just purchased.”;
activityStream::addNewItem($activity);
}
}

class activityStream
{
public static function addNewItem($item)
{
// stub functions
print $item;
}
}

$title = “Wast of a Rib”;
$band = ‘Never Again’;
$cd = new CD($title, $band);

$observer = new buyCDNotifyStreamOberver();
$cd->attachObserver(‘purchased’, $observer);
$cd->buy();

source: http://www.wiley.com/WileyCDA/WileyTitle/productCd-0470496703,descCd-DOWNLOAD.html

Design Patterns Reference: Mediator

Saturday, October 30th, 2010

The Mediator Design Pattern is used to develop an object that communicates or mediates changes to a collection of similar objects without them interacting with each other directly.
class CD
{
public $band = ”;
public $title = ”;
protected $_mediator;

public function __construct($mediator = null)
{
$this->_mediator = $mediator;
}

public function save()
{
// stub – writes data back to database – use this to verify
var_dump($this);
}

public function changeBandName($newName)
{
$this->band = $newName;
$this->save();
}
}

class MP3Archive
{
public $band = ”;
public $title = ”;
protected $_mediator;

public function __construct($mediator = null)
{
$this->_mediator = $mediator;
}

public function save()
{
// stub – writes data back to database – use this to verify

var_dump($this);
}

public function changeBandName($newName)
{
if (!is_null($this->_mediator)){
$this->_mediator->change($this, array(‘band’=>$newName));
}
$this->band = $newName;
$this->save();
}
}

class MusicContainerMediator
{
protected $_containers = array();

public function __construct()
{
$this->_containers[] = ‘CD’;
$this->_containers[] = ‘MP3Archive’;
}

public function change($originalObject, $newValue)
{
$title = $originalObject->title;
$band = $originalObject->band;

foreach ($this->_containers as $container){
if (!($changedObject instanceof $container)){
$object = new $container;
$object->title = $title;
$object->band = $band;

foreach ($newValue as $key=>$value){
$object->key = $val;
}

$object->save();
}
}
}
}

// To use the new Mediator object

$titleFromDB = ‘Waste of a Rib’;
$bandFromDB = ‘Never Again’;

$mediator = new MusicContainerMediator();
$cd = new CD($mediator);
$cd->title = $titleFromDB;
$cd->band = $bandFromDB;

$cd->changeBandName(‘Maybe Once More’);

source: http://www.wiley.com/WileyCDA/WileyTitle/productCd-0470496703,descCd-DOWNLOAD.html

Podpress Plugin WordPress Outside the Loop Single page

Thursday, October 21st, 2010

Am building a page that pulls in a single post from a WordPress podcast site that I built that uses Podpress. The long and short of it is that it requires instantiating the WordPress app externally, and using a mini-loop, pretty straight forward, but for the longest time I couldn’t figure out for the life of me why the Podpress player wasn’t showing up…

Instead, I was only getting the [display_podcast] token that one places in a post for Podpress and WordPress to then replace upon rendering the post…

I knew there had to be a simple solution.  My final code is below.  The key: wp_head();

< ? php

require_once(‘../podcast/wp-load.php’ ); // load the app
wp_head(); // this gets all the plugins and dependencies!!!!
query_posts(‘p=1807’); // documentation on using query_posts is nice and simple and clear
while (have_posts()) : the_post(); // iterate over the return

// use various things to output the data

the_ID(); the_time(‘l, F j, Y’); the_title(); the_content(); // and so on

endwhile;

? >

Design Patterns Reference: Interpreter

Sunday, October 17th, 2010

“The Interpreter Design Pattern analyzes an entity for key elements and provides its own interpretation or action corresponding to each key.”
class User
{
protected $_username;

public function __construct($username)
{
$this->_username = $username;
}

public function getProfilePage()
{
// In lieu of getting the data from a DB, we mock here
$profile = “<h2>I like Never Again!</h2>”;
$profile .= “I love all of their songs. My favorite CD:<br />”;
$profile .= “{{myCD.getTitle}}!!”;

return $profile;
}
}

class userCD
{
protected $_user = NULL;

public function setUser($user)
{
$this->_user = $user;
}

public function getTitle()
{
// mock here
$title = “Waste of a Rib”;

return $title;
}
}

class userCDInterpreter
{
protected $_user = NULL;

public function setUser($user)
{
$this->_user = $user;
}

public function getInterpreted()
{
$profile = $this->_user->getProfilePage();

if (preg_match_all(‘/\{\{myCD\.(.*?)\}\}/’, $profile, $triggers, PREG_SET_ORDER)){
$replacements = array();

foreach($triggers as $trigger){
$replacements[] = $trigger[1];
}
$replacements = array_unique($replacements);
$myCD = new userCD();
$myCD->setUser($this->_user);
foreach($replacements as $replacement){
$profile = str_replace(“{{myCD.{$replacement}}}”, call_user_func(array($myCD, $replacement)), $profile);
}
}
return $profile;
}
}

/**
* implementation
*/

$username = ‘aaron’;
$user = new User($username);
$interpreter = new userCDInterpreter();
$interpreter->setUser($user);
print “<h1>{$username}’s Profile</h1>”;
print $interpreter->getInterpreted();

source: http://www.wiley.com/WileyCDA/WileyTitle/productCd-0470496703,descCd-DOWNLOAD.html

Design Patterns Reference: Factory

Sunday, October 17th, 2010

“The Factory Design Pattern provides a simple interface to acquire a new instance of an object, while sheltering the calling code from the steps to determine which base class is actually instantiated.”
class standardCD
{
public $title = “”;
public $band = “”;
public $tracks = array();

public function __construct()
{
//
}

public function setTitle($title)
{
$this->title = $title;
}

public function setBand($band)
{
$this->band = $band;
}

public function addTrack($track)
{
$this->tracks[] = $track;
}
}

/**
* create a complete standardCD object
*/

$title = ‘Waste of a Rib’;
$band = ‘Never Again’;
$tracksFromExternalSource = array(‘What It Means’,’Brrr’,’Goodbye’);
$cd = new CD();
$cd->setTitle($title);
$cd->setBand($band);
foreach ($tracksFromExternalSource as $track)
{
$cd->addTrack($track);
}

/**
* another slight variation of a CD
* ‘enhanced’ is required as well
*/

class enhancedCD
{
public $title = “”;
public $band = “”;
public $tracks = array();

public function __construct()
{
//
}

public function setTitle($title)
{
$this->title = $title;
}

public function setBand($band)
{
$this->band = $band;
}

public function addTrack($track)
{
$this->tracks[] = ‘DATA TRACK’;
}
}

/**
* We could use conditional logic
* to determine which class to instantiate
* standardCD or enhancedCD
* but behold, instead, the Factory Pattern!
*/

class CDFactory
{
public static function create($type)
{
$class = strtolower($type) . “CD”;
return new $class;
}
}

/**
* Thus, to create a CD or an enhancedCD
*/

$type = ‘enhanced’; // or $type = ‘standard’;
$cd = CDFActory::create($type);
$cd->setBand($band);
$cd->setTitle($title);
foreach($tracksFromExternalSource as $track)
{
$cd->addTrack($track);
}

source: http://www.wiley.com/WileyCDA/WileyTitle/productCd-0470496703,descCd-DOWNLOAD.html

Design Patterns Reference: Facade

Wednesday, October 13th, 2010

“The Facade Design Pattern hides complexity from a calling object by creating a simple facade interface in front of the collection of required logic and methods.”

class CD
{
public $tracks = array();
public $band = ”;
public $title = ”;

public function __construct($title, $band, $tracks)
{
$this->title = $title;
$this->band = $band;
$this->tracks = $tracks;
}
}

/**
* build a CD
*/

$tracksFromExternalSource = array(‘What It Means’,’Brrr’,’Goodbye’);
$title = ‘Waste of a Rib’;
$band = ‘Never Again’;
$cd = new CD($title, $band, $tracksFromExternalSource);

class CDUpperCase
{
public static function makeString(CD $cd, $type)
{
$cd->$type = strtoupper($cd->$type);
}

public static function makeArray(CD $cd, $type)
{
$cd->$type = array_map(‘strtoupper’, $cd->$type);
}
}

class CDMakeXML
{
public static function create(CD $cd)
{
$doc = new DomDocument();

$root = $doc->createElement(‘CD’);
$root = $doc->appendChild($root);

$title = $doc->createElement(‘TITLE’, $cd->title);
$title = $root->appendChild($title);

$band = $doc->createElement(‘BAND’, $cd->band);
$band = $root->appendChild($band);

$tracks = $doc->createElement(‘TRACKS’);
$tracks = $root->appendChild($tracks);

foreach ($cd->tracks as $track){
$track = $doc->createElement(‘TRACK’, $track);
$track = $tracks->appendChild($track);
}
return $doc->saveXML();
}
}

/**
* instead of applying CDUpperCase & CDMake XML on CD object as follows:
*/

CDUpperCase::makeString($cd, ‘title’);
CDUpperCase::makeString($cd, ‘band’);
CDUpperCase::makeArray($cd, ‘tracks’);
print CDMakeXML::create($cd);

/**
* a facade object better serves the purpose!
*/

class WebServiceFacade
{
public static function makeXMLCall(CD $cd)
{
CDUpperCase::makeString($cd, ‘title’);
CDUpperCase::makeString($cd, ‘band’);
CDUpperCase::makeArray($cd, ‘tracks’);

$xml = CDMakeXML::create($cd);

return $xml;
}
}

/**
* thus implemented in ONE line instead, as follows:
*/

print WebServiceFacade::makeXMLCall($cd);

source: http://www.wiley.com/WileyCDA/WileyTitle/productCd-0470496703,descCd-DOWNLOAD.html

Design Patterns Reference: Delegate

Tuesday, October 12th, 2010

“The Delegate Design Pattern removes decisions and complex functionality from the core object by distributing or delegating them to other objects.”

This example accomplishes this by utilizing PHP’s ability to dynamically create class instances based on a variable, and thus functionality may be spread across multiple objects rather than managed by one conglomerated block of conditional logic.

/**
* version 1
* NON-Delegate implementation
* as you’ll see,
* could easily become unweildly
* to extend…
*/

class Playlist
{
private $__songs;

public function __construct()
{
$this->__songs = array();
}

public function addSong($location, $title)
{
$song = array(‘location’=>$location, ‘title’=>$title);
$this->__songs[] = $song;
}

public function getM3U()
{
$m3u = “#EXTM3U\n\n”;

foreach($this->__songs as $song){
$m3u .= “#EXTINF:-1,{$song[‘title’]}\n”;
$m3u .= “{$song[‘location’]}\n”;
}
return $m3u;
}

public function getPLS()
{
$pls = “\nNumberOfEntries=” . count($this->__songs) . “\n\n”;

foreach ($this->__songs as $songCount=>$song){
$counter = $songCount + 1;
$pls .= “File{$counter}={$song[‘location’]}\n”;
$pls .= “Title{$counter}={$song[‘title’]}\n”;
$pls .= “Length{$counter}=-1\n\n”;
}
return $pls;
}
}

/**
* Implemented as follows:
*/

$playlist = new Playlist();
$playlist->addSong(‘/home/aaron/music/brr.mp3’, ‘Brr’);
$playlist->addSong(‘/home/aaron/music/goodbye.mp3’, ‘Goodbye’);
if($externalRetrievedType == ‘pls’){
$playlistContent = $playlist->getPLS();
}
else {
$playlistContent = $playlist->getM3U();
}

/**
* version 2
* Delegate Design Pattern implementation
*/

class newPlaylist
{
private $__songs;
private $__typeObject;

public function __construct($type)
{
$this->__songs = array();
$object = “{$type}PlaylistDelegate”;
$this->__typeObject = new $object;
}

public function addSong($location, $title)
{
$song = array(‘location’=>$location, ‘title’=>$title);
$this->__songs[] = $song;
}

public function getPlaylist()
{
$playlist = $this->__typeObject->getPlaylist($this->__songs);
return $playlist;
}
}

class m3uPlaylistDelegate
{
public function getPlaylist($songs)
{
$m3u = “#EXTM3U\n\n”;

foreach ($songs as $song){
$m3u .= “EXTINF:-1,{$song[‘title’]}\n”;
$m3u .= “{$song[‘location’]}\n”;
}
return $m3u;
}
}

class plsPlaylistDelegate
{
public function getPlaylist($songs)
{
$pls = “\nNumberOfEntries=” . count($songs) . “\n\n”;

foreach($songs as $songCount=>$song){
$counter = $songCount + 1;
$pls .= “File{$counter}={$song[‘location’]}\n”;
$pls .= “Title{$counter}={$song[‘title’]}\n”;
$pls .= “Length{$counter}=-1\n\n”;
}
return $pls;
}
}

/**
* Implemented as follows:
*/

$externalRetrievedType = ‘pls’;
$playlist = new newPlaylist($externalRetrievedType);
$playlistContent = $playlist->getPlaylist();

// to see results of course, something like:

print_r($playlistContent);

source: http://www.wiley.com/WileyCDA/WileyTitle/productCd-0470496703,descCd-DOWNLOAD.html

Design Patterns Reference: Decorator

Tuesday, October 12th, 2010

“The Decorator Design Pattern is best suited for altering or decorating portions of an existing object’s content or functionality without modifying the structure of the original object.”

class CD
{
public $trackList;

public function __construct()
{
$this->trackList = array();
}

public function addTrack($track)
{
$this->trackList[] = $track;
}

public function getTrackList()
{
$output = “”;

foreach ($this->trackList as $num=>$track){
$output .= ($num + 1) . “) {$track}. “;
}
}
}

/**
* cd object use
*/

$tracksFromExternalSource = array(‘What It Means’, ‘Brr’, ‘Goodbye’);
$myCD = new CD();
foreach ($trackFromExternalSource as $track){
$myCD->addTrack($track);
}
print “The CD contains the following tracks: ” . $myCD->getTrackList;

/**
* aha, but now the requirements change on us…
* now all tracks need to display uppercase!
* Instead of modifying the original class,
* or changing the parent-child relationships for such small “living requirements”…
* we use the Decorator design pattern!
*/

class CDTrackListDecoratorCaps
{
private $__cd;

public function __construct(CD $cd)
{
$this->__cd = $cd;
}

public function makeCaps()
{
foreach ($this->__cd->trackList as &$track)
{
$track = strtoupper($track);
}
}
}

/**
* new object use
*/

$myCD = new CD();
foreach ($tracksFromExternalSource as $track){
$myCD->addTrack($track);
}
$myCDCaps = new CDTrackListDecoratorCaps($myCD);
$myCDCaps->makeCaps();

print “The CD contains the following tracks: ” . $myCD->getTrackList();

source: http://www.wiley.com/WileyCDA/WileyTitle/productCd-0470496703,descCd-DOWNLOAD.html

Design Patterns Reference: Data Access Object DAO

Tuesday, October 12th, 2010

“The Data Access Object Design Pattern describes the creation of an object that provides transparent access to any data source.”

/**
* Data Access Object Pattern Example
*/

/**
* first we define the abstract base DAO class,
* which, of course, thus MUST be extended to be used
* to note:
* – the connection is internally referenced,
* allowing multiple simultaneous connections and tables
* – the fetch and update methods are wonderfully abstract
* untied to table name, key, or value
*/
abstract class baseDAO
{
private $__connection;

public function __construct()
{
$this->__connectToDB(DB_USER, DB_PASS, DB_HOST, DB_DATABASE);
}

public function fetch($value, $key = NULL)
{
if (is_null($key)){
$key = $this->_primaryKey;
}

$sql = “select * from {$this->_tableName} where {$key}='{$value}'”;
$results = mysql_query($sql, $this->__connection);

$rows = array();
while ($result = mysql_fetch_array($results)){
$rows[] = $result;
}

return $rows;
}

public function update($keyedArray)
{
$sql = “update {$this->_tableName} set “;

$updates = array();
foreach ($keyedArray as $column=>$value){
$updates[] = “{$column}='{$value}'”;
}

$sql .= implode(‘,’, $updates);
$sql .= “where {$this->_primaryKey}='{$keyedArray[$this->_primaryKey]}'”;

mysql_query($sql, $this->__connection);
}
}

/**
* Finally, let’s extend with a child class
* mapped to a specific table
*/

class userDAO extends baseDAO
{
protected $_tableName = ‘userTable’;
protected $_primaryKey = ‘id’;

public function getUserByFirstName($name)
{
$result = $this->fetch($name, ‘firstName’);
return result;
}
}

/**
* Example of use
* DB connect data, of course, would be elsewhere and flexible
*/

define(‘DB_USER’,’user’);
define(‘DB_PASS’,’pass’);
define(‘DB_HOST’,’localhost’);
define(‘DB_DATABASE’,’test’);

/** fetch row id 1 **/
$user = new userDAO();
$userDetailsArray = $user->fetch(1);

/** update row id 1 **/
$updates = array(‘id’=>1, ‘firstName’=>’aaron’);
$user->update($updates);

/** get users with first name aaron **/
$allAarons = $user->getUserByFirstName(‘aaron’);

source: http://www.wiley.com/WileyCDA/WileyTitle/productCd-0470496703,descCd-DOWNLOAD.html

Design Patterns Reference: Builder

Tuesday, October 12th, 2010

“The Builder Design Pattern defines the design of an object that handles the complex building of another object.”

/**
* the Builder Pattern
* creates objects
* so that only its build method need be modified
* if the class it builds changes in the future
* and to automate object instantiation according to requirements
*/

/**
* class that could change with time
*/

class product
{
protected $_type = ”;
protected $_size = ”;
protected $_color = ”;

public function setType($type)
{
$this->_type = $type;
}

public function setSize($size)
{
$this->_size = $size;
}

public function setColor($color)
{
$this->_color = $color;
}
}

/**
* thus, rather than implementing each and every
* instantiation of the product class as follows:
*/

$productConfigs = array(‘type’=>’shirt’,’size’=>’XL’,’color’=>’red’);
$product = new product();
$product->setType($productConfigs[‘type’]);
$product->setSize($productConfigs[‘size’]);
$product->setColor($productConfigs[‘color’]);

/**
* and then having to change every instantiation
* if/when the product class changes!
* instead, we create a productBuilder,
* and then the change simply happens in the product class
* and in the builder build method
*/

class productBuilder
{
protected $_product = NULL;
protected $_xml = array();

public function __construct($configs)
{
$this->_product = new product();
$this->_xml = $configs;
}

public function build()
{
$this->_product->setSize($configs[‘size’]);
$this->_product->setType($configs[‘type’]);
$this->_product->setColor($configs[‘color’]);
}

public function getProduct()
{
return $this->_product;
}
}

/**
* implemented, instead as follows:
*/

$builder = new productBuilder($productConfigs);
$builder->build();
$product = $builder->getProduct();

source: http://www.wiley.com/WileyCDA/WileyTitle/productCd-0470496703,descCd-DOWNLOAD.html

Design Patterns Reference: Adapter

Tuesday, October 12th, 2010

“The Adapter Design Pattern simply adapts one object’s interfaces to what another object expects.”

/**
* Example Adapter Class
*/

/**
* original object
*/

class errorObject
{
private $__error;

public function __construct($error)
{
$this->__error  = $error;
}

public function getError()
{
return $this->__error;
}
}

/**
* original Log class
*/

class logToConsole
{
private $__errorObject;

public function __construct($errorObject)
{
$this->__errorObject = $errorObject;
}

public function write()
{
fwrite(STDERR, $this->__errorObject->getError());
}
}

/**
* Initial way to utilize this system
* create the new 404 error object
*/

$error = new errorObject(“404:Not Found”);

/** then write the error to the console **/

$log = new logToConsole($error);
$log->write();

/**
* extend the logging functionality
* to log to CSV file instead
* with the log # and text
*/

class logToCSV
{
const CSV_LOCATION = ‘log.csv’;

private $__errorObject;

public function __construct($errorObject)
{
$this->__errorObject = $errorObject;
}

public function write()
{
$line = $this->__errorObject->getErrorNumber();
$line .= ‘,’;
$line .= $this->__errorObject->getErrorText();
$line .= “\n”;

file_put_contents(self::CSV_LOCATION, $line, FILE_APPEND);
}
}

/**
* to use the new log
* original errorObject must either be changed
* or better, extended
*/

class logToCSVAdapter extends errorObject
{
private $__errorNumber, $__errorText;

public function __construct($error)
{
parent::__construct($error);

$parts = explode(‘:’, $this->getError());

$this->__errorNumber = $parts[0];
$this->__errorText = $parts[1];
}

public function getErrorNumber()
{
return $this->__errorNumber;
}

public function getErrorText()
{
return $this->__errorText;
}
}

/**
* new way to implement the system extended
* create the new 404 error object adapted for csv
*/

$error = new logToCSVAdapter(“404:Not Found”);

/** then write the error to the csv file **/
$log = new logToCSV($error);
$log->write();

source: http://www.wiley.com/WileyCDA/WileyTitle/productCd-0470496703,descCd-DOWNLOAD.html

Design Patterns Reference: Iterator

Tuesday, October 12th, 2010

“The Iterator Design Pattern helps construct objects that can provide a single standard interface to loop or iterate through any type of countable data.”

class  implements Iterator
{
/**
* Get the current element
* @return mixed
*/

public function current()
{
}

/**
* Gets the current key
* @return mixed
*/

public function key()
{
}

/**
* Checks if current element exists
* @return boolean
*/

public function valid()
{
}

/**
* Moves pointer forward to next element
*/

public function next()
{
}

/**
* Moves pointer to first element
*/

public function rewind()
{
}
}

/**

* Example Implementation

*/
class  CD
{
public $band = “”;
public $title = “”;
public $trackList = array();

public function __construct($band, $title)
{
$this->band = $band;
$this->title = $title;
}

public function addTrack($track)
{
$this->trackList[] = $track;
}
}

/**
* SPL Iterator, thus requires:
* current(), key(), rewind(), next(), valid()
* public methods
*/

class CDSearchByBandIterator implements Iterator
{
private $__CDs = array();
private $__valid = FALSE;

public function __construct($bandName)
{
$db = mysql_connect(‘localhost’,’user’,’pass’);
mysql_select_db(‘test’);
$sql = “select CD.id, CD.band, CD.title, tracks.tracknum, “;
$sql .= “tracks.title as tracktitle “;
$sql .= “from CD left join tracks on CD.id = tracks.cid where band='”;
$sql .= mysql_real_escape_string($bandname);
$sql .= “‘ order by tracks.tracknum”;
$results = mysql_query($sql);

$cdID = 0;
$cd = NULL;

while($result = mysql_fetch_array($results)){
if($result[‘id’] !== $cdID){
if (!is_null($cd)){
$this->__CDs[] = $cd;
}
$cdID = $result[‘id’];
$cd = new CD($result[‘band’], $result[‘title’]);
}
$cd->addTrack($result[‘tracktitle’]);
}
$this->__CDs[] = $cd;
}

public function next()
{
$this->__valid = (next($this->__CDs) === FALSE) ? FALSE : TRUE;
}

public function rewind()
{
$this->__valid = (reset($this->__CDs) === FALSE) ? FALSE : TRUE;
}

public function valid()
{
return $this->__valid;
}

public function current()
{
return current($this->__CDs);
}

public function key()
{
return key($this->__CDs);
}
}
/**
* Implementation
*/

$queryItem = ‘Never Again’; // band Name
$cds = new CDSearchByBandIterator($queryItem);
print ‘<h1>Found the Following CDs</h1>’;
print ‘<table><tr><th>Band</th><th>Title</th><th>Num Tracks</th></tr>’;
foreach ($cds as $cd){
print “<tr><td>{$cd->band}</td><td>{$cd->title}</td><td>”;
print count($cd->trackList) . ‘</td></tr>’;
}
print ‘</table>’;

source: http://www.wiley.com/WileyCDA/WileyTitle/productCd-0470496703,descCd-DOWNLOAD.html

Zend Notes: Grabbing a resource from the registry via a view helper

Wednesday, September 29th, 2010

Helper (application/views/helpers):

class Zend_View_Helper_ImageUrlHelper extends Zend_View_Helper_Abstract {
/**
* Helper to grab the path to the images directory
* @param String $imageName
* @param String $imageSize, var for possibly different size requests
*/

public function ImageUrlHelper($imageName, $imageSize) {
$config = Zend_Registry::get(‘config’);
$path = $config-> urlpaths-> productImages;
return $path . ‘/products_’ . $imageSize . ‘/’ . $imageName;
}
}

application.ini (application/configs):

urlpaths.productImages = “/path/images/product_images”

from a view (application/views/scripts/controllerName/viewName.phtml):

<?php $imgSrc = $this-> ProductImageHelper($this-> products[$i][‘products_image’], ‘100’); ?>

<img border=”0″  src=”<?php echo $imgSrc; ?>” />

framework.zend.com “Create a Model and Database Table” tutorial fixed, full working code, adapted for MySQL

Monday, September 20th, 2010

http://framework.zend.com/manual/1.10/en/learning.quickstart.create-model.html

Well, I agonized over getting this, and if you read the comments on the tutorial, many others have as well, working on my home Snow Leopard as well as on my work XP pc, and I spent countless hours looking for a post just such as this one is now, to no avail, so here it all is, hope it helps somebody:

hosts

In the event that you don’t have this done already, here is what should go in your environment’s hosts file…

Mac: /private/etc/hosts

PC:  C:\WINDOWS\system32\drivers\etc

# Setup “components” Virtual Host
<VirtualHost *:80>
ServerName project
DocumentRoot “C:\xampp\htdocs\project\public// or /Library/WebServer/Documents/project/public

<Directory “C:\xampp\htdocs\project\public” // or /Library/WebServer/Documents/project/public>
Options Indexes FollowSymLinks Includes
AllowOverride All
Order allow,deny
Allow from all
</Directory>
</VirtualHost>

create the database that this will use

CREATE TABLE IF NOT EXISTS `guestbook` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`email` varchar(32) DEFAULT NULL,
`comment` text,
`created` datetime DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE=MyISAM  DEFAULT CHARSET=latin1 AUTO_INCREMENT=3 ;

add dummy data to the database

INSERT INTO `guestbook` (`id`, `email`, `comment`, `created`) VALUES
(1, ‘ralph@schindler.com’, ‘hello’, ‘2010-09-17 00:00:00’),
(2, ‘foo@bar.com’, ‘goodbye’, ‘2010-09-17 00:00:00’);

if you haven’t done so already, create the user this app will use to connect, and give the user the priviledges they’ll need

CREATE USER ‘guestbook’@’localhost’ IDENTIFIED BY ‘guestbook’;

GRANT ALL ON ‘guestbook’ TO ‘guestbook’@’localhost’;

project/application/Bootstrap.php

<?php
class Bootstrap extends Zend_Application_Bootstrap_Bootstrap
{
public function _initAutoloader()
{
// Create an resource autoloader component
$autoloader = new Zend_Loader_Autoloader_Resource(array(
‘basePath’    => APPLICATION_PATH,
‘namespace’ => ‘Application’
));

// Add some resource types
$autoloader->addResourceTypes(array(
‘forms’ => array(
‘path’ => ‘forms’,
‘namespace’ => ‘Form’
),
‘models’ => array(
‘path’ => ‘models’,
‘namespace’ => ‘Model’
),
));

// Return to bootstrap resource registry
return $autoloader;
}

protected function _initActionHelpers()
{
Zend_Controller_Action_HelperBroker::addPath(APPLICATION_PATH .’/helpers’);
}

protected function _initDoctype()
{
$this->bootstrap(‘view’);
$view = $this->getResource(‘view’);
$view->doctype(‘XHTML1_STRICT’);
}
}

project/public/index.php

<?php
// Define path to application directory
defined(‘APPLICATION_PATH’)
|| define(‘APPLICATION_PATH’, realpath(dirname(__FILE__) . ‘/../application’));

// Define application environment
defined(‘APPLICATION_ENV’)
|| define(‘APPLICATION_ENV’, (getenv(‘APPLICATION_ENV’) ? getenv(‘APPLICATION_ENV’) : ‘development’));

// Ensure library/ is on include_path
set_include_path(implode(PATH_SEPARATOR, array(
realpath(APPLICATION_PATH . ‘/../library’),
get_include_path(),
)));

/** Zend_Application */
require_once ‘Zend/Application.php’;

// Create application, bootstrap, and run
$application = new Zend_Application(
APPLICATION_ENV,
APPLICATION_PATH . ‘/configs/application.ini’
);
$application->bootstrap()
->run();

project/application/configs/application.ini

[production]
phpSettings.display_startup_errors = 0
phpSettings.display_errors = 0
includePaths.library = APPLICATION_PATH “/../library”
bootstrap.path = APPLICATION_PATH “/Bootstrap.php”
bootstrap.class = “Bootstrap”
appnamespace = “Application”
resources.frontController.controllerDirectory = APPLICATION_PATH “/controllers”
resources.frontController.params.displayExceptions = 0
resources.view[] =
resources.layout.layoutPath = APPLICATION_PATH “/layouts/scripts/”

resources.db.adapter = “PDO_MYSQL”
resources.db.params.host = “localhost”
resources.db.params.username = “guestbook”
resources.db.params.password = “guestbook”
resources.db.params.dbname = “guestbook”

[staging : production]

[testing : production]
phpSettings.display_startup_errors = 1
phpSettings.display_errors = 1

[development : production]
phpSettings.display_startup_errors = 1
phpSettings.display_errors = 1
resources.frontController.params.displayExceptions = 1

project/application/controllers/GuestbookController.php

<?php
class GuestbookController extends Zend_Controller_Action
{

public function init()
{
/* Initialize action controller here */
}

public function indexAction()
{
$guestbook = new Application_Model_GuestbookMapper();
$guestbook->fetchAll();
//var_dump($guestbook);
$this->view->entries = $guestbook->fetchAll();
}
}

project/application/models/Guestbook.php

<?php
class Application_Model_Guestbook
{
protected $_comment;
protected $_created;
protected $_email;
protected $_id;

public function __construct(array $options = null)
{
if (is_array($options)){
$this->setOptions($options);
}
}

public function __set($name, $value)
{
$method = ‘set’ . $name;
if ((‘mapper’ == $name) || !method_exists($this, $method)){
throw new Exception(‘Invalid guestbook property’);
}
$this->$method($value);
}

public function __get($name)
{
$method = ‘get’ . $name;
if ((‘mapper’ == $name) || !method_exists($this, $method)){
throw new Exception(‘Invalid guestbook property’);
}
return $this->$method();
}

public function setOptions(array $options)
{
$methods = get_class_methods($this);
foreach($options as $key => $value){
$method = ‘set’ . ucfirst($key);
if (in_array($method, $methods)){
$this->$method($value);
}
}
}

public function setComment($text)
{
$this->_comment = (string) $text;
return $this;
}

public function getComment()
{
return $this->_comment;
}

public function setEmail($email)
{
$this->_email = (string) $email;
return $this;
}

public function getEmail()
{
return $this->_email;
}

public function setCreated($ts)
{
$this->_created = $ts;
return $this;
}

public function getCreated()
{
return $this->_created;
}

public function setId($id)
{
$this->_id = (int) $id;
return $this;
}

public function getId()
{
return $this->_id;
}
}

project/application/models/GuesbookMapper.php

<?php
class Application_Model_GuestbookMapper
{
protected $_dbTable;

public function setDbTable($dbTable)
{
if (is_string($dbTable)){
$dbTable = new $dbTable();
}
if (!$dbTable instanceof Zend_Db_Table_Abstract){
throw new Exception(‘Invalid table data gateway provided’);
}
$this->_dbTable = $dbTable;
return $this;
}

public function getDbTable()
{
if (null === $this->_dbTable){
$this->setDbTable(‘Application_Model_DbTable_Guestbook’);
}
return $this->_dbTable;
}

public function save(Application_Model_Guestbook $guestbook)
{
$data = array(
’email’    =>    $guestbook->getEmail(),
‘comment’    =>    $guestbook->getComment(),
‘created’    =>    date(‘Y-m-d H:i:s’),
);

if (null === ($id = $guestbook->getId())){
unset($data[‘id’]);
$this->getDbTable()->insert($data);
} else {
$this->getDbTable()->update($data,array(‘id = ?’ => $id));
}
}

public function find($id, Application_Model_Guestbook $guestbook)
{
$result = $this->getDbTable()->find($id);
if (0 == count($result)){
return;
}
$row = $result->current();
$guestbook->setId($row->id)
->setEmail($row->email)
->setComment($row->comment)
->setCreated($row->created);
}

public function fetchAll()
{
$resultSet = $this->getDbTable()->fetchAll();
//var_dump($resultSet);
$entries = array();
foreach ($resultSet as $row){
$entry = new Application_Model_Guestbook();
$entry->setId($row->id)
->setEmail($row->email)
->setComment($row->comment)
->setCreated($row->created);
$entries[] = $entry;
}
return $entries;
}
}

project/application/models/DbTable/Guestbook.php

<?php
class Application_Model_DbTable_Guestbook extends Zend_Db_Table_Abstract
{
/** Table name */
protected $_name    = ‘guestbook’;
}

project/application/views/scripts/guestbook/index.phtml

<p><a href=”<?php echo $this->url(
array(
‘controller’ => ‘guestbook’,
‘action’ => ‘sign’
),
‘default’,
true) ?>“>Sign Our Guestbook</a></p>

Guestbook Entries: <br />
<dl>
<?php foreach ($this->entries as $entry): ?>
<dt><?php echo $this->escape($entry->email) ?></dt>
<dd><?php echo $this->escape($entry->comment)?></dd>
<?php endforeach ?>
</dl>

final URL to hit: http://project/guestbook

Drupal Notes 7: module custom content type, hook_filter(), custom hook, mail API, sends themed email to all members, creates an action and a trigger

Monday, September 6th, 2010

a few of the hooks utilized in this module:

hook_help(), hook_node_info(), hook_form(), hook_filter(), hook_filter_tips(),
hook_action_info(), hook_theme(), hook_mail(), hook_install()

Biggest concept herein: module_invoke_all()

Step 1: sitenews.info

; $Id$
name = “sitenews”
description = “Sends an email news message to all members”
core = 6.x
php = 5.1
; dependencies = “trigger”

Step 2: sitenews.module

// $Id$
/**
* sitenews Module
* Adds a content type
* Provides an action for admininstrators
* Sends emails to all members
* Defines a new hook and a new filter as well
* @file
*/
/**
* Implementation of hook_help()
*/

function sitenews_help($path, $arg){
if($path == ‘admin/help#sitenews’){
$txt = ‘Keep members current via email.’
. ‘You will need a trigger to the corresponding action.’
. ‘Recommendation: the node publish event should be tied to the action.’;
$replace = array();
return ‘<p>’ . t($txt, $replace) . ‘</p>’;
}
}
/**
* Create the sitenewsbrief’ content type
* Implements hook_node_info()
*/

function sitenews_node_info(){
return array(
‘newsbrief’ => array(
‘module’ => ‘sitenews’,
‘name’ => t(‘News Brief’),
‘description’ => t(“A newsletter to all members”),
‘has_title’ => TRUE,
‘title_label’ => t(‘Title’),
‘has_body’ => TRUE,
‘body_label’ => t(‘News Brief’),
)
);
}
/**
* Create the form for editing sitenewsbrief nodes
* Implements hook_form()
*/

function sitenews_form(&$node){
$type = node_get_types(‘type’, $node);
if($type->has_title){
$form[‘title’] = array(
‘#type’ => ‘textfield’,
‘#title’ => check_plain($type->title_label),
‘#required’ => true,
‘#default_value’ => $node->title,
‘#weight’ => -5,
);
}
if($type->has_body){
$form[‘body_field’] = node_body_field(
$node,
$type->body_label,
$type->min_word_count
);
}
return $form;
}
/**
* Implements hook_filter()
*/

function sitenews_filter($op, $delta = 0, $format = -1, $text = ”){
global $user;

if($op == ‘list’){
$list = array(
0 => t(‘Newsletter Brief Placeholders’),
1 => t(‘Remove ALL HTML/XML Tags’),
);
return $list;
}

switch($delta){
// Delta 0 is for replacing placeholders
case 0:
switch ($op)
{
case ‘description’:
return t(‘Replaces {{salutation}} with newsletter brief ‘
. ‘salutation, and {{brief name}} with the newsletter brief ‘
. ‘name.’);
case ‘prepare’:
return $text;
case ‘process’:
$text = str_replace(
{{salutation}}‘,
variable_get(‘sitenews_salutation’, ‘Dear Community Member’),
$text
);
$text = str_replace(
{{brief name}}‘,
variable_get(‘sitenews_name’, ‘Site News’),
$text
);
return $text;
case ‘settings’:
$form[‘sitenews_filter’] = array(
‘#type’ => ‘fieldset’,
‘#title’ => t(‘Site Newsletter Filters’),
‘#collapsible’ => true,
‘#collapsed’ => false,
);
$form[‘sitenews_filter’][‘sitenews_salutation’] = array(
‘#type’ => ‘textfield’,
‘#description’ => t(‘The greeting’),
‘#title’ => t(‘Salutation’),
‘#default_value’ => variable_get(‘sitenews_salutation’, ‘Dear Community Member,’),
);
$form[‘sitenews_filter’][‘sitenews_name’] = array(
‘#type’ => ‘textfield’,
‘#description’ => t(‘Title of the site newsletter’),
‘#title’ => t(‘Site Newsletter Name’),
‘#default_value’ => variable_get(‘sitenews_name’, ‘Site Newsletter’),
);
return $form;
}
case 1:
switch($op)
{
case ‘description’:
return t(‘Removes all tags (HTML or XML elements).’);
case ‘prepare’:
return $text;
case ‘process’:
return strip_tags($text);
} // end switch for $op
} // end outer switch
}
/**
* Formatting instruction tips for content creators
* Implements hook_format_info()
*/

function sitenews_filter_tips($delta, $format, $long){
switch($delta){
case 0:
$text = “Instances of {{brief name}} will be ”
. “replaced by the global name for site newsletter.”
. ” {{salutation}} will be replaced with the global ”
. “greeting message.”;
if($long){
$text .= “Site Newsletter name and salutation text ”
. “can be configured from the administration interface.”;
}
return $text;
case 1:
$text = “HTML and XML tags will be removed from the final output”;
return $text;
}
}
/**
* Get a format ID by name
* This returns an Input Format ID that can be passed to check_marckup() to filter content
* If a matching format isn’t found, the default format is returned
* @param $name
* String name of the format
* @return
* The ID (an integer) of the format
*/

function sitenews_get_format($name){
$res = db_query(
SELECT format FROM {filter_formats} WHERE name = ‘%s’“,
$name
);
$format = db_fetch_object($res);
if($format){
return $format->format;
} else {
return FILTER_FORMAT_DEFAULT;
}
}
/**
* Implements hook_action_info()
*/

function sitenews_action_info(){
watchdog(‘action‘,”Called sitenews_action_info”);
$actions[‘sitenews_send_action’] = array(
‘type’ => ‘node’,
‘description’ => t(‘Send site news as email to all users.’),
‘configurable’ => FALSE,
‘hooks’ => array(
‘nodeapi’ => array(‘insert’,’update’,’presave’),
)
);
return $actions;
}
/**
* Action: Send an email message to all users
*/

function sitenews_send_action(&$object, $context){
// If not a published sitenews, skip
if(!$object->status || $object->type != ‘newsbrief’){
return;
}
// Get addresses
$q = “SELECT mail, status FROM {users} ”
. “WHERE status != 0 AND uid > 0
“;
$results = db_query($q);
$addresses = array();
while($obj = db_fetch_object($results)){
$addresses[] = $obj->mail;
}
if(count($addresses) == 0){
watchdog(
‘sitenews’,
‘No user email addresses were found’,
array(),
WATCHDOG_ERROR
);
return;
}
// Execute hook_sitenews()
$content = module_invoke_all(‘sitenews’);
// Build params
$params = array(
‘node’ => $object,
‘to’ => implode(‘, ‘, $addresses),
‘subject’ => $object->title,
‘context’ => $context,
‘additional content’ => $content,
);
$message = _sitenews_do_message($object, $params);
watchdog(
actions‘,
‘Site News “Send action fired. Sending to !mail’,
array(‘!mail’ => $params[‘to’])
);
}
/**
* Internal function to prepare a message and pass it on to the mailer
* @param $node
* The news brief node
* @param $params
* An array of params
*/

function _sitenews_do_message(&$node, $params){
$node = $params[‘node’];
$content = $params[‘additional content’];
// Theme the main node:
$params[‘body’] = theme(‘sitenews_newsbrief’, $node);
// See common.inc (element_sort() and drupal_render()
uasort($content, ‘element_sort’);
// Render each block of content;
foreach($content as $item){
$params[‘body’] .= theme(‘sitenews_msgblock’, $item);
}
// Send the mail:
drupal_mail(
‘sitenews’,
‘sendsitenews’,
$params[‘to’],
language_default(),
$params,
variable_get(‘site_mail’,NULL),
TRUE
);
}
/**
* Implements hook_theme()
*/

function sitenews_theme(){
return array(
‘sitenews_msgblock’ => array(
‘arguments’ => array(‘block’ => NULL),
),
‘sitenews_newsbrief’ => array(
‘arguments’ => array(‘node’ => NULL),
),
);
}
/**
* Theme to display a news brief in a sitenews message block
* @param $node
* The news brief node object
*/

function theme_sitenews_newsbrief($node){
$format = sitenews_get_format(‘Tagless text’);
$text = strtoupper(check_markup($node->title, $format)) . “\n\n”;
$text .= check_markup($node->body, $format) . “\n\n”;
return $text;
}
/**
* Theme for email messages
* @param $block
* A block with #title and #body set
*/

function theme_sitenews_msgblock($block){
$msg = array();
if(!empty($block[‘#title’])){
$title = strtoupper($block[‘#title’]);
for ($i = 0; $i < strlen($title); ++$i){
$underline .= ‘=’;
}
$msg[] = $title;
$msg[] = $underline;
}
$msg[] = $block[‘#body’] .”\n”; // <– extra newline
return implode(“\n”, $msg);
}
/**
* Implementation of hook_mail()
*/

function sitenews_mail($key, &$message, $params){
switch($key){
case ‘sendsitenews’:
$message[‘to’] = $params[‘to’];
$message[‘subject’] = $params[‘subject’];
$message[‘body’] = $params[‘body’];
}
}

Step 3: sitenews.install

// $Id$
/**
* Install the newsletter module
* @file
*/
/**
* Implements hook_intall()
*/
function sitenews_install(){
$name = ‘Tagless text’;
// Check to see if the format already exists
$res = db_query(
SELECT name FROM {filter_formats} WHERE name = ‘%s’“,
$name
);
$has_format = db_result($res);
// Create format
if (!$has_format){
db_query(
INSERT INTO {filter_formats} (name) VALUES (‘%s’)“,
$name
);
}
$res = db_query(
SELECT format FROM {filter_formats} WHERE name = ‘%s’“,
$name
);
$format = db_fetch_object($res);
$q = “INSERT INTO {filters} (format, module, delta, weight) ”
. “VALUES(%d, ‘newsletter’, %d, %d)
“;
// First, insert the “Newsletter Brief Placeholders” filter:
db_query($q, $format->format, 0, 10);
// Second, insert the “Remove ALL HTML/XML Tags” filter:
db_query($q, $format->format, 1, 0);
}

Step 4: add to module_sitenews() to any modules that will be contributing content to these automatically generated email newsletters, example from personality module (Drupal Notes 6) follows:

function personality_theme(){
return array(
‘personality_info’ => array(
‘template’ => ‘personality_info’,
‘arguments’ => array(
‘dates’ => NULL,
‘life’ => NULL,
‘works’ => NULL,
),
),
// NEW
‘personality_sitenews’ => array(
‘arguments’ => array(‘node’ => NULL),
),
);
}
/**
* Theme function for sitenews
*/

function theme_personality_sitenews($node){
$options = array(‘absolute’ => TRUE);
$url = url(‘node/’. $node->nid, $options);
$title = strip_tags($node->title);
$body = strip_tags($node->teaser); // <– Summary
$text = implode(“\n”, array($title, $body, $url));
$text .= “\n”;
return $text;
}

/*
* Implements hook_sitenews() in sitenews module
*/

function personality_sitenews(){
$q = “SELECT nid, created FROM {node} ”
. “WHERE status = 1 AND type = ‘personality’ ”
. “ORDER BY created DESC
“;
$results = db_query_range($q, 0, 3);
$new_bios = array();
while ($row = db_fetch_object($results)){
$node = node_load($row->nid);
$new_bios[] = theme(‘personality_sitenews’, $node);
}
$content[‘personality’] = array(
‘#weight’ => 0,
‘#title’ => t(‘Recent Biographies’),
‘#body’ => implode(“\n”, $new_bios),
);
return $content;
}

Drupal Notes 6: module + new content type (non CCK)

Sunday, September 5th, 2010

Description: Module that uses a new content type (non CCK), that uses the Schema API, Node API, Database API, Forms API and the following hooks:

hook_form(), hook_install(), hook_uninstall(), hook_schema(), hook_node_info(), hook_perm(), hook_access(), hook_insert(), hook_update(), hook_delete(), hook_nodeapi(), hook_load(), hook_view(), hook_theme()

Step 1: sites/all/modules/personality folder

Step 2: personality.info

; $Id$
name = “Personality Content (Node) Type”
description = “This provides a custom content type to store simple online personalities”
core = 6.x
php = 5.1

Step 3: personality.install

// $Id$
/**
* Install the personality module, including its content (node) type.
* @file
*/

/**
* Implementation of hook_install()
*/

function personality_install(){
drupal_install_schema(‘personality’);
}
/**
* Implementation of hook_uninstall()
*/

function personality_uninstall(){
drupal_uninstall_schema(‘personality’);
}
/**
* Implementation of hook_schema()
*/

function personality_schema(){
$schema[‘personality’] = array(
‘fields’ => array(
‘vid’ => array(
‘type’ => ‘int’,
‘unsigned’ => TRUE,
‘not null’ => TRUE,
‘default’ => 0,
),
‘nid’ => array(
‘type’ => ‘int’,
‘unsigned’ => TRUE,
‘not null’ => TRUE,
‘default’ =>0,
),
‘dates’ => array(
‘type’ => ‘varchar’,
‘length’ => 127,
‘not null’ => TRUE,
‘default’ => ”,
),
// Note: On MySQL, text fields cannot have default values
‘life’ => array(
‘type’ => ‘text’,
‘not null’ => FALSE
),
‘works’ => array(
‘type’ => ‘text’,
‘not null’ => FALSE
),
),
‘indexes’ => array(
‘nid’ => array(‘nid’),
),
// Version is primary key.  Could do nid, vid.
‘primary key’ => array(‘vid’),
);
return $schema;
}

Step 4: personality.module

// $Id$
/**
* Provides the Personality content type
* @file
*/
/**
* Implementation of hook_help()
*/
function personality_help($path, $arg){
if($path == ‘admin/help#personality’){
$txt = ‘A personality is a description of a person\’s person.  Should include a brief summary, biography, date of birth, optionally date of death, and accomplishments.’;
$replace = array();
return ‘<p>’ . t($text, $replace) . ‘</p>’;
}
}
/**
* Imnplementation of hook_node_info()
*/

function personality_node_info(){
return array(
‘personality’ => array(
‘name’ => t(‘Personality’),
‘module’ => ‘personality’,
‘description’ => t(‘A personality of a person.’),
‘has_title’ => TRUE,
‘title_label’ => t(‘Personality of’),
‘has_body’ => TRUE,
‘body_label’ => t(‘Overview’),
)
);
}
/**
* Implementation of hook_form()
*/

function personality_form(&$node){
$type = node_get_types(‘type’, $node);
//Existing files: title (Personality of) and body (Overview)
if($type->has_title){
$form[‘title’] = array(
‘#type’ => ‘textfield’,
‘#title’ => check_plain($type->title_label),
‘#required’ => TRUE,
‘#default_value’ => $node->title,
‘#weight’ => -5,
);
}
if($type->has_body){
$form[‘body_field’] = node_body_field(
$node,
$type->body_label,
$type->min_word_count
);
}
// Our custom fields: Dates, Life, Works
$form[‘dates’] = array(
‘#type’ => ‘textfield’,
‘#size’ => 50,
‘#maxlength’ => 127,
‘#title’ => t(‘Dates’),
‘#description’ => t(‘Birth and death dates.’),
‘#default_value’ => isset($node->dates) ? $node->dates : ”,
);
$form[‘life’] = array(
‘#type’ => ‘textarea’,
‘#title’ => t(‘Life’),
‘#cols’ => 50,
‘#rows’ => 15,
‘#description’ => t(‘A description of this perons\’s life.’),
‘#default_value’ => isset($node->life) ? $node-life : ”,
);
$form[‘works’] = array(
‘#type’ => ‘textarea’,
‘#title’ => t(‘Works’),
‘#cols’ => 50,
‘#rows’ => 5,
‘#description’ => t(‘This person\’s Personality’),
‘#default_value’ => isset($node->works) ? $node->works : ”,
);
return $form;
}
/**
* Implements hook_perm()
* Responsible for registering new permissions
*/

function personality_perm(){
return array(
‘create personality node’,
‘edit personality nodes’,
‘delete personality nodes’,
);
}
/**
* Implementation of hook_access()
* which implements our new permissions
*/

function personality_access($op, $node, $account){
switch($op){
case ‘create’:
return user_access(‘create personality node’, $account);
case ‘update’:
return user_access(‘edit personality nodes’, $account);
case ‘delete’:
return user_access(‘delete personality nodes’, $account);
}
}
/**
* Implements hook_insert()
*/

function personality_insert($node){
if(!isset($node->life)){
$node->life = ”;
}
if(!isset($node->works)){
$node->works = ”;
}
db_query(
INSERT INTO {personality} (vid, nid, dates, life, works) VALUES (%d, %d, ‘%s’, ‘%s’, ‘%s’)“,
$node->vid,
$node->nid,
$node->dates,
$node->life,
$node->works
);
}
/**
* Implements hook_update()
*/

function personality_update($node){
if($node->revision){
personality_insert($node);
}
else{
db_query(
UPDATE {personality} SET dates = ‘&s’, life = ‘%s’, works = ‘%s’ WHERE vid = %d“,
$node->dates,
$node->life,
$node->works,
$node->vid
);
}
}
/**
* Implements hook_delete()
*/

function personality_delete($node){
db_query(
DELETE FROM {personality} WHERE nid = %d“,
$node->nid
);
}
/**
* This implementation deletes node revisions
* Implements hook_nodeapi()
*/

function personality_nodeapi(&$node, $op, $teaser, $page){
if($op == ‘delete revision’){
db_query(
DELETE FROM {personality} WHERE vid = %d‘,
$node->vid
);
}
}
/**
* Implementation of hook_load()
*/

function personality_load($node){
$result = db_query(
SELECT dates, life, works FROM {personality} WHERE vid = %d‘,
$node->vid
);
return db_fetch_object($result);
}
/**
* Implementation of hook_view()
*/

function personality_view($node, $teaser = FALSE, $page = FALSE){
$node = node_prepare($node, $teaser);
$dates = check_plain($node->dates);
$life = check_markup($node->life);
$works = check_markup($node->works);
// Add theme
$node->content[‘personality_info’] = array(
‘#value’ => theme(‘personality_info’, $dates, $life, $works),
‘#weight’ => 1,
);
return $node;
}
/**
* Implements hook_theme()
*/

function personality_theme(){
return array(
‘personality_info’ => array(
‘template’ => ‘personality_info’,
‘arguments’ => array(
‘dates’ => NULL,
‘life’ => NULL,
‘works’ => NULL,
),
),
);
}

Step 5: personality_info.tpl.php template theme file

// $Id$
/**
* Template to display personality nodes.
*
* Fields available:
* $dates: cleaned plain text string
* $life: cleaned HTML string
* $works: cleaned HTML string
*/

<div>
<h2>< ? php print t(‘Dates’); ? >:</h2>
< ? php print $dates; ? >
<h2>< ? php print t(‘Life’); ? >:</h2>
< ? php print $life; ? >
<h2>< ? php print t(‘Works’); ? >:</h2>
< ? php print $works; ? >
</div>

Drupal Notes 5: admin module emails users from profile: hook_mail(), hook_mail_alter(), hook_help(), hook_menu(), Forms API, hook_user()

Saturday, September 4th, 2010

For this module it’s best that your development environment is configured to send live emails.
If it’s local, xampp perhaps, and not currently configured as such,
you may want to refer to this post first:
http://alexyz.com/sending-mail-xampp-gmail/

Step 1, of course, create a new folder entitled emailusers in sites/all/modules

Step 2, in that folder, create emailusers.info, containing the following
(if you’ve read Notes 1-4 this should all be very familiar already):

;$Id$
name = “emailusers”
description = “admin module for emailing users from within their profile”
core = 6.x
php = 5.1

Step 3, create emailusers.module in same folder, contents thereof follow:

// $Id$
/**
* This module provides an email interface for administrators.
* Using this module, administrators can send email to a user from the
* user’s “view” page.
* @file
*/
/**

* Implementation hook_help()
*/

function emailusers_help($path, $arg){
if($path == ‘admin/help#emailusers’){
$txt = ‘This module provides a way for an administrator to send’
. ’email to a user. ‘
. ‘It assumes that the Drupal mailer is configured.’;
return ‘<p>’ . t($txt) . ‘</p>’;
}
}
/**
* Implementation of hook_munu()
*/

function emailusers_menu(){
// Need to pass User ID via placeholder %,
// thus URL will be available here: ?q=admin/emailusers/compose/userIdHere

$items[‘admin/emailusers/compose/%‘] = array(
‘title’ => ‘Compose a Message’,
‘page callback’ => ’emailusers_compose’,
‘page arguments’ => array(3), // <- userId (from % in node path)
‘access arguments’ => array(‘administer users’),
‘type’ => MENU_CALLBACK,
);
return $items;
}
/**
* Compose a message.
* This creates the form necessary to compose an email message.
*
* @param $to
* The address to send to.
* @return
* HTML.
*/

function emailusers_compose($userid){
$userid = intval($userid);
if($userid == 0){
return t(‘User ID must be an integer.’);
}
$account = user_load($userid);
if(empty($account)){
return t(‘No such user found.’);
}
$to = $account->mail;
$sb = ‘<p>’
. t(‘Send a message to @email.’, array(‘@email’ => $to))
. ‘</p>’;
$sb .= drupal_get_form(’emailusers_compose_form’, $account);
// Forms API / FAPI
// http://drupal.org/node/751826
// http://api.drupal.org/api/drupal/developer–topics–forms_api_reference.html/6

return $sb;
}
/**
* Form constructor
*/

function emailusers_compose_form($context, $account){
// This is a value only — equivalent to a hidden field
// except that it is never renered into the HTML

$form[‘to’] = array(
‘#type’ => ‘value’,
‘#value’ => $account,
);
// Create a fieldset for the body:
$form[‘message’] = array(
‘#type’ => ‘fieldset’,
‘#title’ => t(‘Compose the Message’),
);
// Textfield for subject of the body
$form[‘message’][‘subject’] = array(
‘#type’ => ‘textfield’,
‘#title’ => t(‘Subject’),
‘#size’ => 50,
‘#maxlength’ => 255,
‘#description’ => t(‘The subject of the email message.’),
);
// And a text area for the body.
$form[‘message’][‘body’] = array(
‘#type’ => ‘textarea’,
‘#title’ => t(‘Message’),
‘#cols’ => 50,
‘#rows’ => 5,
‘#description’ => t(‘The body of the email message.’),
);
// Create a fieldset for details
$form[‘details’] = array(
‘#type’ => ‘fieldset’,
‘#title’ => t(“Details”),
);
// Checkbox: if checked, CC the author too
$form[‘details’][‘cc_me’] = array(
‘#type’ => ‘checkbox’,
‘#title’ => t(‘BCC Yourself’),
‘#default_value’ => 1,
‘#description’ => t(‘If this is checked, the message will also be sent to you.’),
);
// Finally, a submit button:
$form[‘submit’] = array(
‘#type’ => ‘submit’,
‘#value’ => t(‘Send Mail’),
);
return $form;
}
/**
* Form submission handler, which functions like a hook.
* Note that the params $form and &$form_state are new in D6.
* They replace $form_id and $form_values.
*/

function emailusers_compose_form_submit($form, &$form_state){
$form_values = $form_state[‘values’];
$account = $form_values[‘to’];
drupal_mail(
’emailusers’,
‘composemessage’,
$account->mail,
user_preferred_language($account),
$form_values,
variable_get(‘site_mail’, null),
true // Automatically send
);
// drupal_mail will invoke hook_mail(), or in this case, emailusers_mail(), below
$form_state[‘redirect’] = sprintf(‘user/%d’, $account->uid);
}
/**
* Implementation of hook_mail()
*/

function emailusers_mail($key, &$message, $params){
// Just catch calls to this hook from compose form.
if ($key == ‘composemessage’){
$language = $params[‘language’];
$account = $params[‘to’];
if($params[‘cc_me’]){
// Look up current user’s email address:
//$my_account = user_load(null);

$message[‘headers’][‘bcc’] = $GLOBALS[‘user’]->mail;
}
$message[‘to’] = $account->mail;
$message[‘subject’] = t(‘Drupal Message: ‘, array(), $language->language);
// If these were automatically-generated messages
// they should be run through t()
// but since text is user-entered
// don’t use t()

$message[‘subject’] .= $params[‘subject’];
//$message[‘body’] = $params[‘body’];
$message[‘body’][] = $params[‘body’];
}
}
/**
* Implements hook_mail_alter()
* !! Note: similar, and also of interest are hook_link_alter() & hook_menu_alter()
* simply put, _alter hooks alter data right after their parent hooks are called, but before output
* also important to note: this _alter() below will augment ALL emails sent to the Mail API
* not just those from this module!
*/

function emailusers_mail_alter(&$message){
$append = “\n==================================\n”
. “This message was sent from !site_name (!website). ”
. “If you believe this message to be a case of abuse, ”
. “please contact !site_email.\n”;
$args = array(
‘!website’ => url(”, array(‘absolute’ => true)),
‘!site_email’ => variable_get(‘site_mail’, null),
‘!site_name’ => variable_get(‘site_name’, ‘Unknown’),
);
$message[‘body’] .= t($append, $args);
//$message[‘body’][] = t($append, $args);
}
/**
* Implementation of hook_user().
*/

function emailusers_user($op, &$edit, &$account, $category){
if($op == ‘view’ && user_access(‘administer users‘)){
// Create the outer “block”
$account->content[‘EmailUsers’] = array(
‘#type’ => ‘user_profile_category‘,
‘#attributes’ => array(‘class’ => ‘user-member’),
‘#weight’ => 0,
‘#title’ => t(‘Contact user’),
);
// Create the content of the block
$account->content[‘EmailUsers’][‘EmailLink’] = array(
‘#type’ => ‘user_profile_item‘,
‘#title’ => t(‘Send a message to this user from the site administrator.’),
‘#value’ => l(
‘Email’,
‘admin/emailusers/compose/’ . $account->uid
),
);
}
}

Drupal Notes 4: enhance our module with jQuery AJAX/JSON

Friday, September 3rd, 2010

create quoteDisplay.js to contain:

var quoteDisplay = {}; // JS Namespace Object Creation
if(Drupal.jsEnabled){
$(document).ready(
function(){
$(“#quoteDisplay-origin”).after(“<a>Next &raquo;</a>”).next().click(quoteDisplay.randQuote);
}
);
/**
* A function to fetch quotes from the server,
* and display in the designated area.
*/

quoteDisplay.randQuote = function(){
$.get(Drupal.settings.quoteDisplay.json_url, function(data){
myQuote = Drupal.parseJson(data);
if(!myQuote.status || myQuotes.status == 0){
$(“#quoteDisplay-origin”).text(myQuote.quote.origin);
$(“#quoteDisplay-text”).text(myQuote.quote.text);
}
}); // End inline function
}
}

add this line to quoteDisplay.module file’s theme_quoteDisplay() function (after “drupal_add_js” line, before “$output = ‘

drupal_add_js($module_path . ‘/quoteDisplay.js’);
$opts = array(‘absolute’ => TRUE);
$json_url = url(‘quoteDisplay.json’, $opts);
drupal_add_js(
array(‘quoteDisplay’ =>
array(“json_url” => $json_url)), ‘setting‘);

also add these functions to our quoteDisplay.module file:

/*
* Callback to handle requests for
quoteDisplay content.
* @return
* JSON data.
*/

function quoteDisplay_item(){
$item = _quoteDisplay_get_quote();
drupal_set_header(‘Content-Type: text/plain; charset: utf-8’);
printf(
{ “quote”: { “origin”: “%s”, “text”: “%s” } }‘,
$item->title,
$item->body
);
}

/**
* Implementation of hook_menu()
* registers quoteDisplay.json
* will call quoteDisplay_item() when called
* anyone that may access content may access this path
* MENU_CALLBACK below is a bitmask,
* that doesn’t authomatically create links to this item in the menu or elsewhere,
* it simnply makes this accessible by URL,
* more than 20 such bitmask types may be used,
* see documentation.
*/

function quoteDisplay_menu(){
$items[‘quoteDisplay.json’] = array(
‘title’ => ‘Quote Display AJAX Gateway’,
‘page callback’ => ‘quoteDisplay_item’,
‘access arguments’ => array(‘access content’),
‘type’ => MENU_CALLBACK,
);
return $items;
}

now hit the url to see your JSON return! (you may need to clear your drupal cache of course)
http://localhost/yourDrupalSiteName/?q=quoteDisplay.json

Drupal Notes 3: a themed module for a new content type

Wednesday, September 1st, 2010

create a new content type, create some entries
create a new theme (see earlier notes for how)

quoteDisplay.info contains the following:

; $Id$
name = “Quote Display”
description = “Dynamic display of  quotes.”
core = 6.x
php = 5.1

quoteDisplay.module contains this:

// $Id$
/**
* @file
* Module for dynamic display of pithy philosophy quotes.
*/

/**
* Implementation of hook_help()
*/

function quoteDisplay_help($path, $arg)
{
if ($path == ‘admin/help#quoteDisplay’)
{
$txt = ‘This module displays philosophical quotes in blocks. ‘ .
‘It assumes the existence of a content type named “quote”.’;
return ‘<p>’ . t($txt) . ‘</p>’;
}
}

/**
* Implementation of hook_block()
*/

function quoteDisplay_block($op = ‘list’, $delta = 0, $edit = array())
{
switch($op)
{
case ‘list’:
$blocks[0][‘info’] = t(‘Philosophical Quotes’);
return $blocks;
case ‘view’:
$item = _quoteDisplay_get_quote();
if(!empty($item))
{
$content = theme(‘quoteDisplay_quote’,
check_plain($item->body),
check_plain($item->title));
$blocks[‘subject’] = t(‘Pithy Quote’);
$blocks[‘content’] = $content;
return $blocks;
}
}
}

/*
* Return a quote from the Drupal database
*/

function _quoteDisplay_get_quote()
{
$sql = “SELECT nid FROM {node} “.
“WHERE status = 1 AND type = ‘quote’ ORDER BY RAND() LIMIT 1”;
$res = db_query($sql);
$item = db_fetch_object($res);
$quote = node_load($item->nid);
return $quote;

}

/*
* Implementation of hook_theme().
*/

function quoteDisplay_theme()
{
return array(
‘quoteDisplay_quote’ => array(
‘arguments’ => array(
‘text’ => NULL,
‘origin’ => NULL
),
),
);
}

/*
* Theme function for theming quotes.
*
* @param $text
* The quote content as a string.
* @param $origin
* The original source of the quote, as a string.
* @return
* An HTML themed string.
*/

function theme_quoteDisplay_quote($text, $origin)
{
$module_path = drupal_get_path(‘module’,’quoteDisplay‘);
$full_path = $module_path . ‘/quoteDisplay.css’;
drupal_add_css($full_path);
$output = ‘<div id=”quoteDisplay-text”>’ . t($text) . ‘</div><div id=”quoteDisplay-origin”>’ . t($origin) . ‘</div>’;
return $output;
}

quoteDisplay.css (also in /sites/all/modules/quoteDisplay) contains:

#quoteDisplay-text:first-letter{
font-size:18pt;
font-weight:bold;
}
#quoteDisplay-origin{
font-style: oblique;
text-align: right;
margin-right: 5px;
}

Note:

This module thus has a default “theme” of its own.  This may be overridden via CSS, or via a quoteDisplay.tpl.php file placed within the themes/module/currentTheme folder

Drupal Notes 2: sub-theme derivative of bluemarine : Theme inheritance, overriding, preprocessing

Sunday, August 29th, 2010

add folder to:
sites/all/themes(createThis)/subThemeName(createThis)/

create subThemeName.info (in newly created folder):
; $Id$
name = subThemeName
description = blah blah blah blah blah
version = 1.0
core = 6.x
base theme = bluemarine
stylesheets[all][] = descartes-style.css // copy images from parent theme into sub-theme.
stylesheets[all][] = new.css

finally, create above mentioned new.css (in newly created folder) and add styles you’d like to modify, example:
/*
** Style to override the styles.css in
** bluemarine.css
*/

/*
* Plain white right nav.
*/

#sidebar-right{
border-left: 1px solid #ea940c;
background-color: white;
}

ready to go further? copy any of the following over from bluemarine into yourNewSubTheme and edit away:
page.tpl.php (hint: start here), block.tpl.php, box.tpl.php, comment.tpl.php

even further, you’ve moved $breadcrumb in page.tpl.php to where you’d like it, but you want to edit INSIDE that…
these PHPTemplate functions that render content can be found in yourSite/includes/theme.inc
find the one that spits out the content you’d like to modify, and then create a template.php in your new theme directory and override that function…
example: theme_breadcrumb() uses “>>” as separators, in
yourSite/sites/all/themes/yourNewTheme/template.php (make it)
overwrite theme_breadcrumb() via something like this:


// $Id$
/**
* @page
* Override theme_() functions for the youNewTheme.
*/

// Overrides theme_breadcrumb()
function phptemplate_breadcrumb($breadcrumb){
if (empty($breadcrumb)) return;
$sep = ‘<div>&nbsp;&nbsp;</div>’;
$breadcrumb_string = ‘<div>’ . implode($sep, $breadcrumb) . ‘</div>’;
return $breadcrumb_string;
} // end of template.php example

other PHPTemplate theme functions from includes/theme.inc to investigate:
theme_image(), theme_links(), theme_progress_bar(), theme_username(), theme_table(), theme_item_list()

called as follows:
$variable = theme(‘functionName’, $arg1, $arg2, …) , which looks like this:
$crumb = theme(‘item_list’, $breadcrumb, null, ‘ul’, array(‘class’=>’breadcrumb-items’));

IMPORTANT NOTES/REMEMBER:
– a phptemplate_block() function redefined in template.php will override a block.tpl.php file in template folder!
– if you want to preprocess CONTENT before it’s passed to template.php, thus, instead use phptemplate_preprocess_functions()!
– if you’re NOT making a sub-theme, add to .info this line: engine=phptemplate instead of using the base theme line
– don’t forget to make a nice screenshot.png (150×90)

Drupal Notes 1: module hook_block(), hook_help(), check_plain(), check_url(), watchdog(), t(), l(), placeholders(!,%,@)

Sunday, August 29th, 2010

Create:
moduleName.info & moduleName.info, save them in sites, all, modules

.info example content:
;$Id$ // This will be substituted by Drupal CVS
name = “ModuleNameHere”
description = “Displays items blah blah blah”
core = 6.x
php = 5.1

.module beginnings…:
// $Id$ // This will be substituted by Drupal CVS
/**
* @file
// This denotes that this comment refers to this whole file
* Description Here Of Module…
* @see http://www.goodreads.com // Drupal doc is generated by doxygen, this links to a ref
*/

/**
* Implementation of hook_block()
*/

function moduleName_block($op=’list’, $delta=0, $edit=array()){
switch($op){
case ‘list’:
$blocks[0][‘info’] = t(‘Module Info Title’);
return $blocks;
case ‘view’:
$url = ‘http://www.moduleXML.com/review/list_rss/’;
$blocks[‘subject’] = t(‘Module Subject’);
$blocks[‘content’] = “Module Content Dynamic or Static…”;
return $blocks;
}
}

/**
* Implementation of hook_help()
*/

function moduleName_help($path, $arg){
if($path == ‘admin/help#moduleName){
$txt = ‘The moduleName module uses the !subThisHolder_url API ‘;
$link = l(‘copyForTheAnchorTag’, ‘http://www.moduleName.com’);
$replace = array(!subThisHolder_url‘ => $link);
return ‘<p>’ . t($txt, $replace) . ‘</p>’;
}
} //end of example .module code…

Other things useful of note:

The watchdog() function: http://api.drupal.org/api/function/watchdog/6
watchdog(‘loggingCategoryNameThisModuleNameMostLikely’, $msg, $varsToSubIntoMsg, WATCHDOG_WARNING):
logging options:
WATCHDOG_EMERG
WATCHDOG_ALERT
WATCHDOG_CRITICAL
WATCHDOG_ERROR
WATCHDOG_WARNING
WATCHDOG_NOTICE
WATCHDOG_INFO
WATCHDOG_DEBUG

check_plain()http://api.drupal.org/api/function/check_plain/6

check_url() http://api.drupal.org/api/function/check_url/6

t() example:

t(‘Replacing %value by !urlHere for @emailPerhaps ‘, array(‘%value’=>’test’, ‘@emailPerhaps’=>$email, ‘!urlHere’=>’http://blah.com’);

!placeholders replaced as is, @placeholders replaced effectively “escaped by” check_plain(), %placeholders are replaced themed as well

PHP Interface and Abstract Class example

Sunday, August 22nd, 2010

abstract class animal
{
abstract function getowned();
private $age;

protected function __construct($age) {
$this->age = $age;
}

public function getage()
{
return $this->age;
}
}
interface insurable {
public function getvalue();
}

class pet extends animal implements insurable {
private $name;
public function __construct($name,$age) {
parent::__construct($age);
$this->name = $name;
}
public function getname() {
return $this->name;
}
public function getowned() {
return (“Owner String”);
}
public function getvalue() {
return (“Priceless”);
}
}

class house implements insurable {
public function getvalue() {
return (“Rising fast”);
}

}

$charlie = new pet(“Charlie”,6);
$catage = $charlie -> getage();
$catname = $charlie -> getname();
print “$catname is $catage years old!<br><br>”;

if ($charlie instanceof pet) print (“charlie is a pet<br>”);
if ($charlie instanceof animal) print (“charlie is an animal<br>”);
if ($charlie instanceof house) print (“charlie is a house<br>”);

if ($charlie instanceof insurable) print (“charlie is insurable<br>”);
reference: http://www.wellho.net/resources/ex.php4?item=h108/animal3.php

simple PHP namespace example

Sunday, August 22nd, 2010

Foo.class.php
class Foo
{
function Simple()
{
$var = “Hello”;
return $var;
}
}

namespace.php
namespace Second;
include(‘Foo.class.php’);

class Foo
{
function Simple()
{
$var = “Hello in Second Namespace<br />”;
return $var;
}
}

$fooSecond = new \Second\Foo();
echo $fooSecond->Simple();
//option 1
//$fooFirst = new \Foo();
//$fooFirst->Simple();
//option 2

echo \Foo::Simple();

simple PHP __autoload example

Sunday, August 22nd, 2010

Foo.class.php
class Foo
{
public static $varz;
public static function Simple()
{
self::$varz = “Hello”;
return self::$varz;
}
}

index.php (in the same directory)
function __autoload($classname) {
include(“$classname.class.php”);
}

//include “Foo.class.php”; //no longer needed!

$foo = new Foo();
echo $foo->Simple();

simple ob_start(), flush(), ob_gzhandler, sleep(), HEREDOC examples

Sunday, August 22nd, 2010

//ob_start()
ob_start();
print “Hello First!\n”;
ob_end_flush();

ob_start();
print “Hello Second!\n”;
ob_end_clean();

ob_start();
print “Hello Third!\n”;

//outputs “Hello First! Hello Third!”

//flush()

<HTML>
<BODY>
<DIV ID=”flushme”>
Hello, world!
</DIV>
< ? php flush(); sleep(2); ? >
<SCRIPT>
d = document.getElementById(“flushme”);
d.innerHTML = “Goodbye, Perl!”;
</SCRIPT>
< ? php flush(); sleep(2); ? >
<SCRIPT>
d.innerHTML = “Goodnight, New York!”;
</SCRIPT>
</BODY>
</HTML>

// compressed output

< ? php
ob_start(‘ob_gzhandler’);
print “My content\n”;
ob_end_flush();
? >

// sleep

< ? php
ob_implicit_flush(true);
for($i=0;$i<5;$i++)
{
$dis=<<<DIS
<div style=”width:200px; background-color:lime;border:1px; text-align:center;text-decoration:blink;”>
$i
</div>
DIS;
echo $dis;

sleep(5);
//flush();
}
? >

memory jogger: Chain of responsibility, Polymorphism, Design Pattern reference, Decorator pattern, Singleton

Saturday, August 21st, 2010

Good stuff, take a moment to refresh and review:

Chain of responsibility:
http://en.wikipedia.org/wiki/Chain-of-responsibility_pattern
Polymorphism:
http://en.wikipedia.org/wiki/Polymorphism_in_object-oriented_programming
JavaScript really OOP?:
http://articles.techrepublic.com.com/5100-10878_11-1044656.html
http://mckoss.com/jscript/object.htm
JS Prototype object:
http://www.javascriptkit.com/javatutors/proto4.shtml
Design Patterns reference/list:
http://en.wikipedia.org/wiki/Design_pattern_%28computer_science%29
Decorator Pattern:
http://en.wikipedia.org/wiki/Decorator_pattern
Loose Coupling def:
http://en.wikipedia.org/wiki/Loose_coupling
Singleton Pattern:
http://en.wikipedia.org/wiki/Singleton_pattern

MySQL sub query example – nice

Monday, August 16th, 2010

$cp_output = “”;
if(!$get_cp_data = mysql_query(”
SELECT
q.*,
c.*,
vote_counts.Tally
FROM
questions q
LEFT JOIN
(SELECT
questionId,
count(1) as Tally
FROM
votes
GROUP BY
questionId
) vote_counts
ON
q.questionId = vote_counts.questionId
LEFT JOIN
customers c
ON
c.customerId = q.customerId
WHERE
q.courseId = 1
ORDER BY
vote_counts.Tally desc

“)){ echo mysql_error(); }

while($get_cp_data_array = mysql_fetch_array($get_cp_data)){
$q_id = $get_cp_data_array[‘questionId’];

$q_fname = $get_cp_data_array[‘customerFName’];
$q_lname = $get_cp_data_array[‘customerLName’];
$q_email = $get_cp_data_array[‘customerEmail’];

$q_topic = $get_cp_data_array[‘questionTopic’];
$q_question = $get_cp_data_array[‘question’];
$q_date = $get_cp_data_array[‘questionDate’];
//$q_count = $get_cp_data_array[‘votecount’];
$q_customer = $get_cp_data_array[‘customerId’];

if($q_topic == “”){ $q_topic = “–“; }
if($q_fname != “” || $q_lname != “”){
$from = ‘<strong>’ . $q_fname . ‘ ‘ . $q_lname . ‘</strong> – ‘;
}

# Parse the question text.
$old = array(“\n”);
$new   = array(“<br/>”);
$q_question = str_replace($old, $new, $q_question);

# Output the question.
$cp_output = $cp_output . ‘
<div>’ . $q_id . ‘</div>
<div>
<div><strong>’ . $q_topic . ‘</strong></div>
<div>’ . $q_question . ‘</div>
<div><strong>Submitted</strong> ‘ . $q_date . ‘ by ‘ . $from . ‘<a href=”mailto:’ . $q_email . ‘”>’ . $q_email . ‘</a></div>
</div>
<div></div>
‘;
}

clean & simple check your $_SERVER var

Friday, August 6th, 2010

<?

echo “<pre>”;
print_r($_SERVER);

?>

WordPress PHP custom theme functions.php hook

Wednesday, July 28th, 2010

In your theme (wp-content/themes/YourNewTheme) create or find functions.php

and start making whatever you need.  It’s a nice clean place to put things without hacking away at your code,

dynamically inserting with JS, or whatever other measure you’ve either employed in the past, or are considering now…

for example,

<?php
//My own footer hook
function my_footer() {

//code to execute

?><div class=”bigText”>blah blah blah</div><?

}

?>

then, wherever you like, call your new function, example, replace all <? wp_footer(); ?> calls with, you guested it, <? my_footer(); ?>

thanks to: http://www.raymondselda.com/understanding-action-hooks-in-wordpress/

Don’t forget to include the following in your new custom theme functions.php file if you want the dynamic custom drag widget sidebar!:

if ( function_exists(‘register_sidebar’) )
register_sidebar();

reference: http://codex.wordpress.org/Widgetizing_Themes

Reference variables PHP examples: &$var simple, pass by reference to function, array of reference variables

Tuesday, July 27th, 2010

& preceeds variable

$original = “foo”;
$ref = &$original;
echo $ref; \\Prints “foo”
// now we change the value of $original
$original = “bar”;
// and then print the value of the referring variable
echo $ref; \\Now prints the new value: “bar”
source: http://www.whypad.com/posts/php-what-is-the-ampersand-preceding-variables/193/

reference variable (&variable)

<?php
function add_some_extra(&$string)
{
$string .= 'and something extra.';
}
$str = 'This is a string, ';
add_some_extra($str);
echo $str;    // outputs 'This is a string, and something extra.'
?>

Basically, the argument is treated, referenced by the outside variable, as global
Without the &, it would output ‘This is a string’
source: http://php.net/manual/en/functions.arguments.php

 

An Array of Reference Variables:

// We have a bunch of variables
$var1 = 10;
$var2 = 100;
$var3 = 1000;
// Let’s put references to them all into an array. That way we can loop through them all, and edit one or all of them
$array = array(&$var1, &$var2, &$var3);
foreach($array as &$var){

if($var == 1000){

$var = 2000;

}

}
echo $var1 . “<br />”; // 10
echo $var2 . “<br />”; // 100
echo $var3 . “<br />”; // 2000

Postincrement Preincrement Postdecrement Predecrement PHP careful! ++ —

Tuesday, July 27th, 2010
<?php
echo "<h3>Postincrement</h3>";
$a = 5;
echo "Should be 5: " . $a++ . "<br />\n";
echo "Should be 6: " . $a . "<br />\n";

echo "<h3>Preincrement</h3>";
$a = 5;
echo "Should be 6: " . ++$a . "<br />\n";
echo "Should be 6: " . $a . "<br />\n";

echo "<h3>Postdecrement</h3>";
$a = 5;
echo "Should be 5: " . $a-- . "<br />\n";
echo "Should be 4: " . $a . "<br />\n";

echo "<h3>Predecrement</h3>";
$a = 5;
echo "Should be 4: " . --$a . "<br />\n";
echo "Should be 4: " . $a . "<br />\n";
?>

PHP Expat XML Parser refresher

Tuesday, July 27th, 2010

from: http://w3schools.com/php/php_xml_parser_expat.asp

example XML

<?xml version=”1.0″ encoding=”ISO-8859-1″?>
<note>
<to>Tove</to>
<from>Jani</from>
<heading>Reminder</heading>
<body>Don’t forget me this weekend!</body>
</note>

script to parse:

<?php
//Initialize the XML parser
$parser=xml_parser_create();

//Function to use at the start of an element
function start($parser,$element_name,$element_attrs)
{
switch($element_name)
{
case “NOTE”:
echo “– Note –<br />”;
break;
case “TO”:
echo “To: “;
break;
case “FROM”:
echo “From: “;
break;
case “HEADING”:
echo “Heading: “;
break;
case “BODY”:
echo “Message: “;
}
}

//Function to use at the end of an element
function stop($parser,$element_name)
{
echo “<br />”;
}

//Function to use when finding character data
function char($parser,$data)
{
echo $data;
}

//Specify element handler
xml_set_element_handler($parser,”start”,”stop”);

//Specify data handler
xml_set_character_data_handler($parser,”char”);

//Open XML file
$fp=fopen(“test.xml”,”r”);

//Read data
while ($data=fread($fp,4096))
{
xml_parse($parser,$data,feof($fp)) or
die (sprintf(“XML Error: %s at line %d”,
xml_error_string(xml_get_error_code($parser)),
xml_get_current_line_number($parser)));
}

//Free the XML parser
xml_parser_free($parser);
?>

output:

— Note —
To: Tove
From: Jani
Heading: Reminder
Message: Don’t forget me this weekend!

PHP custom error handling, log and email and user messaging

Tuesday, July 27th, 2010

http://w3schools.com/php/php_error.asp

<?php
//error handler function
function customError($errno, $errstr)
{
echo “<b>Error:</b> [$errno] $errstr<br />”;
echo “Webmaster has been notified”;
error_log(“Error: [$errno] $errstr”,1,
“someone@example.com”,”From: webmaster@example.com”);
}

//set error handler
set_error_handler(“customError”,E_USER_WARNING);

//trigger error
$test=2;
if ($test>1)
{
trigger_error(“Value must be 1 or below”,E_USER_WARNING);
}
?>

open a file and read it line by line or character by character reference refresher

Tuesday, July 27th, 2010

from http://w3schools.com/php/php_file.asp

Reading a File Line by Line

The fgets() function is used to read a single line from a file.

Note: After a call to this function the file pointer has moved to the next line.

Example

The example below reads a file line by line, until the end of file is reached:

<?php
$file = fopen(“welcome.txt”, “r”) or exit(“Unable to open file!”);
//Output a line of the file until the end is reached
while(!feof($file))
{
echo fgets($file). “<br />”;
}
fclose($file);
?>

Reading a File Character by Character

The fgetc() function is used to read a single character from a file.

Note: After a call to this function the file pointer moves to the next character.

Example

The example below reads a file character by character, until the end of file is reached:

<?php
$file=fopen(“welcome.txt”,”r”) or exit(“Unable to open file!”);
while (!feof($file))
{
echo fgetc($file);
}
fclose($file);
?>

date() and timestamp refresher

Tuesday, July 27th, 2010

date(format,timestamp)

format is required, example:

date(“Y-m-d”)

of course, Y, m, and d stand for Year, month, day, and they may be separated by whatever you like, so the above example returns 2010-07-27, while date(“m/d/Y”) returns 07/27/2010

now for the timestamp parameter

MAKE what should be supplied for the timestamp, with mktime(hour,minute,second,month,day,year,is_dst)

$tomorrow = mktime(0,0,0,date(“m”),date(“d”)+1,date(“Y”))

date(“Y/m/d”,$tomorrow) returns tomorrow!

I never seem to use the “do…while” loop so here it is just to remind me…

Tuesday, July 27th, 2010

example from :

http://w3schools.com/php/php_looping.asp

<?php
$i=1;
do
{
$i++;
echo “The number is ” . $i . “<br />”;
}
while ($i<=5);
?>

Key difference, it ALWAYS executes once, and THEN evaluates

PHP variable variables $$

Tuesday, July 27th, 2010

“variable variables create variables with variable names”

$Bar = "a";
$Foo = "Bar";
$World = "Foo";
$Hello = "World";
$a = "Hello";

$a; //Returns Hello
$$a; //Returns World
$$$a; //Returns Foo
$$$$a; //Returns Bar
$$$$$a; //Returns a

$$$$$$a; //Returns Hello
$$$$$$$a; //Returns World

//… and so on …//

From:

http://www.php.net/manual/en/language.variables.variable.php

 

Simpler example:

$var = “oldVarName”;
$$var = “newVarName”;

echo $var; //Returns oldVarName
// create a new var with the value of var as it’s var name
echo $oldVarName; //Returns newVarName

 

Handy in Queries idea example:

$fields = array(“AccessLevels”, “AnswerType”,”Language”, “StatusWithType.Status”, “Categories”, “Products”); // ex. result returned categories RQL from RNT

foreach($fields as $key => $field){

$$field = array(1,2,3,4,5,6); // creates $AccessLevels[], $Language[], $StatusWithType.Status[], etc…

}

print_r($AccessLevels); // more useful, do a subsequent query foreach value now in this array, or a query to fill it, and so on…

using a PHP variable in a MySQL IN batch query example

Friday, July 16th, 2010

Note the ‘s

$product_list = “‘1869’, ‘1929’, ‘549’, ‘189’, ‘419’, ‘176’, ‘192’, ‘310’, ‘291’, ‘514’, ‘1643’, ‘1033’;

$db_name = “dbName”;
//conditional platform logic to support multiple connection scenarios

switch($_SERVER[‘HTTP_HOST’])
{
case ‘localhost’:
$db_host = “localhost”;
$db_username = “userName”;
$db_password = “Password”;
$dblink = mysql_connect ($db_host, $db_username, $db_password);
mysql_select_db($db_name, $dblink);
break;
case ‘www-staging.site.com’: break;
case ‘www.site.com’:
include(‘/var/www/includes/connection_script.php’);
break;
}

$result = mysql_query(”
SELECT
product_id,
product_name
FROM
tableNameHere
WHERE
product_id IN
(“.$product_list.“)
“);
if (!$result) { echo “Could not successfully run query ($sql) from DB: . mysql_error(); exit; }


//let’s break out the resource so that it can be singularly requested when needed

while($one = mysql_fetch_assoc($result))
{
$prod_id = $one[‘product_id‘];
$product_name[$prod_id] = $one[‘product_name‘];
}
@
mysql_close($dblink);

PHP sprintf() quick example

Thursday, July 1st, 2010

$template = ‘<div class=”%designIt”><img src=”%s” /><br />%s<br />by %s</div>’;
$designIt = “className”;
$imgSrc = “http://www.imageLivesHere.com/yo.jpg”;
$copyText = “What fabulous and interesting placeholder copy!”;
$sourceAuthor = “Me”;
$altogetherNow = sprintf ( $template, $imgSrc, $linkText, $sourceAuthor);

//Result

<div class=”className“>
<img src=”http://www.imageLivesHere.com/yo.jpg“/>
<br />
What fabulous and interesting placeholder copy!
<br />
by Me
</div>

PHP multiple equal case switch syntax

Tuesday, May 4th, 2010

switch($holder)
{
case “”:
case “http://www.cuealex.com/digitalcatalog”:
case “http://www.iealex.com/digitalcatalog/”:
echo “<script>alert(‘http referer: none’);</script>”;
if(isset($_SESSION[‘enews_refer_value’]))
{
echo “<script>alert(‘but enews_refer_value WAS set, so it stays’);</script>”;
$enews_refer_value = $_SESSION[‘enews_refer_value’];
}
else { $enews_refer_value = “”; }
break;
default:
echo “<script>alert(‘set enews_refer_value session to http_referer’);</script>”;
$_SESSION[‘enews_refer_value’] = $_SERVER[‘HTTP_REFERER’];
$enews_refer_value = $_SESSION[‘enews_refer_value’];
break;
}

IE7 php force download FIX

Friday, April 30th, 2010

Normally, as an  accomplished programmer, you use all the headers, follow the guidelines, include what you should…

but, when Microsoft won’t play by the rules, you have to fudge…

IE7 rejects forced downloads (in this example I was using doing PDF, mp3, zip, and m4b files).

It opens the download dialog, chooses a location, and then commences to quit having downloaded 0 bits.

So, instead of the dutiful example elsewhere in this blog that chooses the correct content-type, length, transer encoding and so on…

We just do this, seems to work, forces it somehow, sorry, I’ve no further explanation…:

<?

$filename = $_GET[‘file’];
// required for IE, otherwise Content-disposition is ignored
if(ini_get(‘zlib.output_compression’))
ini_set(‘zlib.output_compression’, ‘Off’);

$file_extension = strtolower(substr(strrchr($filename,”.”),1));
if( $filename == “” )
{
echo “<html><title></title><body>ERROR: download file NOT SPECIFIED.</body></html>”;
exit;
}

header(“Cache-Control: maxage=1”);
header(“Content-Type: application/force-download”);
header(“Content-disposition: attachment; filename=\””. $filename .”\”;” );
@readfile(“$filename”) or die(“File not found.”);
exit();

?>

PHP htaccess file serve script

Friday, April 30th, 2010

search this blog for the “htaccess” file contents to put in a directory, then use this to serve up pdf files securely from said directory:

file serve php script:

first check Zend permissions…logged in, permissions granted, user active, expirations, etc…..
then:

<?
$file = “path/path/” . $_GET[‘file’];
//$file = “Broker_Admin/Materials/Course.pdf”;
header(‘Content-type: application/pdf’);
header(“Content-Disposition: inline; filename=”.$file);
/*header(“Content-Disposition: attachment; filename=”.$file);*/
header(‘Last-Modified: ‘.gmdate(‘D, d M Y H:i:s’) . ‘ GMT’);
header(‘Cache-Control: no-store, no-cache, must-revalidate’);
header(‘Cache-Control: pre-check=0, post-check=0, max-age=0’);
header(‘Pragma: anytextexeptno-cache’, true);
header(‘Cache-control: private’);
header(‘Expires: 0’);
readfile($file);
?>

then from wherever I want to call it I call this script and pass in the file wanted.

like this:

<a href=”file_serve.php?file=Test.pdf”>Download the Test file here</a>

File is NOT accessible directly, or via this script since it first checks visitor’s SESSIONS, ZEND Permissions, that variables passed to it are set, etc. and so on…

jQuery bind select change to anchor window.open variable

Thursday, April 29th, 2010

add window.open() to an anchor tag…

HTML:

select dropdown changes the source:

<div class=”name”>
<select name=”tpom” style=”float: left; width: 100px; margin-right:20px; border: 1px solid #5A3C18;” >
<option value=”downloader.php?file=folder/file.mp3″>Mp3</option>
<option value=”downloader.php?file=folder/file.zip”>Zip</option>
<option value=”downloader.php?file=folder/file.m4b”>Ipod</option>
</select>

link or button gets source from dropdown via jQuery onReady function:

$(“div.name select”).bind(“change”,function(){
$(‘#button_download’).attr(‘href’,this.value);
windowUrl = $(this).val();
//console.log(windowUrl);
});

<a onclick=”window.open(windowUrl,’download’);return false;” id=”button_download”>Download</a>

fancy complex php force file download script

Thursday, April 29th, 2010

set_time_limit(0);
$file_path=’blah.pptx’;
output_file($file_path, ‘blah.pptx’, ”);

function dl_file($file){

$file = ‘blah.pptx’;
$filename = realpath($file);
$file_extension = strtolower(substr(strrchr($filename,”.”),1));

if (!file_exists($filename)) { die(“NO FILE HERE”); }
$ctype=”application/vnd.ms-powerpoint”;
header(“Pragma: public”);
header(“Expires: 0”);
header(“Cache-Control: must-revalidate, post-check=0, pre-check=0”);
header(“Cache-Control: private”, false);
header(“Content-Type: $ctype”);
header(“Content-Disposition: attachment; filename=\”$filename\””);
header(“Content-Transfer-Encoding: binary”);
header(“Content-Length: “.@filesize($filename));
set_time_limit(0);
@readfile($file);
exit;
}

function output_file($file, $name, $mime_type=”)
{

if(!is_readable($file)) die(‘File not found or inaccessible!’);

$size = filesize($file);
$name = rawurldecode($name);

/* Figure out the MIME type (if not specified) */
$known_mime_types=array(
“pdf” => “application/pdf”,
“txt” => “text/plain”,
“html” => “text/html”,
“htm” => “text/html”,
“exe” => “application/octet-stream”,
“zip” => “application/zip”,
“doc” => “application/msword”,
“xls” => “application/vnd.ms-excel”,
“ppt” => “application/vnd.ms-powerpoint”,
“gif” => “image/gif”,
“png” => “image/png”,
“jpeg”=> “image/jpg”,
“jpg” =>  “image/jpg”,
“php” => “text/plain”
);

if($mime_type==”){
$file_extension = strtolower(substr(strrchr($file,”.”),1));
if(array_key_exists($file_extension, $known_mime_types)){
$mime_type=$known_mime_types[$file_extension];
} else {
$mime_type=”application/force-download”;
};
};

@ob_end_clean(); //turn off output buffering to decrease cpu usage

// required for IE, otherwise Content-Disposition may be ignored
if(ini_get(‘zlib.output_compression’))
ini_set(‘zlib.output_compression’, ‘Off’);

header(‘Content-Type: ‘ . $mime_type);
header(‘Content-Disposition: attachment; filename=”‘.$name.'”‘);
header(“Content-Transfer-Encoding: binary”);
header(‘Accept-Ranges: bytes’);

/* The three lines below basically make the
download non-cacheable */
header(“Cache-control: private”);
header(‘Pragma: private’);
header(“Expires: Mon, 26 Jul 1997 05:00:00 GMT”);

// multipart-download and download resuming support
if(isset($_SERVER[‘HTTP_RANGE’]))
{
list($a, $range) = explode(“=”,$_SERVER[‘HTTP_RANGE’],2);
list($range) = explode(“,”,$range,2);
list($range, $range_end) = explode(“-“, $range);
$range=intval($range);
if(!$range_end) {
$range_end=$size-1;
} else {
$range_end=intval($range_end);
}

$new_length = $range_end-$range+1;
header(“HTTP/1.1 206 Partial Content”);
header(“Content-Length: $new_length”);
header(“Content-Range: bytes $range-$range_end/$size”);
} else {
$new_length=$size;
header(“Content-Length: “.$size);
}

/* output the file itself */
$chunksize = 1*(1024*1024); //you may want to change this
$bytes_send = 0;
if ($file = fopen($file, ‘r’))
{
if(isset($_SERVER[‘HTTP_RANGE’]))
fseek($file, $range);

while(!feof($file) &&
(!connection_aborted()) &&
($bytes_send<$new_length)
)
{
$buffer = fread($file, $chunksize);
print($buffer); //echo($buffer); // is also possible
flush();
$bytes_send += strlen($buffer);
}
fclose($file);
} else die(‘Error – can not open file.’);

die();
}

basic php force file download script

Thursday, April 29th, 2010

<?php
$filename = $_GET[‘file’];
// required for IE, otherwise Content-disposition is ignored
if(ini_get(‘zlib.output_compression’))
ini_set(‘zlib.output_compression’, ‘Off’);

$file_extension = strtolower(substr(strrchr($filename,”.”),1));
if( $filename == “” )
{
echo “<html><title></title><body>ERROR: download file NOT SPECIFIED.</body></html>”;
exit;
}
switch( $file_extension )
{
case “pdf”: $ctype=”application/pdf”; break;
case “txt”: $ctype=”text/plain”; break;
case “html”: $ctype=”text/html”; break;
case “htm”: $ctype=”text/html”; break;
case “exe”: $ctype=”application/octet-stream”; break;
case “zip”: $ctype=”application/zip”; break;
case “doc”: $ctype=”application/msword”; break;
case “xls”: $ctype=”application/vnd.ms-excel”; break;
case “ppt”: $ctype=”application/vnd.ms-powerpoint”; break;
case “gif”: $ctype=”image/gif”; break;
case “png”: $ctype=”image/png”; break;
case “jpeg”: $ctype=”image/jpg”; break;
case “jpg”: $ctype=”image/jpg”; break;
case “php”: $ctype=”text/plain”; break;
default: $ctype=”application/force-download”;
}
header(“Pragma: public”); // required
header(“Expires: 0”);
header(“Cache-Control: must-revalidate, post-check=0, pre-check=0”);
header(“Cache-Control: private”,false); // required for certain browsers
header(“Content-Type: $ctype”);
header(“Content-Disposition: attachment; filename=\””.basename($filename).”\”;” );
header(“Content-Transfer-Encoding: binary”);
header(“Content-Length: “.filesize($filename));
set_time_limit(0);
@readfile(“$filename”) or die(“File not found.”);
exit();
?>

Platform Environments Config for PHP applications example $_SERVER[‘HTTP_HOST’]

Wednesday, April 21st, 2010

You have to look at all of your different server returned variables for each platform,

and simply find one that you may reference and set per platform via script similar to:

// PLATFORM CONFIG


if($_SERVER[‘HTTP_HOST’] == ‘localhost’)
{
define(‘HOME’,’http://localhost/url.com/’);
define(‘PLATFORM_DB’,’localhost’);
}
elseif($_SERVER[‘HTTP_HOST’] == ‘www-staging.url.com’)
{
define(‘HOME’,’http://www-staging.soundstrue.com/’);
define(‘PLATFORM_DB’,’mktgdb.url.com’);
}
elseif($_SERVER[‘HTTP_HOST’] == ‘www.url.com’);
{
define(‘HOME’,’http://www.url.com/’);
define(‘PLATFORM_DB’,’mktgdb.url.com’);
}

Then simply access the variable when needed:

header(“Location:” . HOME . “event/forums/site/index.php/”);

$boarddir = HOME . “event/forums/dangerous/index.php/board,1.0.html”;

This way you can develop on your local machine, promote your app to staging, where it will still work, and finally to production, all without re-coding those pesky app variables.