Re-ordering Core Data Objects on iOS4

The Core Data framework on the iPhone is incredibly powerful. It’s also incredibly efficient and part of that is because a collection of objects only have the order that you implicitly give them. For example you typically might give an Event object a timestamp and when you pull out all the events you might sort on that timestamp.

The NSFetchedResultsController is the main power house when dealing with such a scenario and is great for the master part of a master/detail data relationship. Its main purpose is to manage the results returned from a fetch request similar to the above and provide data for a UITableView via delegate methods. It reacts on the model level so if you delete an Event object, the NSFetchedResultsController informs its delegate and so updates the UITableView automatically. It’s very clever indeed!

As I found out earlier yesterday, the problem comes when you want to re-order the objects in a user-defined way. Instead of sorting on a timestamp, I wanted the user to be able to specify that one object should occur before the other… I’m working on an app that lets you place waypoints down on a map. Timestamps in waypoints aren’t much use. It’s much more critical that they have a specific order.

After some Googling I came across a useful article on CocoaIsMyGirlfriend. This helped me 90% of the way but I had problems when re-ordering. When you re-order the objects, the UITableView would move cells about seemingly at random. This is because NSFetchedResultsController is model-driven. When you re-order something using the tableview methods the view is already correct (because you’ve dragged and dropped the cell there – it’s a user-driven change) and so when the delegate detects your index changes, it walks all over your view believing the cells to be in their original position. The trick is to ‘disable’ the UI updates with a boolean in your delegate methods. Set the boolean just before your re-indexing and unset it afterwards.

For an example, see this stack overflow link on re-ordering.

Also have a look at what the Apple docs say on user-driven updates on the NSFetchedResultsController.

Installing Xdebug on Mac OS X

Xdebug is an incredibly powerful PHP extension that helps you debug scripts by providing a lot of valuable debugging information. It saves you from having to write your own debugging function for catching errors, at least during the development stage of a web application and certainly provides a lot more information than the standard PHP error messages!

Xdebug also provides the following: –

  • Stack traces and function traces in error messages with:
    • Full parameter display for user defined functions
    • Function name, file name and line indications
  • Support for member functions
  • Memory allocation
  • Protection for infinite recursions
  • Profiling information for PHP scripts
  • Code coverage analysis
  • Capabilities to debug your scripts interactively with a debug client

From the above you can see it’s a very powerful tool that every web developer should have installed on his or her machine and is in-fact included with quite a few commercial IDE programs. Surprisingly, Xdebug is actually open-source, so without further ado… I’ll show you how you can easily install it on your Apple Mac using pre-built binaries

Equipment

This tutorial assumes you have the following already set up: –

  • Apple Mac OS 10.4
  • Apache (Using Apple’s version that came with OS X)
  • PHP 5 Module (I use PHP 5 from www.entropy.ch)
  • Some PHP files you can test and debug with

Instructions

Xdebug doesn’t provide any pre-built binaries for Mac OS X, which means we would have to download the source code and compile Xdebug ourselves. Luckily a commercial IDE called Komodo IDE (made by ActiveState who you might remember as the company that makes Perl for Windows), distributes Xdebug with their program and have kindly made their Xdebug binaries available for download. Navigate to the remote debugging page on their website and click on the PHP Remote Debugging option. Make sure you choose Mac OS X / x86 if you have an Intel Mac.
Once downloaded, extract the contents and click on the folder corresponding to your PHP version (I chose 5.2). You should see a single file called xdebug.so. This is our PHP extension… drag it into your user folder.

Now we need to copy the extension into our PHP extensions folder. Drop into the Terminal application and if you used the Entropy PHP 5 extension, you’ll find the PHP folder at /usr/local/php5. The extensions folder is in lib/php/extensions.

At the terminal type:

cd /usr/local/php5/lib/php/extensions

List the contents and you should see a folder called no-debug-non-zts-20060613 or similar, change directory into here. We’ll now move the xdebug.so file into this folder and rename it xdebug. Note: You’ll get prompted for your password since we’re editing system files.

ls
cd no-debug-non-zts-20060613
sudo mv ~/xdebug.so xdebug

Nearly there, we now need to create an .ini file to tell PHP to load in the extension. Change directory to /usr/local/php5/php.d and using vi or your favourite editor create a file called 80-extension-xdebug.ini. Note: You’ll get prompted for your password since we’re editing system files.

cd /usr/local/php5/php.d
sudo vi 80-extension-xdebug.ini

Copy and paste the following into the text file you’ve just created, adjusting the path to where your extensions directory is located.

[xdebug]
zend_extension="/usr/local/php5/lib/php/extensions/no-debug-non-zts-20060613/xdebug"

If you have TextMate, you can add the following line to the config file. This makes clickable error messages that load up the offending PHP file in TextMate and jump to the line containing the error. This is very handy indeed!

xdebug.file_link_format = "txmt://open?url=file://%f&line=%l"

Once your ready to save the config file, close vi by typing ‘:x’ followed by the return key. Restart Apache using your favourite method or simply reboot the whole machine.
Test your new Xdebug configuration by creating a PHP file, which obviously has an error in it such as calling a function that doesn’t exist. Test the PHP file and you should see a lovely coloured error message with a stack trace! You’re all ready to go!

Extras

If you’re interested in getting the most out of Xdebug, I recommend checking out some of the documentation on the Xdebug site. Of particular interest is using the profiler and the basics, which are always good to master.

Problem with PHP mail() and Additional Headers

With the PHP mail() function, you can specify additional headers for the emails that you send. This is a very powerful feature, which lets you do things such as add addresses to blind carbon copy or specify which email address the email is coming from.

It’s great but the PHP manual says this about additional headers: –

additional_headers (optional)

String to be inserted at the end of the email header.

This is typically used to add extra headers (From, Cc, and Bcc). Multiple extra headers should be separated with a CRLF (\r\n).

Yes, so according to the manual multiple headers should be separated with CRLF (\r\n). However, if you try this on a Linux web server (sample code provided below) you will probably get some of your headers stuck in the body of the email! There is a quick and easy solution though…

// Recipient
$to = '[email protected]';

// Subject of email
$subject = 'Message from Eddie';

// Message body
$message = 'Hi there, this is Eddie, and I\'m feeling just
great, guys, and I know I\'m just going to get a bundle of kicks out of any
programme you care to run through me';

// Additional headers
$headers = 'To: [email protected]' . "\r\n";
$headers .= 'From: [email protected]' . "\r\n";

// Mail it
if(mail($to, $subject, $message, $headers)) {
echo 'Email sent';
} else {
	echo 'Email not sent';
}

Apparently on Linux web servers, it’s best to use LF (\n) line endings for separating headers instead. This can be done two ways. The first way is to alter the server’s sendmail path in PHP.ini file to first push the email through dos2unix (which converts the line endings automatically) and then pipe it to send mail.

sendmail_path = "/usr/bin/dos2unix | /usr/sbin/sendmail -t -i"

The other option is to alter your PHP code so that instead of appending the line endings on as strings use the PHP_EOL constant which was introduced in PHP 5.0.2. Echoing PHP_EOL on a Windows server will result in “\r\n” whilst echoing the constant on a Linux server will result in “\n”… which in my opinion is a more elegant solution. :)

The Secret to cURL in PHP on Windows…

cURL is a great library created by Daniel Stenberg, that allows you to connect and communicate to many different types of servers using many different types of protocols. In particular, it’s used heavily in PHP to communicate to Payment Gateways and fetch XML feeds from other sites whilst being ‘transparent’ to web page visitors.

The particular secret I would like to share involves establishing connections to secure sites (SSL-enabled ones in particular). When you browse to an SSL–enabled site in your web browser, a few things happen… One of the things that happen is that your browser checks to see if the site’s security certificate is trusted. It does this by checking the entity that signed the certificate against it’s built in book of trusted signatures and if it finds a match, onto the next step. However, if your browser can’t find a match the certificate will be invalid and it will complain that the site could potentially be a fake or insecure.

The ‘book of trusted signatures’ is known as a Certificate Authority bundle and usually comes built in with most web browsers. If you install cURL (the standalone version that can be run from the command–line), chances are it will come with the cURL Certificate Authority bundle and you won’t need to do a thing as the cURL functions within PHP will use this as it’s book of trusted signatures. However, on Windows the cURL functions within PHP are pre–built and included in the standard PHP setup, thus do not include this bundle. Chances are if you don’t know this you’ll probably spend a good amount of your time screaming at your webpage as it mocks you with error number 60! I know I spent quite a good few hours wondering why it worked on my Linux PC but not on the Windows server!

CURL Error 60: SSL certificate problem, verify that the CA cert is OK.
Details: error:14090086:SSL routines
SSL3_GET_SERVER_CERTIFICATE:certificate verify failed

Luckily the fix is quite easy…

  1. Download standalone cURL for Windows (make sure it is the SSL version).
    Download the .pem file from the cURL site and rename the extension to .crt
  2. Extract curl-ca-bundle.crt from the download and copy to your web server folder.
  3. Add the following line to your code: –
    curl_setopt($ch, CURLOPT_CAINFO, "c:/path/to/ca-bundle.crt");
  4. Remember to change $ch to the variable you’ve assigned your curl connection to and “c:/path/to/ca-bundle.crt” to the location of where you have copied the ca-bundle.crt.
  5. Check the server has permission to read this file.

If you are getting started with cURL, here is some sample code I’ve written that should get you started. It outputs the contents of the secure server to a string, which is echoed out to your page.

// Set up cURL connection
$url = 'https://www.verisign.com/';
$ca = 'c:/path/to/ca-bundle.crt';
$ch = curl_init();

// Apply various settings
curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt($ch, CURLOPT_HEADER, 0); // Don’t return the header, just the html
curl_setopt($ch, CURLOPT_CAINFO, $ca); // Set the location of the CA-bundle
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1); // Return contents as a string

$result = curl_exec ($ch);
curl_close($ch);
echo $result;

That’s it! You should now be able to connect successfully to SSL-enabled websites using the cURL functions of PHP on your Windows server.

UPDATE 2010/08/20: Apparently the certificates aren’t shipped with the archived versions any more. To get the latest certificate bundle that’s been extracted from the Mozilla browser you can download the .pem file from the cURL site and rename the extension to .crt.

Validating Credit Card Numbers

Lately, I’ve been working on an e–commerce website and discovered a handy algorithm for validating card numbers. The Luhn algorithm (also known as mod 10) is a checksum formula and is used to protect against accidental errors rather than malicious attacks.

The algorithm is particularly useful for checking to see if the card number ‘looks’ right before sending it off to the payment provider for processing. This reduces the amount of rejected card payments, which is always a good thing. :)

More details of how the algorithm works can be found on Wikipedia and my annotated PHP implementation can be found below.

/* PHP function for validating card numbers */
function checkLuhn($cardNumber) {
    // Copyright (c) Richard Warrender. Licenced under the LGPL.
    // https://richardwarrender.com//

    // Get total amount of digits to process
    $digitCount = strlen((String) $cardNumber);
    // Checksum must be zero to begin with
    $checksum = 0;

    // Loop round card number extracting digits
    for($i = 1; $i<=$digitCount; $i++) {
            // Extract digit number
            $digits[$i] = (int) substr($cardNumber, -$i, 1);

            // Check to see if this the luhn number, we need to double it
            if(($i%2) == 0) {
                    // Double luhn digit
                    $digit = $digits[$i] * 2;

                    // If greater or equal to 10, then use sum of digits
                    if($digit >= 10) {
                            // Get first digit
                            $firstDigit = substr($digit, 0, 1);
                            // Get second digit
                            $secondDigit = substr($digit, 1, 1);
                            /// Add together and replace original luhn digit
                            $digit = $firstDigit + $secondDigit;
                    }

                    // Reload back into array
                    $digits[$i] = $digit;
            }
            // Keep a running total for use in checksum
            $checksum += $digits[$i];
    }

    if(($checksum % 10) == 0) {
            return true;
    } else {
            return false;
    }
}