howtos » php

This snippet of code reorders items in a table based on the number of steps you want to move an item from its current position. It moves the item of interest to its new position and shifts all other items to their new shifted positions.

PHP:
  1. function moveItem ($n_steps) {
  2. if ($n_steps == 0) {
  3. return;
  4. }
  5.  
  6. $cur_pos = $this->pos;
  7. $new_pos = $cur_pos + $n_steps;
  8.  
  9. if ($n_steps <0) {
  10. $min_pos = $cur_pos + $n_steps;
  11. $max_pos = $cur_pos - 1;
  12. $shift_sign = '+';
  13. } elseif ($n_steps> 0) {
  14. $min_pos = $cur_pos + 1;
  15. $max_pos = $cur_pos + $n_steps;
  16. $shift_sign = '-';
  17. } else {
  18. return;
  19. }
  20.  
  21. $id = $this->id;
  22.  
  23. //Reorder existing items that will be existed by moving this item
  24. $sql = "UPDATE  positions
  25. SET  order_num = order_num $shift_sign 1
  26. WHERE   id = $id
  27. AND position>= $min_pos
  28. AND position <= $max_pos";
  29.  
  30. $this->db->query($sql);
  31.  
  32. //Now set new position for this item
  33. $sql = "UPDATE postions SET position = $new_pos WHERE id = $id";
  34. $this->db->query($sql);
  35. }

A few sites I administer have recently had the misfortune of having spambots visit their enquiry and contact pages. These pages usually have a contact form, where an enquirer can leave their name, e-mail, and request or comment. When they submit the form, a copy of the message is e-mailed to the site owner. The spambots try and submit messages that usually contain gibberish but also multiple URLs to spam sites. Something had to be done to prevent site owners from receiving hundreds of spam messages a day.

I considered a few methods for preventing the bots from visiting the enquiry page. These included firewall configuration, user-agent detection, rudimentary parsing of the messages, captcha systems, and so forth. These methods were either too cumbersome to implement, could be circumvented, or spoiled the user experience for a genuine user. The latter was a critical concern.

Enter Akismet

The Akismet API is an open API used to assess the spam score of comments left or enquiries made on a site. It is in widespread use as a plugin for WordPress blogs. Its effectiveness has become a must-have plugin for WordPress installations. The Akismet API however can be applied to any site or application capable of making HTTP requests.

First you need an API key. You can obtain one by registering for a WordPress.com user account (you do not need to have an active WordPress blog). Your API key will be e-mailed to you once you have activated your account.

Akismet and PHP5

Download the PHP5 Akismet Library.
Extract the contents of the downloaded package and place them in a location that your application can access when required.

Here's how to use the Akismet API in your PHP5 code.

PHP:
  1. require_once('Akismet.class.php');
  2.  
  3. $API_key = 'xxxxxxxxxxxx';
  4. $source_url = 'http://www.mysite.com/contact.php';
  5.  
  6. $akismet = new Akismet($source_url, $API_key);
  7. $akismet->setCommentAuthor($enquirer_name);
  8. $akismet->setCommentAuthorEmail($enquirer_email);
  9. $akismet->setCommentContent($enquiry);
  10.  
  11. if ($akismet->isCommentSpam()){
  12.     //Enquiry is spammy - log it for later review by site owner
  13.     //If false positive, be sure to submit to Akismet so that it can learn from
  14.     //  its mistake.  Use Akismet::submitHam()
  15. } else {
  16.     //Enquiry is not spammy - e-mail it to the site owner
  17.     //If false, be sure to submit to Akismet so that it can train itself better.
  18.     //  Use Akismet::submitSpam()
  19. }
  20.  
  21. //Below are other Akismet methods that you could call
  22. $akismet->setCommentAuthorURL($enquirer_url);
  23. $akismet->setCommentType($enquiry_type);    //{'blank', 'comment', 'trackback', 'pingback', or custom}
  24. $akismet->setPermalink($url);   //A permanent URL referencing the resource for which a comment is being left for

Akismet and PHP4

Download the PHP4 Akismet library. Extract the contents of the downloaded package and place them in a location that your application can access when required.

Here's how to use the Akismet API in your PHP4 code.

PHP:
  1. require_once('Akismet.class.php');
  2.  
  3. $API_key = 'xxxxxxxxxxxx';
  4. $source_url = 'http://www.mysite.com/contact.php';
  5.  
  6. $comment = array('author'     => $enquirer_name,
  7.                  'email'        => $enquirer_email,
  8.                  'website'   => $enquirer_uri,
  9.                  'body'         => $enquiry,
  10.                  'permalink'    => $this_page_uri,
  11.                  'user_ip'   => $referrer_ip,     // optional, defaults to $_SERVER['REMOTE_ADDR']
  12.                  'user_agent'   => $client_ua,        // optional, defaults to $_SERVER['HTTP_USER_AGENT']
  13.                 );
  14.                
  15. $akismet = new Akismet($source_url, $API_key, $comment);
  16.  
  17. // test for errors before submitting to Akismet
  18. if($akismet->errorsExist()) {
  19.     if($akismet->isError('AKISMET_INVALID_KEY')) {
  20.         //...
  21.     } elseif($akismet->isError('AKISMET_RESPONSE_FAILED')) {
  22.         //...
  23.     } elseif($akismet->isError('AKISMET_SERVER_NOT_FOUND')) {
  24.         //...
  25.     }
  26. } elseif ($akismet->isSpam()) {
  27.     //Enquiry is spammy - log it for later review by site owner
  28.     //If false positive, be sure to submit to Akismet so that it can learn from
  29.     //  its mistake.  Use Akismet::submitHam()
  30. } else {
  31.     //Enquiry is not spammy - e-mail it to the site owner
  32.     //If false, be sure to submit to Akismet so that it can train itself better.
  33.     //  Use Akismet::submitSpam()
  34. }

If you are dealing with multiple users in different timezones or simply want to display times in a timezone other than your server's settings, it is best to store timestamps as their UTC (~ GMT) equivalents. When you read those timestamps later, you can convert them to local time.

Local time to UTC time

PHP:
  1. date_default_timezone_set('Australia/Sydney');
  2. $time = gmmktime($hr, $min, $sec, $mon, $day, $yr);
  3. $date = gmdate('d/m/Y H:i', time());

date_default_timezone_set sets the default timezone for all date & time operations.
gmmktime is analogous to mktime except it takes in local time values and creates the corresponding UTC timestamp.
gmdate similarly takes in local time values and creates the corresponding UTC date & time.

UTC time to Local time

PHP:
  1. $ts_utc = read_timestamp_from_db()//Some custom function in your script
  2. date_default_timezone_set('Australia/Sydney');
  3. $offset = date('Z');    //Timezone offset from UTC in number of seconds (can be +ve or -ve)
  4. $ts_local = $ts_utc + $offset;

To prevent the caching of a web page on your client's end, use the following snippet of PHP to ensure that the appropriate HTTP headers are sent.

PHP:
  1. header("Cache-Control: no-cache, must-revalidate"); // HTTP/1.1
  2. header("Expires: Tue, 03 Jul 1979 00:00:00 GMT");   // Date in the past

The first header tells the client that the page must not be cached.
The second header is a backup, and tells the client that the page expired a long time ago in the past, and it should fetch a more recent version.

The same effect can be achieved by placing corresponding meta tags in your HTML document

HTML:
  1. <meta http-equiv="Expires" content="Tue, 03 Jul 1979 00:00:00 GMT" />
  2. <meta http-equiv="Pragma" content="no-cache" />

Where possible, place your cache control directives in the HTTP header, because some clients and proxies rely on your server's HTTP response to determine caching.

cURL is used to interact with remote URLs without needing a user to initiate the process (e.g. by clicking on a form submit button). cURL is useful for submitting HTTP POST/PUT/DELETE requests when dealing with web services. PHP has inbuilt cURL support since PHP 4.0.2 using cURL's libcurl library. Find out more about PHP/CURL -- using libcurl with PHP here.

A fullset of cURL options and what they mean can be found in
PHP's manual entry for curl_setopt().

PHP:
  1. //Contains encoded string to pass along for basic authentication purposes
  2. $auth_token = base64_encode($username . '-' . $password);
  3.  
  4. //Target URL - the URL you want to submit a form to
  5. $target_url = 'http://www.remotesite.com/post_target.php';
  6.  
  7. //Create  a new cURL handle
  8. //Passing the target URL to curl_init allows you to bypass the call curl_setopt($ch, CURLOPT_URL, $target_url);
  9. $ch = curl_init($target_url);
  10.  
  11. //Tell the handler that the info is to be sent using an HTTP POST request
  12. curl_setopt($ch, CURLOPT_POST, true);
  13.  
  14. //Set other relevant headers.  Place each header as an array element
  15. //An alternative to building the Authorization header is to use curl_setopt($ch, CURLOPT_USERPWD, $username . ':' . $password);
  16. $headers = array('Authorization: Basic ' . $auth_token,
  17.                  'User-Agent: Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.8.1.3) Gecko/20070309 Firefox/2.0.0.3');
  18. curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);
  19.  
  20. //Pass the POST fields - be sure to urlencode your value strings (hint: http_build_query() will do this for you; PHP5)
  21. //Below we assume values have already been posted to this script and kept in $_POST.  We have validated the submission and
  22. // are now posting the same values to a remote URL
  23. curl_setopt($ch, CURLOPT_POSTFIELDS, http_build_query($_POST));
  24.  
  25. //When we execute the handle, we want curl_exec() to return to a string rather than directly outputting it
  26. curl_setopt($ch, CURLOPT_RETURNTRANSER, true);
  27.  
  28. //Don't use a cached connection - explicitly create a new one
  29. curl_setopt($ch, CURLOPT_FRESH_CONNECT, true);
  30.  
  31. //Fail if cannot connect to the target server within 5 seconds
  32. curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, 5);
  33.  
  34. //If the target server returns a redirect request using the "Location:" header directive, then follow it.
  35. //To prevent recursive redirects, only do a max of 5 follows
  36. curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true);
  37. curl_setopt($ch, CURLOPT_MAXREDIRS, 5);
  38.  
  39. //Let's now execute the handler
  40. //Because CURLOPT_RETURNTRANSFER is true, we need to capture the return value of curl_exec()
  41. $response_data = curl_exec($ch);
  42.  
  43. //Was there an error?
  44. //curl_errno() returns the error code
  45. //curl_error() returns a clear text message for the last cURL operation
  46. if (curl_errno($ch)> 0){
  47.     die('There was a cURL error: ' . curl_error($ch));
  48. } else {
  49.     //Close the handler and release resources
  50.     curl_close($ch);
  51. }
  52.  
  53.  
  54. //Now do something with your data
  55. return myProcessingFunction($data);

Sending a plain-text e-mail through PHP is a simple process

PHP:
  1. mail ($to, $subject, $message, $headers);

The $to parameter can look like:

example@mysite.com
example@mysite.com, user@mysite.com
Example Sr <example@mysite.com>, Example Jr <user@mysite.com>

Common headers to use in your messages:

PHP:
  1. $headers =  "From: yourname@yoursite.com\r\n
  2.              Reply-To: replyhere@yoursite.com\r\n
  3.              Cc: watcher@yoursite.com\r\n
  4.              Bcc: spy@yoursite.com\r\n
  5.              X-Mailer: YourApplicationNameHere\r\n"

PHP 5's DOM Functions (or extension) allows you to create and manipulate XML documents. In fact, it can also be used to create and manipulate any documents adhering to the DOM3 specifications such as HTML and XHTML documents.

Creation of a DOM document is a fairly simple affair

  • Instantiate DOMDocument - also specify which version of XML the document is in and how it is encoded
  • Create elements through the DOMDocument object
  • Set your elements' properties (e.g. values, attributes, child nodes)
  • Append the elements to your parent DOMDocument
  • Output as fully-formed XML using DOMDocument::saveXML()

The following example shows you how to create an XML document (using UTF-8 encoding) using PHP 5's DOM functions.

PHP:
  1. //First create an XML document
  2. //The following statement sets XML version 1.0, encoding utf-8
  3. $dom = new DOMDocument('1.0', 'utf-8');
  4.  
  5. //Step 1: create the root node
  6. //Now create the root node and declare the XML namespace
  7. $entry_node = $dom->createElementNS('http://www.w3.org/2005/Atom', 'entry');
  8. //If you need to add additional namespace declarations, do it now
  9. $entry_node->setAttribute('xmlns:gd','http://schemas.google.com/g/2005');
  10.  
  11. //Step 2: create all child nodes
  12. $category_node = $dom->createElement('category');
  13. $category_node->setAttribute('scheme', 'http://schemas.google.com/g/2005#kind');
  14. $category_node->setAttribute('term', 'http://schemas.google.com/g/2005#event');
  15.  
  16. $title_node = $dom->createElement('title', $title);
  17. $title_node->setAttribute('type', 'text');
  18.  
  19. $content_node = $dom->createElement('content', $content);
  20. $content_node->setAttribute('type', 'text');
  21.  
  22. //In some cases the child node may itself be a parent with its own child nodes
  23. //Create the parent node
  24. $author_node = $dom->createElement('author');
  25.  
  26. //Create the child nodes
  27. $author_name_node   = $dom->createElement('name', $author_name);
  28. $author_email_node  = $dom->createElement('email', $author_email);
  29.  
  30. //Add the child nodes to the parent
  31. $author_node->appendChild($author_name_node);
  32. $author_node->appendChild($author_email_node);
  33.  
  34. $transparency_node = $dom->createElement('gd:transparency');
  35. $transparency_node->setAttribute('value', 'http://schemas.google.com/g/2005#event.opaque');
  36.  
  37. $eventstatus_node = $dom->createElement('gd:eventStatus');
  38. $eventstatus_node->setAttribute('value', 'http://schemas.google.com/g/2005#event.confirmed');
  39.  
  40. $where_node = $dom->createElement('gd:where');
  41. $where_node->setAttribute('valueString', $where);
  42.  
  43. $when_node = $dom->createElement('gd:when');
  44. $when_node->setAttribute('startTime', $startTime . '+10:00');
  45. $when_node->setAttribute('endTime', $endTime . '+10:00');
  46.  
  47. //Another child node which is also a parent
  48. $reminder_node = $dom->createElement('gd:reminder');
  49. $reminder_node->setAttribute('minutes', $minutes);
  50.  
  51. $when_node->appendChild($reminder_node);
  52.  
  53. //Step 3: Add child nodes to the parent node
  54. $entry_node->appendChild($category_node);
  55. $entry_node->appendChild($title_node);
  56. $entry_node->appendChild($content_node);
  57. $entry_node->appendChild($author_node);
  58. $entry_node->appendChild($transparency_node);
  59. $entry_node->appendChild($eventstatus_node);
  60. $entry_node->appendChild($where_node);
  61. $entry_node->appendChild($when_node);
  62.  
  63.  
  64. //Append the root node to the document
  65. $dom->appendChild($entry_node);
  66.  
  67. //Return the fully-formed XML representation of the DOMDocument
  68. return $dom->saveXML();

Here's how to include another template file within a template file:

PHP:
  1. {include file='includes/menu_calendar.inc.tpl'}

PHP:
  1. $guid = md5( uniqid( rand(), true));

  • md5 sanitizes the ID and limits it to 32 characters.
  • uniqid generates a random ID based on your server's time, etc.
    • rand() is prefixed onto the ID - thus enhancing the ID's uniqueness.
    • true tells uniqid() to make use of "more entropy" - again enhancing the ID's uniqueness.

Your development environment might be configured to not display errors and log them instead. While this makes good sense in the production environment, while developing you want to be able to see every error and warning in order to pick up potential troublespots.

You can override php.ini's error display settings via .htaccess or within your PHP script.

Here's a way to turn on error display from within your PHP script.

PHP:
  1. error_reporting(E_ALL)//set PHP to report all errors and warnings
  2. ini_set('display_errors','on'); //configure PHP to display errors on screen