10 useful PHP PEAR packages

MDB2

PEAR MDB2 is a merge of the PEAR DB and Metabase php database abstraction layers.

It provides a common API for all supported RDBMS. The main difference to most
other DB abstraction packages is that MDB2 goes much further to ensure
portability. MDB2 provides most of its many features optionally that
can be used to construct portable SQL statements:

  • Object-Oriented API
  • A DSN (data source name) or array format for specifying database servers
  • Datatype abstraction and on demand datatype conversion
  • Various optional fetch modes to fix portability issues
  • Portable error codes
  • Sequential and non sequential row fetching as well as bulk fetching
  • Ability to make buffered and unbuffered queries
  • Ordered array and associative array for the fetched rows
  • Prepare/execute (bind) named and unnamed placeholder emulation
  • Sequence/autoincrement emulation
  • Replace emulation
  • Limited sub select emulation
  • Row limit emulation
  • Transactions/savepoint support
  • Large Object support
  • Index/Unique Key/Primary Key support
  • Pattern matching abstraction
  • Module framework to load advanced functionality on demand
  • Ability to read the information schema
  • RDBMS management methods (creating, dropping, altering)
  • Reverse engineering schemas from an existing database
  • SQL function call abstraction
  • Full integration into the PEAR Framework
  • PHPDoc API documentation

MDB2 – InstallationWiki
How to use PHP and PEAR MDB2

Text_CAPTCHA

Implementation of CAPTCHAs (Completely Automated Public Turing tests to tell Computers and Humans Apart).
Using PEAR’s Text_CAPTCHA to Secure Web Forms

Log

The Log package provides an abstracted logging framework. It includes output handlers for log files, databases, syslog, email, Firebug, and the console. It also provides composite and subject-observer logging mechanisms.
The Log Package
PHPBuilder
Debugging PHP With Firebug
Advanced Logging in PHP with PEAR

LiveUser

LiveUser is a set of classes for dealing with user authentication
and permission management. Basically, there are three main elements that make up this package:

  • The LiveUser class
  • The Auth containers
  • The Perm containers

The LiveUser class takes care of the login process and can be configured to use a certain permission container and one or more different auth containers.
That means, you can have your users’ data scattered amongst many data containers and have the LiveUser class try each defined container until the user is found.
For example, you can have all website users who can apply for a new account online on the webserver’s local database. Also, you want to enable all your company’s employees to login to the site without the need to create new accounts for all of them. To achieve that, a second container can be defined to be used by the LiveUser class.

You can also define a permission container of your choice that will manage the rights for each user. Depending on the container, you can implement any kind of permission schemes for your application while having one consistent API.
Using different permission and auth containers, it’s easily possible to integrate newly written applications with older ones that have their own ways of storing permissions and user data. Just make a new container type and you’re ready to go!

PEAR::LiveUser Wiki
Getting Started with LiveUser Permissions
Authentication
PHP Authentication and Access Control Libraries

Translation2

This class provides an easy way to retrieve all the strings for a multilingual site from a data source (i.e. db).
The following containers are provided, more will follow:

  • PEAR::DB
  • PEAR::MDB
  • PEAR::MDB2
  • gettext
  • XML
  • PEAR::DB_DataObject (experimental)

It is designed to reduce the number of queries to the db, caching the results when possible.
An Admin class is provided to easily manage translations (add/remove a language, add/remove a string).
Currently, the following decorators are provided:

  • CacheLiteFunction (for file-based caching)
  • CacheMemory (for memory-based caching)
  • DefaultText (to replace empty strings with their keys)
  • ErrorText (to replace empty strings with a custom error text)
  • Iconv (to switch from/to different encodings)
  • Lang (resort to fallback languages for empty strings)
  • SpecialChars (replace html entities with their hex codes)
  • UTF-8 (to convert UTF-8 strings to ISO-8859-1)

PEAR::Translation2 tutorials

Validate

Package to validate various data. It includes :

  • numbers (min/max, decimal or not)
  • email (syntax, domain check, rfc822)
  • string (predefined type alpha upper and/or lowercase, numeric,…)
  • date (min, max, rfc822 compliant)
  • uri (RFC2396)
  • possibility valid multiple data with a single method call (::multiple)

An introduction to PEAR’s Validate package

Spreadsheet_Excel_Writer

Spreadsheet_Excel_Writer was born as a porting of the Spreadsheet::WriteExcel Perl module to PHP.
It allows writing of Excel spreadsheets without the need for COM objects.
It supports formulas, images (BMP) and all kinds of formatting for text and cells.
It currently supports the BIFF5 format (Excel 5.0), so functionality appeared in the latest Excel versions is not yet available.
Generating Spreadsheets with PHP and PEAR
What is Spreadsheet_Excel_Writer?

Net_GeoIP

A library that uses Maxmind’s GeoIP databases to accurately determine geographic location of an IP address.
Tutorial from HTML Blog

File_Archive

This library makes it very easy to use, writing simple code, yet the library is very powerful.
It lets you easily read or generate tar, gz, tgz, bz2, tbz, zip, ar (or deb) archives to files, memory, mail or standard output.
File_Archive tutorial
SitePoint » File_Archive

XML_Serializer

XML_Serializer serializes complex data structures like arrays or object as XML documents.
This class helps you generating any XML document you require without the need for DOM.
Furthermore this package can be used as a replacement to serialize() and unserialize() as it comes with a matching

XML_Unserializer that is able to create PHP data structures (like arrays and objects) from XML documents, if type hints are available.
If you use the XML_Unserializer on standard XML files, it will try to guess how it has to be unserialized. In most cases it does exactly what you expect it to do.

Dev Shed XML_Serializer
Instant XML with PHP and PEAR::XML_Serializer

8 practical tips to make your web pages faster

faster web pages

Yahoo’s Exceptional Performance team has compiled a list of 34 best practices to have faster web pages. In this post I’ll show you 8 tips which helped me to get a B grade in YSlow! for web pages that I develop. Currently YSlow’s web page analysis is based on 13 identified basic rules that affect web page performance. In decreasing order of priority they are:

  1. Make Fewer HTTP Requests
  2. Use a Content Delivery Network
  3. Add an Expires Header
  4. Gzip Components
  5. Put CSS at the Top
  6. Move Scripts to the Bottom
  7. Avoid CSS Expressions
  8. Make JavaScript and CSS External
  9. Reduce DNS Lookups
  10. Minify JavaScript
  11. Avoid Redirects
  12. Remove Duplicate Scripts
  13. Configure ETags

You can get more info by clicking on each item. Of course using a CDN is not affordable by everybody, including me. This didn’t prevent me to have a B grade though. I will guide you through some of the items which worked for me.


Make Fewer HTTP Requests
If you’re using the YUI library, the good news is that recently the team graciously offered a Combo Handler Service, served from their CDN. This helps us to eliminate HTTP requests by requesting a single file. For example, to use the Rich Text editor, it needed 6 separate HTTP requests:

 
 
 

 

Now with the Combo Handler service, it has been stripped to only 1 file:


If you’re not using the YUI library or not interested in using the Combo Handler service, you can try Minify!
Minify is a PHP5 app that can combine multiple CSS or Javascript files, compress their contents (i.e. removal of unnecessary whitespace/comments), and serve the results with HTTP encoding (gzip/deflate) and headers that allow optimal client-side caching.

Another tool which can be helpful is Dojo Shrinksafe which not only minifies your javascript code but also allows you to upload several javascript files and have them compressed in 1 single file.

Another way to make fewer HTTP requests is by using CSS sprites which are big images containing lots of smaller ones. An online tool which can make CSS sprites out of your smaller ones is the CSS Sprite Generator. You just have to upload your pics and it will generate your sprite together with the CSS code. More info about CSS sprites can be found on CSS Tricks.


Add an Expires Header
For this to work on Apache, you’ll need to have mod_expires enabled. Then create an .htaccess file or edit your httpd.conf with the following content:

ExpiresActive On
ExpiresByType image/jpg "access plus 2 years"
ExpiresByType image/jpeg "access plus 2 years"
ExpiresByType image/gif "access plus 2 years"
ExpiresByType application/javascript "access plus 2 years"
ExpiresByTYpe text/css "access plus 2 years"

In the above listing, all images(jpg/jpeg/gif) will have an expires header 2 years in the future.


Gzip Components
You must have mod_deflate enabled and drop these lines in your httpd.conf file

SetOutputFilter DEFLATE
SetEnvIfNoCase Request_URI \.(?:gif|jpe?g|png)$ no-gzip dont-vary
SetEnvIfNoCase Request_URI \.(?:exe|t?gz|zip|bz2|sit|rar)$ no-gzip dont-vary
SetEnvIfNoCase Request_URI \.pdf$ no-gzip dont-vary

Put CSS at the Top
All CSS must be between your head tag, like that :

	
		
			
		
		
		
		
	

Move Scripts to the Bottom
While the CSS are sitting at the top of your page, javascripts must be moved towards the lower part of your page, typically in the body tag. I usually put them before the closing body tag.

	
		
		
		
		...
		...
		
		
	

Reduce DNS Lookups
I don’t usually have more than 2 DNS lookups in my scripts, else YSlow will be removing some points.


Minify JavaScript
As I mentioned earlier on, Dojo Shrinksafe is an online tool which minifies your code.

Another great command line tool is Julien Lecomte YUI Compressor.

In order to use it you must have Java installed (>= 1.4).

Douglas Crockford also has something similar in JSMin


Configure ETags
Just drop this line in your httpd.conf:

FileETag None

😉

10 code snippets for PHP developers

I’ve compiled a small list of some useful code snippets which might help you when writing your PHP scripts…

Email address check

Checks for a valid email address using the php-email-address-validationclass.
Source and docs: http://code.google.com/p/php-email-address-validation/

include('EmailAddressValidator.php');
	
$validator = new EmailAddressValidator;
if ($validator->check_email_address('[email protected]')) { 
    // Email address is technically valid 
} 
else {
    // Email not valid
}

Random password generator

PHP password generator is a complete, working random password generation function for PHP. It allows the developer to customize the password: set its length and strength. Just include this function anywhere in your code and then use it.
Source : http://www.webtoolkit.info/php-random-password-generator.html

function generatePassword($length=9, $strength=0) {
    $vowels = 'aeuy';
    $consonants = 'bdghjmnpqrstvz';
    if ($strength & 1) {
        $consonants .= 'BDGHJLMNPQRSTVWXZ';
    }
    if ($strength & 2) {
        $vowels .= "AEUY";
    }
    if ($strength & 4) {
        $consonants .= '23456789';
    }
    if ($strength & 8) {
        $consonants .= '@#$%';
    }

    $password = '';
    $alt = time() % 2;
    for ($i = 0; $i < $length; $i++) {
        if ($alt == 1) {
            $password .= $consonants[(rand() % strlen($consonants))];
            $alt = 0;
        } else {
            $password .= $vowels[(rand() % strlen($vowels))];
            $alt = 1;
        }
    }
    return $password;
}

Get IP address

Returns the real IP address of a visitor, even when connecting via a proxy.
Source : http://roshanbh.com.np/2007/12/getting-real-ip-address-in-php.html

function getRealIpAddr(){
	if (!empty($_SERVER['HTTP_CLIENT_IP'])){
		//check ip from share internet
		$ip = $_SERVER['HTTP_CLIENT_IP'];
	}
	elseif (!empty($_SERVER['HTTP_X_FORWARDED_FOR'])){
		//to check ip is pass from proxy
		$ip = $_SERVER['HTTP_X_FORWARDED_FOR'];
	}
	else{
		$ip = $_SERVER['REMOTE_ADDR'];
	}
	return $ip;
}

XSL transformation

PHP5 version
Source : http://www.tonymarston.net/php-mysql/xsl.html

$xp = new XsltProcessor();

// create a DOM document and load the XSL stylesheet
$xsl = new DomDocument;
$xsl->load('something.xsl');
  
// import the XSL styelsheet into the XSLT process
$xp->importStylesheet($xsl);

// create a DOM document and load the XML datat
$xml_doc = new DomDocument;
$xml_doc->load('something.xml');

// transform the XML into HTML using the XSL file
if ($html = $xp->transformToXML($xml_doc)) {
	echo $html;
}
else {
	trigger_error('XSL transformation failed.', E_USER_ERROR);
} // if 

PHP4 version

function xml2html($xmldata, $xsl){
   /* $xmldata -> your XML */
   /* $xsl -> XSLT file */

   $arguments = array('/_xml' => $xmldata);
   $xsltproc = xslt_create();
   xslt_set_encoding($xsltproc, 'ISO-8859-1');
   $html = xslt_process($xsltproc, $xmldata, $xsl, NULL, $arguments);

   if (empty($html)) {
       die('XSLT processing error: '. xslt_error($xsltproc));
   }
   xslt_free($xsltproc);
   return $html;
}

echo xml2html('myxmml.xml', 'myxsl.xsl');

Force downloading of a file

Forces a user to download a file, for e.g you have an image but you want the user to download it instead of displaying it in his browser.

header("Content-type: application/octet-stream");

// displays progress bar when downloading (credits to Felix ;-))
header("Content-Length: " . filesize('myImage.jpg'));

// file name of download file
header('Content-Disposition: attachment; filename="myImage.jpg"');

// reads the file on the server
readfile('myImage.jpg');

String encoding to prevent harmful code

Web applications face any number of threats; one of them is cross-site scripting and related injection attacks. The Reform library attempts to provide a solid set of functions for encoding output for the most common context targets in web applications (e.g. HTML, XML, JavaScript, etc)
Source : http://phed.org/reform-encoding-library/

include('Reform.php');
Reform::HtmlEncode('a potentially harmful string');

Sending mail

Using PHPMailer
PHPMailer a powerful email transport class with a big features and small footprint that is simple to use and integrate into your own software.
Source : http://phpmailer.codeworxtech.com/

include("class.phpmailer.php");  
$mail = new PHPMailer();  
$mail->From = '[email protected]';  
$mail->FromName = 'HTML Blog';  
$mail->Host = 'smtp.site.com';  
$mail->Mailer = 'smtp'; 
$mail->Subject = 'My Subject';
$mail->IsHTML(true);
$body = 'Hello<br/>How are you ?';
$textBody = 'Hello, how are you ?';
$mail->Body = $body;  
$mail->AltBody = $textBody;  
$mail->AddAddress('asvin [@] gmail.com');
if(!$mail->Send())  
	echo 'There has been a mail error !';

Using Swift Mailer
Swift Mailer is an alternative to PHPMailer and is a fully OOP library for sending e-mails from PHP websites and applications.
Source : http://swiftmailer.org/

// include classes
require_once "lib/Swift.php";
require_once "lib/Swift/Connection/SMTP.php";
 
$swift =& new Swift(new Swift_Connection_SMTP("smtp.site.com", 25));
$message =& new Swift_Message("My Subject", "Hello<br/>How are you ?", "text/html");
if ($swift->send($message, "asvin [@] gmail.com", "[email protected]")){
    echo "Message sent";
}
else{
    echo 'There has been a mail error !';
}
 
//It's polite to do this when you're finished
$swift->disconnect();

Uploading of files

Using class.upload.php from Colin Verot
Source : http://www.verot.net/php_class_upload.htm

$uploadedImage = new Upload($_FILES['uploadImage']);
	
if ($uploadedImage->uploaded) {
	$uploadedImage->Process('myuploads');
	if ($uploadedImage->processed) {
		echo 'file has been uploaded';
	}
}

List files in directory

List all files in a directory and return an array.
Source : http://www.laughing-buddha.net/jon/php/dirlist/

function dirList ($directory) {
    // create an array to hold directory list
    $results = array();

    // create a handler for the directory
    $handler = opendir($directory);

    // keep going until all files in directory have been read
    while ($file = readdir($handler)) {

        // if $file isn't this directory or its parent, 
        // add it to the results array
        if ($file != '.' && $file != '..')
            $results[] = $file;
    }

    // tidy up: close the handler
    closedir($handler);

    // done!
    return $results;
}

Querying RDBMS with MDB2 (for e.g MySQL)

PEAR MDB2 provides a common API for all supported RDBMS.

Source : http://pear.php.net/package/MDB2

// include MDB2 class
include('MDB2.php');


// connection info
$db =& MDB2::factory('mysql://username:[email protected]/database');
// set fetch mode
$db->setFetchMode(MDB2_FETCHMODE_ASSOC);

// querying data
$query = 'SELECT id,label FROM myTable';
$result = $db->queryAll($query);

// inserting data
// prepare statement
$statement = $db->prepare('INSERT INTO mytable(id,label) VALUES(?,?)');
// our data
$sqlData = array($id, $label);
// execute
$statement->execute($sqlData);
$statement->free();

// disconnect from db
$db->disconnect();

Pixidou – an Open Source AJAX Image Editor (PHP and YUI based)

Pixidou is a new open source AJAX image editor which will allow you to :

  • adjust brightness
  • adjust contrast
  • cropping
  • flipping
  • negative
  • resizing
  • rotating
  • tint

images.

What you need to get running

  • PHP5.2+ installed on your webserver
  • GD2
  • a web browser

Demo

Installation
Unzip/untar the software in your web directory and that’s all 😉
Also ensure the images folder is writable by your webserver.
Have fun !!!

Download
Get it and follow it at github

All the image manipulation is PHP-based with the help of the great class.upload.php class by Colin Verot which I highly recommend.

The frontend is the most interesting part, where I’ve use the one and only YUI library. Here are the component I used (served from Yahoo CDN) :

  • reset-fonts.css – for all resetting, style information
  • utilities – for all AJAX, animation, drag drop, event handling stuff
  • container – for all panels, dialogs, alerts
  • menu – for the top navigation menu together with the submenus
  • button – provides nice buttons
  • slider – for adjusting contrast and brightness
  • color picker – to choose the color to tint the image
  • resize – to resize the image
  • image cropper – image cropping utility
  • json – to parse all JSON data returned from PHP scripts
  • layout – the general layout
  • tabview – for the about information

I’ve not used the grids.css since it caused some problems while using the color picker.

It’s only the beginning of Pixidou and I’am currently looking for some collaborators. So, if you think you can give a helping hand in any way to Pixidou, don’t hesitate to contact me (asvin.balloo [@] gmail.com), I’ll happily add you as a contributor to the repository on github.

Since it’s an early version, there must be some bugs lying everywhere, don’t hesitate to drop me an email.

AJAX image cropper with YUI and PHP

This post will show you how to build an AJAX crop image tool using the image cropper control from YUI library and PHP.


The ImageCropper Control from the YUI library gives you an interactive interface for getting the dimensions to crop an image and using these dimensions in PHP, we can do some cropping.

The script we are going to build will

  • allow users to upload an image via AJAX
  • then allow them to select an area for cropping
  • lastly, provide a download link for the cropped image.

There are 3 files we are going to use

  • index.php – will contain the form for image upload as well as the cropping interface
  • upload.php – provides uploading functionality
  • crop.php – provides cropping functionality

From a technical point of view, the flow will be like this :

  1. user uploads jpg image (index.php)
  2. index.php then posts the image asynchronously to upload.php which will do the upload on the server, returning JSON data containing the image file name, its width and its height.
  3. with the JSON data and innerHTML we put the image in our page
  4. initialize the javascript cropping tool
  5. generate a download link (crop.php)


Let’s have a look at index.php

The index.php is our main file where users will be able upload images and then download the cropped ones.

We’ll need the following components from the YUI library :

  • yahoo-dom-event.js – for DOM manipulation and Event handling
  • dragdrop – dependency for the image cropper control
  • element – dependency for the image cropper control
  • resize – dependency for the image cropper control
  • connection – for AJAX requests, in our case for image uploads via AJAX
  • json – for parsing JSON data
  • imagecropper – our most important control

Of course we’ll use Yahoo combo handling and add the js to our page along with the CSS needed for the above controls :

<link rel="stylesheet" type="text/css" href="http://yui.yahooapis.com/2.5.2/build/resize/assets/skins/sam/resize.css" />
<link rel="stylesheet" type="text/css" href="http://yui.yahooapis.com/2.5.2/build/imagecropper/assets/skins/sam/imagecropper.css" />
<!-- js -->
<script type="text/javascript" src="http://yui.yahooapis.com/combo?2.5.2/build/yahoo-dom-event/yahoo-dom-event.js&2.5.2/build/dragdrop/dragdrop-min.js&2.5.2/build/element/element-beta-min.js&2.5.2/build/resize/resize-beta-min.js&2.5.2/build/imagecropper/imagecropper-beta-min.js&2.
5.2/build/connection/connection-min.js&2.5.2/build/json/json-min.js"></script>

Next users must be able to upload images via AJAX, so we add a form to our page:

<form action="upload.php" enctype="multipart/form-data" method="post" name="uploadForm" id="uploadForm">
	Image : <input type="file" name="uploadImage" id="uploadImage" />
	<input type="button" id="uploadButton" value="Upload"/>
</form>

We have an onclick event to the upload button to fire the uploading process.

// add listeners
YAHOO.util.Event.on('uploadButton', 'click', uploader.carry);

We’ll also need 2 containers :

  • imageContainer – will contain our uploaded image
  • downloadLink – will contain the download link
<div id="imageContainer"></div>
<div id="downloadLink"></div>

Both containers will be updated via innerHTML afterwards.

AJAX upload

For the AJAX upload, Code Central

has an excellent tutorial which I highly recommend. I took the code sample and modified it a bit to fit my needs. Finally I came up with a nice JSON object called uploader which has one method, carry. The latter just posts form data to a specified URL.

uploader = {
	carry: function(){
		// set form
		YAHOO.util.Connect.setForm('uploadForm', true);
		// upload image
		YAHOO.util.Connect.asyncRequest('POST', 'upload.php', {
			upload: function(o){
				// parse our json data
				var jsonData = YAHOO.lang.JSON.parse(o.responseText);
				
				// put image in our image container
				YAHOO.util.Dom.get('imageContainer').innerHTML = '<img id="yuiImg" src="' + jsonData.image + '" width="' + jsonData.width + '" height="' + jsonData.height + '" alt="" />';
						
				// init our photoshop
				photoshop.init(jsonData.image); 
							
				// get first cropped image
				photoshop.getCroppedImage();
			}
		});
	}
};

When upload is complete, we get the JSON data we mentioned earlier on. For e.g :

{"image" : "images/myimage.jpg", "width" : "500", "height" : 400}

With this data and using innerHTML we update our imageContainer div to put our image which will have yuiImg as id :

YAHOO.util.Dom.get('imageContainer').innerHTML = '<img id="yuiImg" src="' + jsonData.image + '" width="' + jsonData.width + '" height="' + jsonData.height + '" alt="" />';

It’s very important to specify the image width and height else the image cropper won’t work.
Next we initialize another JSON object, photoshop which we’ll have a look now.

Our photoshop object

photoshop = {
	image: null,
	crop: null,
	
	init: function(image){
		// set our image
		photoshop.image = image;
					
		// our image cropper from the uploaded image					
		photoshop.crop = new YAHOO.widget.ImageCropper('yuiImg');
		photoshop.crop.on('moveEvent', function() {
			// get updated coordinates
			photoshop.getCroppedImage();
		});
	},
	
	getCroppedImage: function(){
		var coordinates = photoshop.getCoordinates();
		var url = 'crop.php?image=' + photoshop.image + '&cropStartX=' + coordinates.left +'&cropStartY=' + coordinates.top +'&cropWidth=' + coordinates.width +'&cropHeight=' + coordinates.height;
		YAHOO.util.Dom.get('downloadLink').innerHTML = '<a href="' + url + '">download cropped image</a>';		

	},

	getCoordinates: function(){
		return photoshop.crop.getCropCoords();
	}
};

The init function iniatializes the YUI image cropper from the uploaded image which has yuiImg as id.

photoshop.crop = new YAHOO.widget.ImageCropper('yuiImg');

We also subscribe to the moveEvent for the cropper since we’ll need to update the download link for the cropped image. So whenever the image cropper is moved/resized, we call the getCroppedImage function.

photoshop.crop.on('moveEvent', function() {
	// get updated coordinates
	photoshop.getCroppedImage();
});

The getCroppedImage function will generate the download link for the cropped image. To do image cropping in PHP we’ll need

  • the image we want to crop
  • the X,Y coordinates
  • height and width of the to be cropped area

Fortunately the YUI cropper utility has a function which will give us what we want, it’s the getCropCoords() method. So, whenever the getCroppedImage function is called, we get the coordinates of the cropped area, build a URL and finally put the download link in our downloadLink container.

// get coordinates
var coordinates = photoshop.getCoordinates();

// build our url
var url = 'crop.php?image=' + photoshop.image + '&cropStartX=' + coordinates.left +'&cropStartY=' + coordinates.top +'&cropWidth=' + coordinates.width +'&cropHeight=' + coordinates.height;

// put download link in our page
YAHOO.util.Dom.get('downloadLink').innerHTML = '<a href="' + url + '">download cropped image</a>';

This is all we need for the index page.

upload.php

if(!empty($_FILES["uploadImage"])) {
  	// get file name
	$filename = basename($_FILES['uploadImage']['name']);
		
	// get extension
  	$ext = substr($filename, strrpos($filename, '.') + 1);
  		
  	// check for jpg only
  	if ($ext == "jpg") {
      		// generate unique file name
  		$newName = 'images/'.time().'.'.$ext;
  			
  		// upload files
        	if ((move_uploaded_file($_FILES['uploadImage']['tmp_name'], $newName))) {
			
        		// get height and width for image uploaded
        		list($width, $height) = getimagesize($newName);
        		
        		// return json data
           		echo '{"image" : "'.$newName.'", "height" : "'.$height.'", "width" : "'.$width.'" }';
        	}
        	else {
           		echo '{"error" : "An error occurred while moving the files"}';
        	}
  	} 
  	else {
     		echo '{"error" : "Invalid image format"}';
  	}
}	

The upload.php file too is self explanatory, we check for a jpg image only, then generate an unique filename, put it in the images folder and finally build json data which we’ll use for DOM manipulation. Of course the images folder must be writable by the web server.

crop.php

// get variables
$imgfile = $_GET['image'];
$cropStartX = $_GET['cropStartX'];
$cropStartY = $_GET['cropStartY'];
$cropW = $_GET['cropWidth'];
$cropH = $_GET['cropHeight'];

// Create two images
$origimg = imagecreatefromjpeg($imgfile);
$cropimg = imagecreatetruecolor($cropW,$cropH);

// Get the original size
list($width, $height) = getimagesize($imgfile);

// Crop
imagecopyresized($cropimg, $origimg, 0, 0, $cropStartX, $cropStartY, $width, $height, $width, $height);

// force download nes image
header("Content-type: image/jpeg");
header('Content-Disposition: attachment; filename="'.$imgfile.'"');
imagejpeg($cropimg);

// destroy the images
imagedestroy($cropimg);
imagedestroy($origimg);

Crop.php allows us to crop our uploaded image. First we get all the variables passed to us via the AJAX request,

// get variables
$imgfile = $_GET['image'];
$cropStartX = $_GET['cropStartX'];
$cropStartY = $_GET['cropStartY'];
$cropW = $_GET['cropWidth'];
$cropH = $_GET['cropHeight'];

Then we create 2 images, the original one and the cropped one, and use the imagecopyresized function to generate the cropped image. We add some header information to tell the world it’s an image and prompt for a save dialog.

f-lv.com – download YouTube videos in FLV/MP4/3GP format

After playing with the YouTube API and Python over the past week, I’am pleased to announce the launch of f-lv.com

You will be able to :

  • download your favorite YouTube videos in FLV/MP4 format
  • email the video download link to your friend
  • have a look at a nice carousel (thanks Bill for that) with the latest downloaded videos


Site is built in PHP5 with a tiny bit of Python for generating the link part, powered by the one and only YUI library for all AJAX stuff, dialogs, panels.

Latest update (22 August 2008):
Support for 3GP files has been added. Users can now download 3GP files which are perfect for their mobile phones.

Add RSS feeds to your website

Adding a RSS feed to your website has never been this easy with PHP, especially with MagpieRSS.

About MagpieRSS

MagpieRSS is an RSS and Atom parser for PHP which supports RSS 0.9, RSS 1.0, the various Userland RSS versions (0.9x and 2.0). Additionally it supports Atom 0.3, and many custom RSS namespaces.

Features of MagpieRSS

  • Easy to Use
  • Parses RSS 0.9 – RSS 1.0
  • Integrated Object Cache
  • HTTP Conditional GETs
  • Configurable
  • Modular
  • Secure
  • Bandwidth friendly

Where to get the bird?

Download MagpieRSS from http://sourceforge.net/project/showfiles.php?group_id=55691

Sample basic script

The following script will parse the RSS feed from Slashdot and display the titles.

	include_once('magpierss/rss_fetch.inc');

	$feed = 'http://rss.slashdot.org/Slashdot/slashdot';
	$rss = fetch_rss($feed);

	echo '<ul>';
	foreach ($rss->items as $item ) {
		$title = $item['title'];
		$url = $item['link'];
		echo '<li><a href="'.$url.'">'.$title.'</a></li>';
	}
	echo '</ul>';

First we include the rss_fetch.inc file located in the extracted magpierss folder which will help us in fetching and parsing the feed. Then we define the RSS feed URL and we tell MagpieRSS to fetch the data with the fetch_rss function. After that we just loop through the array of data and echo the output.

Note that MagpieRSS will try to create a directory named “cache” to cache the items for 1 hour to prevent excessive requests to the RSS feed. This directory must be writable by your webserver. If you want to change the cache lifespan, add

define('MAGPIE_CACHE_AGE', 900);

in your script. This will cache the items for 15 minutes (900 seconds). And if you want to change the cache directory add the following line of code :

define('MAGPIE_CACHE_DIR', '/tmp/feedcache');

The cache file will be created with a long random name and saved in the /tmp/feedcache directory

The final code looks like that :

	include_once('magpierss/rss_fetch.inc');
	define('MAGPIE_CACHE_DIR', '/tmp/feedcache');
	define('MAGPIE_CACHE_AGE', 900);		

	$feed = 'http://rss.slashdot.org/Slashdot/slashdot';
	$rss = fetch_rss($feed);

	echo '<ul>';
	foreach ($rss->items as $item ) {
		$title = $item['title'];
		$url = $item['link'];
		echo '<li><a href="'.$url.'">'.$title.'</a></li>';
	}
	echo '</ul>';

Geolocate your visitors with PHP (part 2)

In the first part of this series I showed how you could get the country of a visitor via his IP address. Now with this precious information, I’ll show you how to map the visitor visually on the world map using Google Maps.


You must sign up for a Google Maps API key if you don’t already have one.

After signing up for the key, include the following code in the head of your page :

<script src="http://maps.google.com/maps?file=api&amp;v=2&amp;key=YOURKEY" type="text/javascript"></script>

replacing the YOURKEY by the key you obtained.

We then define a container to hold our map with a width of 630px and height of 350px :

<div id="map" style="width:630px;height:350px;"></div>

Till now the overall code for the page, including the first part, is :

<?php
	require_once("Net/GeoIP.php");
	
	if (isset($HTTP_SERVER_VARS['HTTP_X_FORWARDED_FOR']) && eregi("^[0-9]{1,3}\\.[0-9]{1,3}\\.[0-9]{1,3}\\.[0-9]{1,3}$", 

$HTTP_SERVER_VARS['HTTP_X_FORWARDED_FOR'])){
		$ip = $HTTP_SERVER_VARS['HTTP_X_FORWARDED_FOR'];
	}
	else{
		$ip = getenv("REMOTE_ADDR");
	}
	
	$geoip = Net_GeoIP::getInstance("./data/GeoIP.dat");

	$country = $geoip->lookupCountryName($ip);
?>

<html>
	<head>
		<title>Google maps</title>
		<script src="http://maps.google.com/maps?file=api&amp;v=2&amp;key=YOURKEY" type="text/javascript"></script>	
	</head>
	<body>
		<div id="map" style="width:630px;height:350px;"></div>
	</body>
</html>

Now begins the cool stuff, I’ll show you the complete javascript code and then explain afterwards.

var locator = {    			
	addAddressToMap: function(response) {
		locator.map.clearOverlays();
		if (!response || response.Status.code != 200) {
			//alert("Sorry, we were unable to geocode that address");
		}
		else {
			place = response.Placemark[0];
			point = new GLatLng(place.Point.coordinates[1], place.Point.coordinates[0]);
			marker = new GMarker(point);
			locator.map.addOverlay(marker);
			marker.openInfoWindowHtml(place.address);
		}
	},

	load: function() {
		if (GBrowserIsCompatible()) {
			locator.map = new GMap2(document.getElementById("map"));
        		locator.map.setCenter(new GLatLng(34, 0), 1);
        		locator.geocoder = new GClientGeocoder();
        		locator.geocoder.getLocations("<?php echo $country; ?>", locator.addAddressToMap);
      		}
    	}
}

We have a nice JSON object with 2 functions in it, namely:

  • load
  • addAddressToMap

The load function

The load function will be called upon loading the page, it will initialize our map, and center it.

locator.map = new GMap2(document.getElementById("map"));
locator.map.setCenter(new GLatLng(34, 0), 1);

We then create an instance of the GClientGeoCoder class which will allow us to obtain geocodes for user specified addresses.

With the object created, we then call the getLocations method with 2 parameters. The first one is the country which we got from the php script and the second parameter being the callback function. In this case our callback function is addAddressToMap.

The addAddressToMap function

The addAddressToMap function is called when the geocoder returns an answer, with response as parameter. The response object contains various information such as the address and the coordinates for the country obtained via the getLocations method.

These coordinates can be accessed via

  • response.Placemark[0].Point.coordinates[1] for longitude and
  • response.Placemark[0].Point.coordinates[0] for latitude

To make things a bit short I’ve placed the response.Placemark[0] in a variable called place :

place = response.Placemark[0];

, thus the coordinates can be accessed via :

place.Point.coordinates[1]
place.Point.coordinates[0]

With these 2 coordinates we create a marker which we’ll plot on the map :

point = new GLatLng(place.Point.coordinates[1], place.Point.coordinates[0]);
marker = new GMarker(point);
locator.map.addOverlay(marker);

As a bonus we also have a popup showing the country name using the openInfoWindowHtml method. We simply add the following line :

marker.openInfoWindowHtml(place.address);

our final PHP page looks like that :

<?php
	require_once("Net/GeoIP.php");
	
	if (isset($HTTP_SERVER_VARS['HTTP_X_FORWARDED_FOR']) && eregi("^[0-9]{1,3}\\.[0-9]{1,3}\\.[0-9]{1,3}\\.[0-9]{1,3}$", 

$HTTP_SERVER_VARS['HTTP_X_FORWARDED_FOR'])){
		$ip = $HTTP_SERVER_VARS['HTTP_X_FORWARDED_FOR'];
	}
	else{
		$ip = getenv("REMOTE_ADDR");
	}
	
	$geoip = Net_GeoIP::getInstance("./data/GeoIP.dat");

	$country = $geoip->lookupCountryName($ip);

?>

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="fr" lang="fr">
	<head>
		<meta http-equiv="content-type" content="text/html; charset=utf-8"/>
		<title>my ip address with Google Maps</title>
		<script src="http://maps.google.com/maps?file=api&amp;v=2&amp;key=YOURKEY" type="text/javascript"></script>

		<script type="text/javascript">
    		//<![CDATA[
    		
    		var locator = {    			
    			addAddressToMap: function(response) {
				locator.map.clearOverlays();
				if (!response || response.Status.code != 200) {
					//alert("Sorry, we were unable to geocode that address");
				}
				else {
					place = response.Placemark[0];
					point = new GLatLng(place.Point.coordinates[1], place.Point.coordinates[0]);
					marker = new GMarker(point);
					locator.map.addOverlay(marker);
					marker.openInfoWindowHtml(place.address);
				}
			},

			load: function() {
				if (GBrowserIsCompatible()) {
					locator.map = new GMap2(document.getElementById("map"));
        				locator.map.setCenter(new GLatLng(34, 0), 1);
        				locator.geocoder = new GClientGeocoder();
        				locator.geocoder.getLocations("<?php echo $country; ?>", locator.addAddressToMap);
				}
      			}
    		}
   
    		//]]>
		</script>
	</head>
	<body onload="locator.load();" onunload="GUnload();">
		<div id="map" style="width:630px;height:350px;"></div>
	</body>
</html>

After the page has been loaded, we just call the locator.load() function which will initialize the whole process.

SEO friendly URL in PHP

When I started implementing mod_rewrite in websites I had a problem in PHP as how to make a SEO friendly URL. All tutorials were geared towards how to implement mod_rewrite, about modifying .htaccess files, but none treated how to make the urls friendly with dynamic content. For example I have a news section which are pulled from the database, but how can I make the URL friendly with the title.

For example, my problem was to convert titles like “Barca rejects FIFA statement on Olympics row” into “barca-rejects-fifa-statement-on-olympics-row.html”. The trick has to work also with french titles (I’am sure my friends at Nexen will appreciate ;-)) like “Guantanamo: le chauffeur de Ben Laden plaide non coupable à l’ouverture de son procès” into “guantanamo-le-chauffeur-de-ben-laden-plaide-non-coupable-a-l-ouverture-de-son-proces.html”, removing all french accentuated characters.

Hopefully I came across this function which I think might help you too :

function friendlyURL($string){
	$string = preg_replace("`\[.*\]`U","",$string);
	$string = preg_replace('`&(amp;)?#?[a-z0-9]+;`i','-',$string);
	$string = htmlentities($string, ENT_COMPAT, 'utf-8');
	$string = preg_replace( "`&([a-z])(acute|uml|circ|grave|ring|cedil|slash|tilde|caron|lig|quot|rsquo);`i","\\1", $string );
	$string = preg_replace( array("`[^a-z0-9]`i","`[-]+`") , "-", $string);
	return strtolower(trim($string, '-'));
}

Use :

$myFriendlyURL = friendlyURL("Barca rejects FIFA statement on Olympics row");
echo $myFriendlyURL; // will echo barca-rejects-fifa-statement-on-olympics-row

You just have to concatenate anything you want with the string afterwards. For french users, make sure your string is encoded in UTF-8 else it won’t work.

If you’re using the Smarty templating engine I made a little modifier which you can download. Extract the zip file in your Smarty/libs/plugins/ folder and to use it in your templates :

{"Barca rejects FIFA statement on Olympics row" | friendlyURL}

Or if your string is in a variable :

{$yourString | friendlyURL}

Geolocate your visitors with PHP (part 1)

In this short post, I’ll show you how to geolocate your visitors with PHP. First of all let’s have a look at what you’ll need :

  • PEAR GeoIP
  • MaxMind GeoLite Country

Installing PEAR GeoIP

Using your console or using the command prompt type :

pear install http://download.pear.php.net/package/Net_GeoIP-1.0.0RC1.tgz

Obtaining MaxMind GeoLite Country

The database can be downloaded freely here. Download it and put it in the same folder where your script will reside.

The code

<?php
	require_once('Net/GeoIP.php');

	$geoip = Net_GeoIP::getInstance('./GeoIP.dat');
	$ip = getenv('REMOTE_ADDR');
	$country = $geoip->lookupCountryName($ip);

	echo "Hi, you're from ".$country;
?>

Walkthrough

Now let’s go through the lines of code. The first line tells us to include the GeoIP class, which we installed previously and then create a geoip object in line 5 from the database we downloaded.
Next, in line 6 we get the IP address of the visitor and finally we call the lookupCountryName method with the IP address as parameter in line 7 and it will return us the country.

The last line just outputs the country, for example, “Hi, you’re from Mauritius”. That’s it, now you know where your visitor’s from.

In the second part of this article I’ll show you how to use the script to visually map your visitors using Google Maps. You can have a little preview of the script here.