Using an Iterator Interface to Create “Round-Robin” Array

I had a requirement that seemed to need a way to cycle through a set of values in an array in such a way that when I got to the end of the array, it would start over at the beginning, essentially load-balancing the use of those array elements. Perhaps you might want to do the same thing for a set of ads, making sure a given user sees each available advertisement before starting again with the first (perhaps an array stored in $_SESSION?).

After exploring a few alternatives, one I found that I kind of like (for its elegance if not its lack of brevity) was to use PHP’s built-in Iterator interface. The concept here was to load any array into an instance of a class that implements the Iterator, and then simply using the Iterator::next() method to get the current value, then advance the array pointer, pointing it back to the beginning if it has reached the end of the array. Without further ado, the class:


<?php

class RoundRobin implements Iterator
{
    private 
$var = array();

    public function 
__construct($array)
    {
        if (
is_array($array)) {
            
$this->var $array;
        }
    }

    public function 
rewind()
    {
        
reset($this->var);
    }

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

    public function 
key()
    {
        return 
key($this->var);
    }

    
/**
     * Get the current array element, then advance the pointer
     * @return mixed
     */
    
public function next()
    {
        
$var current($this->var);
        
next($this->var);
        if(!
$this->valid()) {
            
$this->rewind();
        }
        return 
$var;
    }

    public function 
valid()
    {
        
$key key($this->var);
        return (
$key !== NULL && $key !== FALSE);
    }
}

A sample usage:


<?php

$data 
= new RoundRobin(range(1,10));
$dbStuff getLotsOfStuffFromTheDB();
foreach(
$dbStuff as $stuff) {
    
$result getSomeMoreStuff($dbStuff['foo'], $data->next());
}

Danger, Will Robinson. Don’t do this, or you’ll have an endless loop:


<?php

$data 
= new RoundRobin(range(1,10));
foreach(
$data as $foo) {
    echo 
$foo "<br />\n";
}

Bug in PHP 5.3.7, Recommended that We Wait for 5.3.8

Due to a bug in crypt(), PHP.net is recommending that you not updgrade to PHP version 5.3.7, but instead wait for 5.3.8 to be released.

Description:
------------
If crypt() is executed with MD5 salts, the return value conists of the salt only.
DES and BLOWFISH salts work as expected.

PHP 5.3.7 Released, 5.2.x No Longer Supported

UPDATE 2011-08-22: See this post about a bug in crypt() in 5.3.7. PHP.net is recommending that you not upgrade to 5.3.7, but instead wait for 5.3.8.

PHP.net announced today that PHP version 5.3.7 has been released. I’m not sure if this is old news or not, but I also saw in the announcement that “all PHP users should note that the PHP 5.2 series is NOT supported anymore. All users are strongly encouraged to upgrade to PHP 5.3.7.” The major fixes/enhancements are:

Security Enhancements and Fixes in PHP 5.3.7:

  • Updated crypt_blowfish to 1.2. (CVE-2011-2483)
  • Fixed crash in error_log(). Reported by Mateusz Kocielski
  • Fixed buffer overflow on overlog salt in crypt().
  • Fixed bug #54939 (File path injection vulnerability in RFC1867 File upload filename). Reported by Krzysztof Kotowicz. (CVE-2011-2202)
  • Fixed stack buffer overflow in socket_connect(). (CVE-2011-1938)
  • Fixed bug #54238 (use-after-free in substr_replace()). (CVE-2011-1148)

Key enhancements in PHP 5.3.7 include:

  • Upgraded bundled Sqlite3 to version 3.7.7.1
  • Upgraded bundled PCRE to version 8.12
  • Fixed bug #54910 (Crash when calling call_user_func with unknown function name)
  • Fixed bug #54585 (track_errors causes segfault)
  • Fixed bug #54262 (Crash when assigning value to a dimension in a non-array)
  • Fixed a crash inside dtor for error handling
  • Fixed bug #55339 (Segfault with allow_call_time_pass_reference = Off)
  • Fixed bug #54935 php_win_err can lead to crash
  • Fixed bug #54332 (Crash in zend_mm_check_ptr // Heap corruption)
  • Fixed bug #54305 (Crash in gc_remove_zval_from_buffer)
  • Fixed bug #54580 (get_browser() segmentation fault when browscap ini directive is set through php_admin_value)
  • Fixed bug #54529 (SAPI crashes on apache_config.c:197)
  • Fixed bug #54283 (new DatePeriod(NULL) causes crash).
  • Fixed bug #54269 (Short exception message buffer causes crash)
  • Fixed Bug #54221 (mysqli::get_warnings segfault when used in multi queries)
  • Fixed bug #54395 (Phar::mount() crashes when calling with wrong parameters)
  • Fixed bug #54384 (Dual iterators, GlobIterator, SplFileObject and SplTempFileObject crash when user-space classes don’t call the parent constructor)
  • Fixed bug #54292 (Wrong parameter causes crash in SplFileObject::__construct())
  • Fixed bug #54291 (Crash iterating DirectoryIterator for dir name starting with )
  • Fixed bug #54281 (Crash in non-initialized RecursiveIteratorIterator)
  • Fixed bug #54623 (Segfault when writing to a persistent socket after closing a copy of the socket)
  • Fixed bug #54681 (addGlob() crashes on invalid flags)
  • Over 80 other bug fixes.

Sphinx Search Beginner’s Guide

I recently received a review copy of Sphinx Search Beginner’s Guide by Abbas Ali (Packt Publishing). What is Sphinx Search? From the SphinxSearch.com web site:

Sphinx is an open source full text search server, designed from the ground up with performance, relevance (aka search quality), and integration simplicity in mind. It’s written in C++ and works on Linux (RedHat, Ubuntu, etc), Windows, MacOS, Solaris, FreeBSD, and a few other systems.

Sphinx lets you either batch index and search data stored in an SQL database, NoSQL storage, or just files quickly and easily — or index and search data on the fly, working with Sphinx pretty much as with a database server.

As advertised, this book is designed to get any reasonably proficient developer up and running with Sphinx while not spending much time on theory or other “boring bits” (quoted from the back cover). Ali does a good job of keeping the text clear, concise, and focused on that task. The text takes you sequentially through the steps to install Sphinx, test the installation, and then proceed through using it in progressively more complex applications.

The book is PHP- and Linux-centric, but there are notes for some of the differences with other OS’s and languages. (The SphinxSearch download includes API code for Python, Ruby, C, and Java as well as PHP.) I downloaded the 2.0.1-beta version, and there were a few minor installation/implementation differences from what was in the book, but nothing significant. Really the only complaint I had was that there were numerous examples of command line screens that were white text on a black background, which I would have found much easier to read if inverted to the usual black-on-white.

I found Sphinx Search Beginner’s Guide to do what it set out to do, and a worthwhile acquisition for anyone who wants to work with Sphinx. My only other complaint is that there is no Kindle e-book version, though you can get it as a PDF or EPUB e-book from Packt (and Amazon has announced Kindle support for EPUB sometime later this year).

Review: PHP 5 Social Networking

PHP 5 Social Networking by Michael Peacock (Packt Publishing) is a book that takes you through the process of creating a social networking web site written in PHP (preferably at least PHP 5.2.0). It is probably not ideal for beginners just getting into web programming, but if you have at least a little bit of experience it could be a good way to get your feet wet while actually creating some useful code.

The book essentially walks you through the creation of a sample site. You’ll see many of the features you’re familiar with in sites such as FaceBook, if somewhat stripped down without many of the bells and whistles. The author discusses some of the choices and viable alternatives to consider at each point of the process, including deciding how much code to create yourself versus some of the ready-made third-party alternatives to look at (view full table of contents).

If you download the code from the PacktPub.com web site, along with this book you will then essentially have a working framework for a social networking site with full, detailed documentation. While this may be exactly what you need, for my level of ability plus my particular interests at this time, I probably would have been more interested in something that dealt more with the design-level considerations: more class diagrams and discussions of “why” as opposed to specific source code and explanations of “how”. (As a bit of an aside: as far as I can tell, there is only one class in the code base which is ever extended, and there is no use of interfaces or abstract classes. This is not necessarily bad, as they may not always be necessary, but I would think for a project of this size there would have been more inheritance and such in a decent object-oriented design.)

E-book versions in PDF or ePUB formats are available from the publisher. It is not currently available from Amazon.com in a Kindle version (nor do I know if it ever will be), but I was able to convert the ePUB document to MOBI via the Calibre program and view it on my Kindle, though ultimately I find it easier to read such technical books in the paper version.

All in all this seems to be a solid product, perhaps not exactly the sort of thing I might look for, but definitely worth your considertaion if you are thinking about diving into the world of social networking web sites.

Image Resize and Crop Function

I thought I would share this function with the PHP community, as it seems to be working pretty well. I created it as part of a page for creating screensaver images for the Amazon Kindle. It accepts the path to a JPEG image file and the desired width and height, then returns a PHP image resource of the resized image, which can then be displayed, saved, or otherwise modified. (In the linked page, it is also converted to a gray-scale image.

An obvious enhancement possibility would be to add support for other image types, which I may do soon as I would also like to add the ability to fetch the resulting image as a PNG file instead of JPEG. So feel free to use and modify it as desired, and let me know if you come up with any useful mods.

/**
* Resize image to specific dimension, cropping as needed
* @return resource Resized image resource, or boolean false on failure
* @param string $imgFile Path to image to be resized
* @param int $width
* @param int $height
* @param string $error Error message
*/
function resize($imgFile, $width, $height, &$error = null)
{
   $attrs = @getimagesize($imgFile);
   if($attrs == false or $attrs[2] != IMG_JPEG)
   {
      $error = "Uploaded image is not JPEG or is not readable by this page.";
      return false;
   }
   if($attrs[0] * $attrs[1] > 3000000)
   {
      $error = "Max pixels allowed is 3,000,000. Your {$attrs[0]} x " .
               "{$attrs[1]} image has " . $attrs[0] * $attrs[1] . " pixels.";
      return false;
   }
   $ratio = (($attrs[0] / $attrs[1]) < ($width / $height)) ?
            $width / $attrs[0] : $height / $attrs[1];
   $x = max(0, round($attrs[0] / 2 - ($width / 2) / $ratio));
   $y = max(0, round($attrs[1] / 2 - ($height / 2) / $ratio));
   $src = imagecreatefromjpeg($imgFile);
   if($src == false)
   {
      $error = "Unknown problem trying to open uploaded image.";
      return false;
   }
   $resized = imagecreatetruecolor($width, $height);
   $result = imagecopyresampled($resized, $src, 0, 0, $x, $y, $width, $height,
             round($width / $ratio, 0), round($height / $ratio));
   if($result == false)
   {
      $error = "Error trying to resize and crop image.";
      return false;
   }
   else
   {
      return $resized;
   }
}

Expressing the Difference Between 2 Dates/Times

In an effort to consolidate some things I’ve posted on my site in a less organized manner, here is a reprint of a function I came up with a few years ago for expressing the difference between two UNIX timestamp values (such as returned from the time() and mktime() functions). The result is an array of years, months, weeks, days, hours, minutes, and seconds.


<?php
/**
* Get difference between timestamps broken down into years/months/weeks/etc.
* @return array
* @param int $t1 UNIX timestamp
* @param int $t2 UNIX timestamp
*/
function timeDiff($t1$t2)
{
   if($t1 $t2)
   {
      $time1 $t2;
      $time2 $t1;
   }
   else
   {
      $time1 $t1;
      $time2 $t2;
   }
   $diff = array(
      'years' => 0,
      'months' => 0,
      'weeks' => 0,
      'days' => 0,
      'hours' => 0,
      'minutes' => 0,
      'seconds' =>0
   );
   foreach(array('years','months','weeks','days','hours','minutes','seconds')
         as $unit)
   {
      while(TRUE)
      {
         $next strtotime("+1 $unit"$time1);
         if($next $time2)
         {
            $time1 $next;
            $diff[$unit]++;
         }
         else
         {
            break;
         }
      }
   }
   return($diff);
}

Here’s a sample usage:


<?php
$start strtotime('2007-01-15 07:35:55');
$end strtotime('2009-11-09 13:01:00');
$diff timeDiff($start$end);
$output "The difference is:";
foreach($diff as $unit => $value)
{
   echo " $value $unit,";
}
$output trim($output',');
echo $output;
?>

It would output:

The difference is: 2 years, 9 months, 3 weeks, 4 days, 5 hours, 25 minutes, 4 seconds

Undoing Magic Quotes

The often maligned (and rightfully so) magic_quotes_gpc “feature” of PHP can be problematic, especially if you are trying to develop scripts for general consumption on any platform. A brief example of the sort of problem it can cause is that if it is turned on and you do not undo its addition of back-slash escape characters, then if you apply a function such as mysql_real_escape_string() to prepare external data for use in a query, you will end up escaping the magic quotes backslashes and including them in the actual data.

To repair this potential “damage”, my solution is simply to test to see if the feature is turned on, and if it is, to recursively walk through the affected arrays, $_GET, $_POST, $_COOKIE (thus the “gpc”), via the array_walk_recursive() function. My function makes use of an “anonymous function” via the create_function() function. Then all that needs to be done in any script is to run the following function before otherwise using any of those three super-global arrays.

Continue reading “Undoing Magic Quotes”

Book Review: CodeIgniter 1.7 Professional Development

I was recently provided a review copy of CodeIgniter 1.7 Professional Development by Adam Griffith (Packt Publishing). It claims that it will help the reader “Become a CodeIgniter expert with professional tools, techniques and extended libraries.” As someone who has used CodeIgniter and found it to be very useful, I was looking forward to learning more and becoming a CI power user. However, I cannot say that my wish was fulfilled.

While some of the second half of the book introduced me to a few CI features I did not know about or at least had not yet used, most of the book was either about things I already knew or things I didn’t really care much about.

Most of the first half of the book essentially reiterated things you can find in the CI documentation, and that documentation is one of the strong points of CI. Also, some of the organization of the material was odd, such as detailing the image manipulation library before discussing a basic functionality such as session data handling. Some of the code samples seemed to be less than optimal as good examples of object-oriented PHP, such as the large switch/case block in the “Rest” class in Chapter 8.

My overall response to this book is therefore that it might be of use to intermediate-level PHP users who are new to CodeIgniter (with the caveat that it is not necessarily a good source for learning good OOP practices), but the experienced CodeIgniter user probably will find little in this book to make it worth purchasing. I’d probably only give it 2-1/2 stars out of 5.

Object Iteration in PHP 5

PHP 5 gives us the ability to iterate through objects much as we can with arrays, such as with the foreach() loop construct. I knew this ability existed but had not really looked into it or made use of it. However as a result of a thread at PHPBuilder.com, I thought this might be a good solution.

The key here is that while the default behavior of object iteration is to access each of the object’s public properties, you can override that behavior via the Iterator interface, defining custom methods to iterate what you specifically want from the object.

Continue reading “Object Iteration in PHP 5”