June 16, 2006

PHP form input and Cross-Site attacks

You will find other articles relevant to this document in these sections:
Cameron Manderson @ 11:51 am

Something that we have to be careful to consider is hackers generating a Form and remotely sending form input to your website. eg.

  1. Hacker creates a form that has the same variables as your website form, and sets the action to your websites form action;
  2. Hacker hits submit to inject in values to your form; such as malicious code or generating a script that automatically inserts data

Although we learn never to trust information sent to us in a form and checking the submitted values to be valid, we will also want to consider the origin of the forms submission [Cross-Site Request Forgeries (CSRF)]. Our Environment variables allow us to check a variable called HTTP-REFERRER but this can be easily changed by the hacker. So instead we will need to consider ways to ensure the form originated from our website (and only issued once).

I have done a little research into ways and Chris Shifflet recommends a token placed into the form and applied to the users session. This method can prove a very useful method of identifying whether a form had been “issued” from your website. His example of a useful way to help limit the occurance of this issue:

<?php
$token = md5(uniqid(rand(), true));
$_SESSION[‘token’] = $token;
$_SESSION[‘token_timestamp’] = time();
?>


<form action=”/add_post.php” method=”post”>
<input type=”hidden” name=”token” value=”<?php echo $token; ?>” />
Subject: <input type=”text” name=”post_subject” />
Message: <textarea name=”post_message”></textarea>
<input type=”submit” value=”Add Post” />
</form>

Chris’s recommendation supplies quite a good method of forcing the use of your own HTML forms, but is linear in nature (one form with one submit). For this to be more rock solid we need to consider implementation issues we always face as Web Developers: Multiple Windows and the Back Button.

We can make some more modifications to the script by including a 2D array of issued form tokens, and individually identify the Form with the corresponding Token:

<?php
$formId = md5(uniqid(rand(), true));
$token = md5(uniqid(rand(), true));

$_SESSION[‘formTokens’][$formId][‘token’] = $token;
$_SESSION[‘formTokens’][$formId][‘token_timestamp’] = time();
?>

<form action=”/add_post.php” method=”post”>
<input type=”hidden” name=”formId” value=”<?php echo $formId; ?>” />
<input type=”hidden” name=”token” value=”<?php echo $token; ?>” />
Subject: <input type=”text” name=”post_subject” />
Message: <textarea name=”post_message”></textarea>
<input type=”submit” value=”Add Post” />
</form>

We now are able to uniquely identify the valid token based on a unique form ID, with its own timeout values etc. This will allow us to cater for multiple windows or use of the back button across our forms.

June 15, 2006

Sharing a session across multiple domains/servers with PHP

You will find other articles relevant to this document in these sections:
Cameron Manderson @ 5:40 pm

Updated 15 June 2007: I have provided the source code to this and a working example of sharing a session across unique domains here.

In-light of a recent project I have had to consider a strategy from diverting a user from an non-SSL server running to a different domain running SSL, and keep the same session. This would involve keeping the user who is signed in on the first server with a session cart selection being somehow shared to the next server. It also requires that the user have a single sign-in between several different domains.

Get your sessions into a database
To consider the sharing of information between different domains where they are potentially run by different users or servers, we would need to place the session information directly into a database that is able to be read in by each domain.

To get your sessions into a database, we could:
- Gain control of the Session with a PHP SessionWrapper using a Singleton
- Overwrite the main _open, _read, _write, _close, _destroy and _gc methods to persist to a common datasource (MySQL database)
- Create a _sessionInit method that checks for a PHPSESSID from the Request, if not checks the Cookie for a PHPSESSID
- Create the session with the ID present (if one)

My database table (session) would form:
- sessionkey varchar(32)
- data text
- expiry timestamp

This will securely conform with ownership issues in PHP Safe Mode as the session data will not be written to disk under each web user, it will be written to a common secure database accessible by other websites (with the correct username/password etc). Once again as you will be now taking over some of the security of a session you could read on ways of encrypting the information stored in the database for further security. You will simply need to add methods of encrypting the information (either with Symetrical or Assymetrical keys) in your _read and _write methods of your Session Wrapper.

* Note: I would recommend that you don’t store sensitive information in your session as by default it will be serialised in clear text to your datastore. Anyone capable accessing your session information will be able to see the details (such as CC details etc).

Updated 21 June 2006: Zend provide a good Code Gallery spotlight that gives a good example of a custom session handler to MySQL Database. You can read their article here.

Sharing the Session ID between sites
When diverting the user to the Secure server they would be parsed over using a URL containing the current PHPSESSID to resume on the next hosting service. If they end up at the website without travelling through a URL with PHPSESSID we can attempt to gain it from the user VIA the cookie (if present this is done automatically by PHP). But how can we ensure the user isn’t starting new sessions?

Centralised Issuing Session ID Server
So we have centralised our Sessions and made them available across multiple domains, but how can we further further ensure that the user holds onto the same Session ID? As there is not always clear sever points between the applications, parsing the Session ID in the URL might not be always as easy to track. Even if we searched through all links and applied the PHPSESSID in the URL - a user may decide to type in a domain directly to switch to the different server.

Unfortunately Cookies can not be shared across different domains (* although they can be across subdomains), so we cannot simply keep track of a session ID via a cookie.

A way to backup remedy to this would be to involve a Session ID issuing server that you can bounce a visitor off when creating an initial visit. The user is returned to the site URL they were requesting but after having a centralised Session ID inserted into their request. Also, if for some reason you wish to not reveal the Session ID in the bounce you could simply place in a retrieve_key that looks up the Session ID once the user is returned to their previous URL. You would also need to assign to the session a unique variable that indicated the session was “issued” and is not created by itself.

Using this central session ID manager as a fall back we could help eliminate those cases when the user shows up at a different domain and starting a new session ID. In some cases you may even be able to eliminate the requirement of parsing PHPSESSID in the URLs.

You will need to consider the security implications of handling sessions this way. If you need to regenerate a session ID it must be done with the Centralised Issuing server otherwise you will either loose the information in your session or start dual sessions that are not shared.

In most cases we will try to use the SSL server as the centralised issuing server and all secure steps can be processed under this URL. We can destoy the session on this server and start a new session. It will automatically cause the other domains to try and retrieve a new key (as long as we assign to the session a unique variable that indicated the session was issued, as when the session can’t be resumed on the other domains, they will realise they have to get a new session ID from the centralised server).

June 8, 2006

Setting up a website in Dreamweaver MX

You will find other articles relevant to this document in these sections:
Richard Lee @ 3:23 pm

Dreamweaver sites are defined in 3 parts;

Local Info is where you define the site name and working directories on your machine.

Remote Info is where your define the web server - where files will be uploaded for testing, production, collaboration, and publication purposes - depending on your setup this might simply be on your machine or your web host.

Testing Server is where Dreamweaver will test dynamic pages i.e. server side scripts. Unless specified otherwise, this is the same as the Remote folder defined above. If however you are developing a large scale web application which involves heavy server requests, and/ or a large number of contributors it is better to setup a web server locally.

Getting started…

1. If you have started a project already, close any open files and move them into one common directory on your local hard drive something like My Docoments/local_sites/my_site

2. Define a site in Dreamweaver: Site > Manage Sites > New. If the Wizard comes up (Basic tab) click the Advanced tab and select the first Category “Local Info” - which should be selected by default anyway.

3. Enter your Site name and choose the my_site folder you created before for the Local root folder. You can also define a Default images folder.

4. Now proceed to the “Remote Info” Category and select your Access option for the web server. If you are uploading to a hosted account choose ‘FTP’. If your web server is local, choose Local/ Network.
5. For FTP access simply enter your FTP details as provided by your web host (note: most FTP requires a Passive connection unless otherwise specified). For Local/Network simply browse and select the Remote folder. Finalise by clicking ‘Test’ to test the connection.
6. Another nice option we will enable is the “Enable file check in and checkout” followed by “Check files when opening”. By enabling this feature you will ensure only 1 user can only work on any given file at a time (once opened), essentially preventing users from overwriting each others work - It also helps you track what your working on too ;)

7. Next proceed to the Testing Server. You may choose to use the same settings as Remote Info. If you are working on a large web application, and prefer to keep the Remote host separate from your testing environment this is your opportunity to set a separate web server. For PHP and MySQL I recommend setting up something like XAMP’s on your machine (See Cams post on XAMP).

8. You have now completed the base setup of your site. OK > Done
Note: There are more options in the setup screen however or the purpose of introduction I have only covered the main necessary section

Working with files…

1. To create a new file make sure you are in Remote View in the file tree (left of screen) and select File > New File from the menu.

2. Now right-click your new file and open. With the “Check files when opening” option enabled you should see a green tick appear beside the filename which means the file is “checked out” - You are now the sole owner of that file until you check it in.

3. After entering your source code you may save - and update - the file whilst you still have it checked out, preventing other users from accessing that file while you test it for instance. To do this right-click on the filename and select “Put” - you should see an upload progress bar appear to indicate the file is being uploaded to the remote host.

4. When you have finished working on the file simply save, then right-click the filename and select “Check in” - The file is now available for checkout by any user.

Testing…

1. If you have setup a Testing Server you can use the preview button (globe icon in top bar) to test your page.

Note: you must have permission to the parent directory to preview the file

For more information on setting up projects in Dreamweaver please visit the official Tech Notes

How to define a site in Dreamweaver tn 1048

June 6, 2006

PHP Source Code Protect

You will find other articles relevant to this document in these sections:
Cameron Manderson @ 1:25 pm

I have been using PHP for commercial products now for some time and I have always been concerned with providing code to clients that is not protected from other developers - one thing that we are familiar with compiling/distributing code under C++ or Java. Often code that is included in even the smallest a job to make our life a lot easier and can be the result of hundred of hours of unpaid development.

There are a number of different methods to help disguise and protect our code under PHP and is often overlooked by many web developers. For reasons I am unsure, maybe the same reason that the Internet has failed to develop standards. As we have discussed topics of security on this site I think it is important to discuss ways to secure a commercial application or a standard library that you or your business have developed in PHP.

This scenario could apply to:

  • Distribute shareware or trial software written in PHP
  • Protect source code from being viewed by other developers or by your hosting provider
  • Freelancers working on small/group projects without giving away their entire library of developed code
  • Harden the ability for people to analyse ways to exploit/hack your code

Considering licences such as expiring applications or limiting what servers or domains host your files are all possible with the help of a few software packages. You can embed the licensing in each file, or call on a licence file that could be issued (FTP’d) to your server. Also, degrees of how you protect your intellectual property and source code are covered such as compilation, encryption or obfuscation.

In terms of protecting your source code instead of trying to explain the meaning better than wikipedia, I thought I would just include: “Obfuscated code is source code that is (perhaps intentionally) very hard to read and understand.” Typically we can perform obfuscation through replacing local variables, functions and removing formatting and commenting. (It is worth noting that if you are working with creating a reusable package that variable or function obfuscation may not be quite what you are after).

A method of obfuscation could be to create a intermediate compiled code, which often is smaller and more efficient. It also can be a way of protecting our code from reverse engineering. Obfuscation can also be an example of security through obscurity, (which should never be relied on). To further the protection of our code we should consider encryption of our code.

If you have used an MVC implementation you may only consider protecting your Model or maybe your Model and Controller. You may wish to leave your View (Smarty/HTML/etc) as open as you will not want to limit simple visual updates that you may not be available to update for your client. Typically your view is not reusable and does not contain your Intellectual Property – and I imagine may often cause more problems than it is worth, but depends on the scenario.

There are packages that help protect our source code (through compilation, obfuscation and encryption) and most come with friendly GUI to help us achieve protection and handle licensing.

When we protect our code typically it requires server side installation to provide the required functionality (although some can export bundled required files). There are a few that provide the functionality through included source files. Your decision of which package to use will be in some part dictated by the support of your hosting company. I recommend your first step to check what package is available to you. I gave my hosting company and quick call and asked them what methods they support to secure my PHP source code and found that my hosting company supports two popular packages:

Both are available for purchase at around the ~US$250 or ~AUS$380 which really is quite a small investment when you consider the protection it can provide. If you own your own business or freelance you would immediately see that for the small investment you will gain a big return: protection of your intellectual property and future work. You may also find that as part of your professional practice of being a responsible programmer that suggesting the cost be included in a project budget as it can help further strengthen your security.

ionCube Project Sheet

Default Project Sheets

ionCube add source code to protect

Select project files

Example of output code from ionCube:

if(!extension_loaded('ionCube Loader')){$__oc=strtolower(substr(php_uname(),0,3));$__ln='/ioncube/ioncube_loader_'.$__oc.'_'.substr(phpversion(),0,3).(($__oc=='win')?'.dll':'.so');$__oid=$__id=realpath(ini_get('extension_dir'));$__here=dirname(__FILE__);if((@$__id[1])==':'){$__id=str_replace('','/',substr($__id,2));$__here=str_replace('','/',substr($__here,2));}$__rd=str_repeat('/..',substr_count($__id,'/')).$__here.'/';$__i=strlen($__rd);while($__i--){if($__rd[$__i]=='/'){$__lp=substr($__rd,0,$__i).$__ln;if(file_exists($__oid.$__lp)){$__ln=$__lp;break;}}}@dl($__ln);}else{echo('The file '.__FILE__." is corrupted.n");return 0;}if(function_exists('_il_exec')){return _il_exec();}echo('This encoded file cannot be run. Please run the file ioncube-loader-helper.php for more information.');return 0;
 
?>
0y4hYErdHGVGixqeLj/G9FXUdF4/0fdmCtjjNAv3HcIYGaw0iOU34iT84LwcPV5XJcau0RQgkiNL
AVfBK2FhhSoxdC504USDRPO+lhcm5T6RBUjej+Xz8amc0pUigrTnMMmjcdW3ZewemB0XE5aLmAgT
fbcV0ToCKoCpSbfEpCAgH0tccGSSV3a1×1NC3KkjGLT0Ld/PzHVao/q6Zveq1/vLZ2FFpFK5lH6u
iT+lo8Av02HzMsKNl3zafQuLOTKQoWpGI3sRe9fKyK/pDQa/8FMYHCpwZ7lBKQzL5Ha3h56RS+e3
FbDgAbfY2t1i14GW8J5s6eq94fjhAEbGQ4fHa43LTeUy0qCLdW==

The first section of the code handles how to load the dynamic libraries and checks support for iconCube. The second is the ASCII (you can export out in binary) source code.

Unfortunately for some reason my hosting company didn’t support Zend’s product. Zend provides a Zend Guard which is more expensive but operates on the popular free Zend Optimiser server side which generally most hosting companies will have or won’t be bothered installing, although mine did.

Both of the other products provide an easy way to generate a licence file which allows you to customise the restrictions for individual end-users without having to resupply the compiled protected source code again. You can simply FTP or generate and email the new licence file. This is particularly good for converting Trial software into full working versions, or from a development version to a full version for production.

Standard License Options

Some standard options for licensing in ionCube

Example of licence file contents:

------ LICENSE FILE DATA -------
TY24U9294dRrU8XBUkuaZ9ITVuwcMAZc
9bBtv0mZcsLrK6E5LnHJMN9glODwfHF3
pSv9XCuR9JGhpfyXvYOXe3cjsMD6qzGr
2mnQcvm6zftypTDRLf+TdlCTjxWJKbVd
4eFgH6+cfvR8QqAIO8EQ3XCwZ/S+o7r/
mnGKru11PbFrsJvZ0oDPPZZgLH0OIHZL
edk4/AKKg2KMztID9oWoW9D4jmd3nGaN
kjgWaXeTU7yGN+ojRf/vOM984m4Fjmuu
eoGHlkbGLIR7Ot5lF3==
------------------------------–

Before you choose which package suits your requirements better, you will want to view over the feature checklist and download and play with a trial version (and test on your deployment server). I found it particularly difficult to find the differences between the two.

In the end? I chose ionCube as it came across to me as more established product and supported all the good features I expect from an encoding package. Also general comments from forums appear to be fairly positive and it runs on ionCubes own code optimiser.

After installation of the trial versions both come with easy to use Wizards and Licence Generators. You typically need to create your project and select your source file. Within a few minutes you can easily identify all the advanced functionality and have working encoded source files.

Advanced steps allow you to customise dynamic variables that are included in your licence. You can also even consider ways to write the licensing into your source code, but this will not be enforced by the your packages parser (e.g. By ionCube etc), but that way you can start to extend the functionality of your licensing past the standard; and even use Digital Signatures to ensure non-tampering of your source (and underlying licensing system). That way you are not relying on an individual encoders licensing and you may be able to encode using different encoders if you meet a project that needs to run on a different choice of encoder.

After setting up my first encode with ionCube I timed the originals versus the encoded. A simple API consisting of around 30 classes and about 100KB of code. A simple include of the class file saw an immediate 50% increase in speed of the include. (From around .03 seconds to around .015 seconds).

Also it may be worth mentioning that if you have a lot of classes it may be easier to concatenate all the files into one single distributable file. To do this you can create a simple concatenate/compress class that gets the file contents of each of your PHP class files and places them into a single temp file. You can then invoke PHP CLI to compress your classes. This removes white-space (new lines, tabs etc) and commenting. The end result is raw PHP. Note: Be sure to remove any “include” statements that call on included source code as it may cause errors.

// Consider security if variable contain user input
$execute = "php -w " . $incFile . " > " . $destFile;
exec($execute);

Testing this in the past it is a quick way of including your files. Including individually can result in large delays (depending on how many class-path directories need to be scanned to locate the files to include). One thing you will have to consider then is whether you concatenate all classes or just base classes, then use further includes to pull in required functionality, as part of your API may not be required. You can use simple profiling techniques to identify times taken to load.

Further to developing your commercial API you may consider using an documentation generator like phpDoc. Depending on how you setup your commenting and phpDoc, you can indicate which parts functions and files are documented publicly. Ensure to analyse how your API will be used, and protect functions that are not to be invoked. Further to this topic you will need to research ways of writing a commercial API that conceals unnecessary functionality and I.P.

Here are the some useful resources that will help you protect your source code:

May 19, 2006

PHP Generating Passwords

You will find other articles relevant to this document in these sections:
Cameron Manderson @ 10:24 am

There are many different ways to generate passwords, and (depending on the requirements) will need to involve both numbers and letters (preferrably additional special characters like !@#$%^ etc). With PHP the generally easiest way to generate a password is to use a random number mapping to a pointer in a string of ‘valid’ characters. A simple example may be as follows:

Generate password using a for loop and random pointer and string of allowed characters

// Generate a password
$password = '';
$len = 6;
$validCharacters = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabchefghjkmnpqrstuvwxyz0123456789';
while (strlen($password) < $len) {
  $pointer = rand() % strlen($validCharacters);
  $nextChar = substr($validCharacters, $pointer, 1);
  $password .= $nextChar;
}
print "Your new password is " . $password;

Trying to use a larger set of valid characters and the length of the password will help build the strength of your password. Including special characters into the set will help also.
NOTE: Consider if having issues like i,I,1,l,L,0,O (all different characters) will cause confusion and you may consider stripping some of them out (like done above).

Technically, I am sure a maths person will be able to figure out using probability the chances of the pointer landing on a set of upper case, lower case or number, and be able to better guess at what a likely result would be.

Instead we could re-write the function above to use a array, that allows us to seperate out the character sets, and from there we could better balance the generation. We can also then write a more useful password generation function that will allow us to specify not only length, but strength (based on what sets of characters are included).

Generate a password using a array of allowed character set with 2 random pointers

/**
 * Generate a password based on sets of characters (levels)
 *
 * String getNewPassword(int $length, int $level);
 * Set level higher to include more character sets
 * 1 = lowercase alpha
 * 2 = mixed case alpha
 * 3 = mixed case alphanumeric
 * 4 = mixed case alphanumeric and special characters
 *
 * @param length int Length of password
 * @param level int Sets number of character sets to include
 * @return String New Password based on parameters
 * @author Cameron Manderson &lt;cameronmanderson@gmail.com&gt;
 */
function getNewPassword($length = 8, $level = 3) {
  // Our character Sets
  $characterSets = array();
  $characterSets[] = 'abcdefghijklmnopqrstuvwxyz';
  $characterSets[] = 'ABCDEFGHIJKLMNOPQSRTUVWXYZ';
  $characterSets[] = '01234567890';
  $characterSets[] = '`~!@#$%^&*()-_=+.'/\"';
 
  // Check we have a valid level
  if($level > count($characterSets)) $level = count($characterSets);
  else if($level < 1) $level = 1;
 
  // Generate the password
  $password = ''; // Out new password
  for($i = 0; $i < $length; $i++) {
    $xPointer = rand() % $level; // Get out set pointer
    $yPointer = rand() % strlen($characterSets[$xPointer]);
    $password .= substr($characterSets[$xPointer], $yPointer, 1);
  }

  // Return our new password
    return $password;
}

You will also want to consider how you are going to store your passwords. There are many different algorithms and approaches that can be taken. SHA and MD5 are very common.

May 16, 2006

XML Flash Actionscript Tools

You will find other articles relevant to this document in these sections:
Cameron Manderson @ 11:15 am

A while ago helped out a designer (Sacha Jerrems) with some ActionScript XML functions that helped him retrieve nodes and node values instead of using firstChild etc.

Instead of using for loops to locate child nodes, and then go into them, we can make simple function calls to do the work for us.

Example Use

Say we have a valid XHTML document, with a node named ‘title’. To get its value we could simple call:

trace(getValue(getNode('title', xhtmlDoc)));

This method allows us to pipe the results without needing to assign them to variables etc. It can typically compress your code from 10s of lines down to a single assignment.

The Actionscript

/**
 * Searches through an XMLNode's children to locate a particular child node
 * 
 * @param String nodeName The nodeName to locate
 * @param XMLNode parent The parent to search through
 * @returns Found node or null if it could unable to locate a match
 * @author Cameron Manderson <cameronmanderson@gmail.com>
 */
function getChild(nodeName, parent) {
  return getNode(nodeName, parent, false);
}
 
/**
 * Searches Recursively through an XMLNode to locate a particular 
 * child node
 *
 * @param String nodeName The nodeName to locate
 * @param XMLNode parent The parent to search through
 * @param boolean recursive Whether to search recrusively
 * @returns Found node or null if it could unable to locate a match
 * @author Cameron Manderson <cameronmanderson@gmail.com>
 */
function getNode(nodeName, parent, recursive) {
  // Check that we are not looking through or for undefined variables
  if(nodeName == undefined || parent == undefined) {
    return null;
  }
  if(recursive == undefined) recursive = false;
  var i = 0; var locatedNode = null;
  // Check parent for match
  if(parent.nodeName == nodeName) { 
    return parent;
  }
  // Check through the child nodes until the particular child node is located
  for(var i = 0; parent.childNodes && i < parent.childNodes.length; i++) {
    // look to see if the child is what we want
    if(parent.childNodes[i].nodeName == nodeName) {
      return parent.childNodes[i]; 
    }
    // if we are recursing, recurse into child
    if(recursive) {
      locatedNode = getChild(nodeName, parent.childNodes[i], recursive);
    }
    if(locatedNode !== null) {
      return locatedNode;
    }
  }
  return null;
}

You could also then use a simple getValue() function such as below to help you retrieve a node value.

function getValue(node) {
  if (node && node.firstChild) {
    return node.firstChild.nodeValue;
  }
  return "";
}

Hopefully this helps you quickly find the power of XML with Flash

P.S. I request that you leave my name in the functions if you use them. Code is released under our standard LGPL. Which means it is free for you to use, but you must leave the code intact. If you make changes to the code, you should email them back to me. I wrote this a while back and it is probably time for me to make it AS2, but atleast it is more backward compatible.

April 28, 2006

Mail Forms and Shared Hosting

You will find other articles relevant to this document in these sections:
Richard Lee @ 12:06 pm

If you’ve ever had to deal with sending mail from a shared host you’ll know what I mean when I say it’s a pain in the ass!

Scenario:

In your shared-hosting environment all mail is sent to your host’s mail server  - as set in your DNS setup(i.e. mail.my-hosts-domain.com.au). And in all of your mail scripts, being the cautious developer you are, you have specified the return-path for (bounced emails) to a mailbox on your domain (webmaster@mydomain.com.au). Unfortunately it appears some of your users aren’t receiving your mail, while some are - but it’s turning up in their junk folder labelled as spam.

The Low-Down:

Apart from the obvious reasons, such as being blacklisted by an ISP/ host, or the very user, it’s quite possible your mail has been failing your host’s Sender Framework Policy (SFP).

Essentially, the SPF specifies who is authorized to send mail for the sender’s domain. So if there’s no MX record (domain mail server id) for your domain within the hosts very own DNS - which is often the case in shared hosting - your outgoing mail will be flagged (Received-SPF header:…”failed”) and in-turn be filtered as spam! I should note though, not all spam filters check for SFP validility. Currently I know Gmail does it, and although it is an annoyance at the best of times, SFP prevents spammers from spoofing mail addresses.

So what are the options?

In terms of mail turning up as junk mail, failed SFP may not be your only problem as spam filters check for a variety of other things too. But if your sure everything is the way it should be check your mail headers, there’s plenty of information to be found. For SFP issues look for the presence of the “Received-SFP:….” header. If it says  “failed”, you’ve got major problems, on the other hand if it says “neutral” it’s not so bad, depending on the severity of the spam filter your encountering “neutral” flagged mail should come through. For “failed” you could try appending the hosts domain name

me@my-domain.my-hosts-domain.com.auOtherwise the next best step is to contact  your host and enquire as to whether there is an MX Record for your domain.

If anyone has further comments on successfully sending mail from a shared hosting environment please let us know!

April 27, 2006

PHP unique ID

You will find other articles relevant to this document in these sections:
Cameron Manderson @ 10:20 am

Using two popular database abstraction packages for PHP, PEAR::DB and Adodb, you are able to generate a unique identifier that is only issued once. It provides this ability by creating sequence tables that will return the unique ID and automatically increment the index. People familiar with MySQL AUTO_INCREMENT would be familiar with this behaviour.

This helps in many situations, such as creating order numbers or unique reference numbers/receipts. You can also use it for your row identifiers. Since the classes work on the idea of portability between different Relational Database Management Systems (RDBMS) you should be incouraged to use them so that you do not rely on individual methods of geenrating the next ID (such as using AUTO_INCREMENT). You can therefore allow the drivers included in the abstraction packages to handle the best implementation for the current RDBMS.
Depending on the flavour of abstraction classes you use, you can generate your unique key doing the following:

PEAR::DB (visit PEAR::DB or the PEAR::DB End user documentation)

PEAR is a very common database abstraction that you can download from the above site. You can simply extract it to a lib folder in your application and use it to execute all your SQL and manage your record set results.

Pear provides the API for working with sequences with the methods:

  • integer createSequence (string $seq_name);
  • integer nextId (string $seq_name, boolean $onDemand = TRUE);
  • integer dropSequence (string $seqName);

An example for generating a unique ID through the API would be as follows:

< ?php
// Once you have a valid DB object named $db...
$id = nextId('mySequence');
if (PEAR::isError($id)) {
die($id->getMessage());
}
// Use the ID in your INSERT query
$res =& $db->query("INSERT INTO myTable (id, text) VALUES ($id, 'foo')");
?>

ADODB (visit ADODB or the ADODB Manual)

ADODB is another database abstraction that supports many different RBDMS. It is modelled off the Microsoft ADO database classes and provides a very extended package overall with many added benefits, such as Caching etc.

ADODB provides the API for working with sequences with the following methods:

  • CreateSequence($seqName = ‘adodbseq’,$startID=1)
  • GenID($seqName = ‘adodbseq’,$startID=1)
  • DropSequence($seqName = ‘adodbseq’)

An example for generate a unique ID through the API would be as follows:

< ?php
// Lookup the value from the DB connection
$id = $db->GenID('mySequence');
if(empty($id)) die('Unable to generate sequence value);
 
// Use the ID in your INSERT query
$res = $db->Execute("INSERT INTO myTable (id, text) VALUES ($id, 'bar')");
?>

April 24, 2006

Use PHP number_format

You will find other articles relevant to this document in these sections:
Cameron Manderson @ 6:17 pm

Ok, here is a basic one, I thought I would provide a quick overview of how the PHP number_format function works for presentation of numbers.

Invocation

string number_format ( float number [, int decimals [, string dec_point, string thousands_sep]] )

When you would like to represent a number to the user you can make use of the number_format PHP function. It accepts a number and a series of optional method parameters. Your optional parameters specify how you wish to present your number. You can either specify 1, 2 or 4 parameters (therfore not 3).
Examples

To display a 2 decimal place number (such as a currency) you can use:

// To display myValue (4.3123123123) as 4.31
print(number_format($myValue, 2));

To display a number with thousands represented by a ‘,’ and the decimal represented by a ‘.’ you can use:

// To display myValue (4500.131313) as 4,500.13
print(number_format($myValue, 2, '.', ','));

For those of you who use Smarty for presentation, you can invoke a simple decimal presentation via:

{$myValue|@number_format:2}

Using smarty you can pipe your input into various PHP methods. The above example demonstrates how the parameter $myValue gets piped as the first parameter to the number_format function, followed by the second parameter ‘2′. The above call is the same as our first example: number_format($myValue, 2);

Further Manipulations

If you are looking for rounding a number for use in an equation, you will want to have a look at the PHP round() function located here. An example would be:

<p align="left">// Makes a 4.326 become 4.33 in value.
$myRoundedVal = round($myVal,2);</p>

If you are looking for a quick way to pad with zeros (zerofill), use the (powerful) PHP sprintf() function. An example would be:

// Make a digit zero padded, such as 70 = '070' or 7 = '007'
print(sprintf("%03d", $myVal)); // Change %03d with %04d etc for more padded zeros

April 21, 2006

Quick Apache PHP Mysql FTP install

You will find other articles relevant to this document in these sections:
Cameron Manderson @ 10:41 am

Your development environment is important to match the sort of environment that you wish to deploy on. Often the basic infrastructure of a webdevelopment company would have this sort of simplified deployment server environments:

- Development
Development server is usually either a the workstation locally for a developer or may be a development office server that is setup with the required apache environment. It is used so that developers can independantly develop and test without affecting other developers or destroying a client review version of the project.
- Staging
Staging matches the Live infrastructure/environment as close as possible. It may be used for formal testing (often there is a testing server, but sometimes staging is used) and review by the client. It will represent the version of the project before the project is moved to the live servers.
- Live/production
These host the live project in use for its intended purpose.

Often to achieve this process, installing Apache, PHP, MySQL, PhpMyAdmin etc can be quite a hastle - especially on several different machines and environments.
That may quickly make you think how am I going to quickly get my development and staging servers up? Surely that will take weeks of configurations to achieve? Well you would be right to initially feel that way, but you shouldn’t. There are many ‘quick install’ programs out there that allow us to quickly install and configure and Apache web environment instantly.
I have used variations of xampp and it is available in many different flavours for different operating systems. It is free for use. I have xampp running easily under a Win32 and Linux environment and the process is extremely quick and easy. There are also versions for Solaris and MacOSX. It is provided as a ready to go package that provides everything you need to get your testing/development environment up.

It also is very beneficial to PHP developers as it allows a option to switch between PHP 4 and PHP 5 with a simple script that can be run. Great for testing forward/backward compatibility.

You will need to first visit the Xampp Sourceforge File Listing and choose the packages required for your Operating System.

Windows

For windows this comes in two flavours, and two installation methods. At the time of writing this, xampp windows package was upto version 1.5.1.

The distribution for Windows 98, NT, 2000 and XP. This version contains: Apache, MySQL, PHP + PEAR, Perl, mod_php, mod_perl, mod_ssl, OpenSSL, phpMyAdmin, Webalizer, Mercury Mail Transport System for Win32 and NetWare Systems v3.32, JpGraph, FileZilla FTP Server, mcrypt, eAccelerator, SQLite, and WEB-DAV + mod_auth_mysql.

Xampp Windows is provided in a Lite (basic) version with minimal package configuration and a complete version with all the packages. You can either download the package in a self extracting .exe, a ZIP archive or a .exe style installer.

Installing the packages could not be easier, either extract or use the installer to install the Xampp package onto your computer. I like to use “\server\xampp” as an install location and I try to keep it the same on every workstation.

Once Xampp is installed you will want to go to the installation directory and run the Xampp-control. This control panel allows you to easily start and stop the various installed packages, such as FTP/Apache or MySQL. You can also tick the “svc” tickbox which will install xampp to the windows service list (Control Panel -> Administrative Tools -> Services) which will set the services to start automatically when you boot windows.

Then you need to point your web browser to http://localhost/. At this point you will be able to choose your language and perform various install tests to see if everything is running smoothly.

You will need to run the security recommendations immediately and configure your webserver with a password. This is a very important step.

Linux

Linux is very easy to install. At the time of writeing this, xampp linux was also upto version 1.5.1

The distribution for Linux systems (tested for SuSE, RedHat, Mandrake and Debian) contains: Apache, MySQL, PHP & PEAR, Perl, ProFTPD, phpMyAdmin, OpenSSL, GD, Freetype2, libjpeg, libpng, gdbm, zlib, expat, Sablotron, libxml, Ming, Webalizer, pdf class, ncurses, mod_perl, FreeTDS, gettext, mcrypt, mhash, eAccelerator, SQLite and IMAP C-Client.

You will simply need to download the package to you linux /tmp directory. If you are only accessing your server with Putty, and need a way to download the file directly onto your computer from the command line, connect with SSH and perform the following:

cd /tmp
wget http://nchc.dl.sourceforge.net/sourceforge/xampp/xampp-linux-1.5.1.tar.gz

The location of where you need to download the installation can be found by selecting a mirror to download the file from in Sourceforge.

Once that you have downloaded the package, execute the following under root previledge:

tar xvfz xampp-linux-1.5.1.tar.gz -C /opt

This command extracts a GZip Tar file to the /opt location. You install will now reside under /opt/lampp

Once the package has extracted you can now start the server. If you currently have any other services (such as previous Apache/MySQL services installed, this may fail. Turn them off using the appropriate “apachectl stop” or “/etc/init.d/apache stop” commands.

/opt/lampp/lampp start

Before taking any more steps I would recommend immediately running the security option of Lampp to configure the security of the server. This is highly recommended.

/opt/lampp/lampp security

Now you can point your browser to the IP of your linux box (either localhost if you are running the apache under your local computer or the IP on the network).

If you are having problems with your linux isntallation, checkout the Linux FAQ on Apache Friends.

Mac OSX or Solaris
If you installing xampp follow the appropriate guide below:

- Max OSX install read here.
- Solaris install read here.
Security Note: They do not recommend Xampp to be run for live/production. This is to do with security and takes extra configuration to make is secure enough for a live environment.

Once you have installed these packages successfuly it is very quick and easily to replicate the install across different workstations/server environments.

« Previous PageNext Page »