<?xml version="1.0" encoding="UTF-8"?> <rss
version="2.0"
xmlns:content="http://purl.org/rss/1.0/modules/content/"
xmlns:wfw="http://wellformedweb.org/CommentAPI/"
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:atom="http://www.w3.org/2005/Atom"
xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
><channel><title>Brandon Checketts &#187; PHP</title> <atom:link href="http://www.brandonchecketts.com/archives/category/php/feed" rel="self" type="application/rss+xml" /><link>http://www.brandonchecketts.com</link> <description>Web Programming, Linux System Administation, and other geeky stuff</description> <lastBuildDate>Fri, 06 Jan 2012 01:23:26 +0000</lastBuildDate> <language>en</language> <sy:updatePeriod>hourly</sy:updatePeriod> <sy:updateFrequency>1</sy:updateFrequency> <generator>http://wordpress.org/?v=3.3.1</generator> <item><title>Fix For Amazon API Error: Your request is missing required parameters. Required parameters include AssociateTag.</title><link>http://www.brandonchecketts.com/archives/fix-for-amazon-api-error-your-request-is-missing-required-parameters-required-parameters-include-associatetag</link> <comments>http://www.brandonchecketts.com/archives/fix-for-amazon-api-error-your-request-is-missing-required-parameters-required-parameters-include-associatetag#comments</comments> <pubDate>Thu, 03 Nov 2011 21:09:41 +0000</pubDate> <dc:creator>Brandon</dc:creator> <category><![CDATA[Amazon APIs]]></category> <category><![CDATA[PHP]]></category><guid
isPermaLink="false">http://www.brandonchecketts.com/?p=509</guid> <description><![CDATA[Users of Amazon&#8217;s Product Advertising API will begin seeing the following error as of about November 1st: Your request is missing required parameters. Required parameters include AssociateTag. This is due to changing requirements to the Product Advertising API. The AssociateTag parameter is now a required and validated field. You can see in the list of [...]]]></description> <content:encoded><![CDATA[<p>Users of Amazon&#8217;s Product Advertising API will begin seeing the following error as of about November 1st:</p><p>Your request is missing required parameters. Required parameters include AssociateTag.</p><p>This is due to changing requirements to the <a
href="https://affiliate-program.amazon.com/gp/advertising/api/detail/main.html">Product Advertising API</a>.  The AssociateTag parameter is now a required and validated field.  You can see in the <a
href="https://affiliate-program.amazon.com/gp/advertising/api/detail/api-changes.html">list of changes</a> that it is the first thing mentioned.</p><p>These changes are made to keep the Product Advertising API in line with its purpose of driving affiliate sales through the Amazon.com website.   The AssociateTag is a tag generated from your <a
href="https://affiliate-program.amazon.com/gp/associates/network/main.html">Amazon Associates account</a>.</p><p>So far, it looks like the tag is not entirely validated to your account.  I&#8217;ve had luck using fictitious tags such as <strong>aztag-20</strong>.</p> ]]></content:encoded> <wfw:commentRss>http://www.brandonchecketts.com/archives/fix-for-amazon-api-error-your-request-is-missing-required-parameters-required-parameters-include-associatetag/feed</wfw:commentRss> <slash:comments>0</slash:comments> </item> <item><title>KnitMeter.com Has Been Upgraded</title><link>http://www.brandonchecketts.com/archives/knitmeter-com-has-been-upgraded</link> <comments>http://www.brandonchecketts.com/archives/knitmeter-com-has-been-upgraded#comments</comments> <pubDate>Fri, 25 Mar 2011 03:06:47 +0000</pubDate> <dc:creator>Brandon</dc:creator> <category><![CDATA[PHP]]></category> <category><![CDATA[Programming]]></category> <category><![CDATA[Websites]]></category><guid
isPermaLink="false">http://www.brandonchecketts.com/?p=485</guid> <description><![CDATA[KnitMeter Has Been Upgraded KnitMeter.com was originally started over four years ago in December of 2007 as a small project that my wife thought would be useful. Since then, the site hasn&#8217;t changed much, but it has managed to grow to thousands of users who have knit nearly 20 thousand miles of yarn. I&#8217;ve received [...]]]></description> <content:encoded><![CDATA[<p><img
src="http://knitmeter.com/images/logo-50x50.png" width="50" height="50" alt="KnitMeter Logo" style="float:left;" /></p><h1 style="padding-left:80px;">KnitMeter Has Been Upgraded</h1><p><a
href="http://knitmeter.com/">KnitMeter.com</a> was originally started over four years ago in December of 2007 as a small project that my wife thought would be useful.  Since then, the site hasn&#8217;t changed much, but it has managed to grow to thousands of users who have knit nearly 20 thousand miles of yarn.  I&#8217;ve received numerous requests and have finally gotten a chance to impliment what many of you have been requesting for a while now.  New features on the site include:</p><ul
class="dots"><li>Users can now add entries for <strong>knitting</strong>, <strong>crocheting</strong>, and <strong>spinning</strong></li><li>Completely new and modernized design and logo</li><li>You can customize your widgets directly on KnitMeter.com rather than editing the code for the widget on your website</li><li>The website and the <a
href="http://apps.facebook.com/knitmeter/">KnitMeter Facebook Application</a> are now completely integrated.  Entries added in one will be displayed and counted in the other</li><li>The Facebook application can (again) publish your entries to your news feed, but only when you tell it to</li><li>You can chose to make your profile public, which will display some of the most recent entries on the KnitMeter home page with a link to your website</li><li>Added several new timeframes, including specific calendar years  (ie: I knit 4.3 miles in 2010)</li><li>Numerous technical changes that should make the site faster to use and make it easier to make future changes</li></ul><p>These new features have been rolled out over the past couple of weeks.  I appreciate the patience of those who have dealt with a few bugs over that time, and I believe that everything should be pretty bug-free now.  I encourage you to check out the new site and to start adding up the mileage for your own projects.   The next major milestone will be when we have gone through enough yarn to go around the earth (about 24,901 miles).  At the present rate, we should hit that figure in about 3-5 months.</p><p>Happy Knitting, Crocheting, and Spinning,<br
/> Brandon Checketts<br
/> <a
href="http://knitmeter.com/">KnitMeter.com</a></p> ]]></content:encoded> <wfw:commentRss>http://www.brandonchecketts.com/archives/knitmeter-com-has-been-upgraded/feed</wfw:commentRss> <slash:comments>0</slash:comments> </item> <item><title>Website Performance: Tables Versus CSS</title><link>http://www.brandonchecketts.com/archives/website-performance-tables-versus-css</link> <comments>http://www.brandonchecketts.com/archives/website-performance-tables-versus-css#comments</comments> <pubDate>Sat, 16 Oct 2010 21:00:18 +0000</pubDate> <dc:creator>Brandon</dc:creator> <category><![CDATA[General]]></category> <category><![CDATA[PHP]]></category> <category><![CDATA[Programming]]></category> <category><![CDATA[Website Performance]]></category> <category><![CDATA[Websites]]></category><guid
isPermaLink="false">http://www.brandonchecketts.com/?p=478</guid> <description><![CDATA[Most website designers have been using CSS for page layout for several years now, but I occasionally see some websites that continue to use HTML tables for layout. As I&#8217;ve been focusing on website performance lately, I&#8217;ve found some references that modern browsers render sites using tables for layout slower than they do sites that [...]]]></description> <content:encoded><![CDATA[<p>Most website designers have been using CSS for page layout for several years now, but I occasionally see some websites that continue to use HTML tables for layout.  As I&#8217;ve been focusing on website performance lately, I&#8217;ve found some references that modern browsers render sites using tables for layout slower than they do sites that use CSS.  I decided to investigate and confirmed that there are many possible situations where sites using large tables will appear to load much slower than those using CSS.  I put together two pages to confirm:</p><p><a
href="/book_samples/performance_divs.php" target="_blank">This page uses &lt;div&gt; elements for layout</a><br
/> and<br
/> <a
href="/book_samples/performance_tables.php" target="_blank">This pages uses a large table for layout</a></p><p>On both pages I&#8217;ve added a 5-second sleep near the end of the page to show what might happen if the server was slow, if there were network problems, or any other number of things may have happened.</p><p>Notice that the page created using a table changes a lot after the delay.  I&#8217;ve tried it in Firefox 3 which extends the main (yellow) content section all of the way to the right until it receives the rest of the document, at which point it has to shrink that part to make room for the section on the right.   Internet Explorer behaves even worse.  It leaves a blank white page until after the delay, at which point it draws the whole table.</p><p>By contrast, the page created with CSS positioning shows all of the content above the delay and has it in the correct position.  When the rest of the document is sent it just fills in the appropriate content, but doesn&#8217;t have to re-arrange anything on the page.</p> ]]></content:encoded> <wfw:commentRss>http://www.brandonchecketts.com/archives/website-performance-tables-versus-css/feed</wfw:commentRss> <slash:comments>0</slash:comments> </item> <item><title>Script to Import Static Pages into GetSimple CMS</title><link>http://www.brandonchecketts.com/archives/script-to-import-static-pages-into-getsimple-cms</link> <comments>http://www.brandonchecketts.com/archives/script-to-import-static-pages-into-getsimple-cms#comments</comments> <pubDate>Thu, 13 May 2010 04:30:52 +0000</pubDate> <dc:creator>Brandon</dc:creator> <category><![CDATA[General]]></category> <category><![CDATA[PHP]]></category> <category><![CDATA[Websites]]></category><guid
isPermaLink="false">http://www.brandonchecketts.com/?p=457</guid> <description><![CDATA[I&#8217;ve recently been impressed with a very simple Content Management System called GetSimple. It provides just the very basics that allows a user to edit their own website content. For brochure sites with owners who don&#8217;t want the complexity of a larger CMS, I think it is pretty ideal. When I develop a site though, [...]]]></description> <content:encoded><![CDATA[<p>I&#8217;ve recently been impressed with a very simple Content Management System called <a
href="http://get-simple.info/">GetSimple</a>.  It provides just the very basics that allows a user to edit their own website content.  For brochure sites with owners who don&#8217;t want the complexity of a larger CMS, I think it is pretty ideal.</p><p>When I develop a site though, I typically have a header and footer, and then all of the content pages exist as PHP files that simply include that header and footer.  Converting a static site like that into the CMS takes a bunch of copy/pasting.  I always try to avoid such tedious jobs, and so developed a script  that will import those static pages into a GetSimple installation.</p><p>To run this script, I wanted to import a bunch of files in a &#8216;static&#8217; directory where I had moved all of the static files to.  I then ran this from the command line to import all of the content into GetSimple</p><pre>
# for file in `find static -type f`
> do
> ./getsimple_import_file.php $file
> done
</pre><p>The script is available as <a
href="http://www.brandonchecketts.com/downloads/getsimple_import_file.php">getsimple_import_file.php</a></p><p>It takes a little configuration before running it.   It works by simulating the data that you would submit when creating the page through the web interface, so we have to fake the necessary session cookie.  Uncomment the bit in the middle that will display your cookie and run the script once.  You&#8217;ll need to copy your cookie name and value into the script before doing any actual imports.</p><p>Once you&#8217;ve done that, you will probably want to change the regular expression that attempts to grab the page title from your file.  You may also want to manipulate how it figures the URL to use.</p><p>Feel free to post comments here if  you found this useful, or made any changes  you&#8217;d like to share with other users</p> ]]></content:encoded> <wfw:commentRss>http://www.brandonchecketts.com/archives/script-to-import-static-pages-into-getsimple-cms/feed</wfw:commentRss> <slash:comments>9</slash:comments> </item> <item><title>Enabling HTTP Page Caching with PHP</title><link>http://www.brandonchecketts.com/archives/enabling-http-page-caching-with-php</link> <comments>http://www.brandonchecketts.com/archives/enabling-http-page-caching-with-php#comments</comments> <pubDate>Thu, 29 Apr 2010 16:54:30 +0000</pubDate> <dc:creator>Brandon</dc:creator> <category><![CDATA[PHP]]></category> <category><![CDATA[Programming]]></category> <category><![CDATA[Websites]]></category><guid
isPermaLink="false">http://www.brandonchecketts.com/?p=454</guid> <description><![CDATA[I&#8217;ve been doing a lot of work on BookScouter.com lately to reduce page load time and generally increase the performance of the website for both users and bots. One of the tips that the load time analyzer points out is to enable an expiration time for static content. That is easy enough for images and [...]]]></description> <content:encoded><![CDATA[<p>I&#8217;ve been doing a lot of work on <a
href="http://bookscouter.com/">BookScouter.com</a> lately to reduce page load time and generally increase the performance of the website for both users and bots.  One of the tips that the <a
href="https://addons.mozilla.org/en-US/firefox/addon/3371">load time analyzer</a> points out is to enable an expiration time for static content.  That is easy enough for images and such by using an Apache directive such as:</p><pre>
    ExpiresActive On
    ExpiresByType image/gif A2592000
    ExpiresByType image/jpg A2592000
    ExpiresByType image/png A2592000
</pre><p>But pages generated with PHP by default have the Pragma: no-cache header set, so that the users&#8217; browsers do not cache the content at all.  In most cases, even hitting the back button will generate another request to the server which must be completely processed by the script.  You may be able to cache some of the most intensive operations inside your script, but this solution will eliminate that request completely.  Simply add this code to the top of any page that contains semi-static content.  It effectively sets the page expiration time to one hour in the future.  So if a visitor hits the same URL within that hour, the page is served locally from their browser cache instead of making a trip to the server.  It also sends an HTTP 304 (Not Modified) response code if the user requests to reload the page within the specified time.  That may or may-not be desired based on your site.</p><pre>
$expire_time = 60*60; // One Hour
header('Expires: '.gmdate('D, d M Y H:i:s \G\M\T', time() + $expire_time));
header("Cache-Control: max-age={$expire_time}");
header('Last-Modified: '.gmdate('D, d M Y H:i:s \G\M\T', time()));
header('Pragma: public');

if ((!empty($_SERVER['HTTP_IF_MODIFIED_SINCE'])) &#038;&#038; (time() - strtotime($_SERVER['HTTP_IF_MODIFIED_SINCE']) < = $expire_time)) {
    header('HTTP/1.1 304 Not Modified');
    exit;
}
</pre></pre> ]]></content:encoded> <wfw:commentRss>http://www.brandonchecketts.com/archives/enabling-http-page-caching-with-php/feed</wfw:commentRss> <slash:comments>0</slash:comments> </item> <item><title>PHP Wrapper Class for a Read-only database</title><link>http://www.brandonchecketts.com/archives/php-wrapper-class-for-a-read-only-database</link> <comments>http://www.brandonchecketts.com/archives/php-wrapper-class-for-a-read-only-database#comments</comments> <pubDate>Tue, 05 Jan 2010 04:11:58 +0000</pubDate> <dc:creator>Brandon</dc:creator> <category><![CDATA[General]]></category> <category><![CDATA[Linux System Administration]]></category> <category><![CDATA[MySQL]]></category> <category><![CDATA[PHP]]></category> <category><![CDATA[Programming]]></category><guid
isPermaLink="false">http://www.brandonchecketts.com/?p=421</guid> <description><![CDATA[This is a pretty special case of a database wrapper class where I wanted to discard any updates to the database, but want SELECT queries to run against an alternative read-only database. In this instance, I have a planned outage of a primary database server, but would like the public-facing websites and web services to [...]]]></description> <content:encoded><![CDATA[<p>This is a pretty special case of a database wrapper class where I wanted to discard any updates to the database, but want SELECT queries to run against an alternative read-only database.  In this instance, I have a planned outage of a primary database server, but would like the public-facing websites and web services to remain as accessible as possible.</p><p>I wrote this quick database wrapper class that will pass all SELECT queries on to a local replica of the database, and silently discard any updates.   On this site almost all of the functionality still works, but it obviously isn&#8217;t saving and new information while the primary database is unavailable.</p><p>Here is my class.  This is intended as a wrapper to an ADOdb class, but it is generic enough that I think it would work for many other database abstraction functions as well.</p><pre>
class db_unavailable {
    var $readonly_db;

    function __construct($readonly_db)
    {
        $this->query_db = $readonly_db;
    }

    function query($sql)
    {
        $args = func_get_args();
        if (preg_match("#(INSERT INTO|REPLACE INTO|UPDATE|DELETE)#i", $args[0])) {
            // echo "Unable to do insert/replace/update/delete query: $sql\n";
            return true;
        } else {
            return call_user_func_array(array($this->readonly_db, 'query'), $args);
        }
    }

    function __call($function, $args)
    {
        return call_user_func_array(array($this->readonly_db, $function), $args);
    }
}
</pre><p>I simply create my $query_db object that points to the read-only database.  Then create my main $db object as a new db_unavailable() object.  Any select queries against $db will behave as they normally do, and data-modifying queries will be silently discarded.</p> ]]></content:encoded> <wfw:commentRss>http://www.brandonchecketts.com/archives/php-wrapper-class-for-a-read-only-database/feed</wfw:commentRss> <slash:comments>0</slash:comments> </item> <item><title>LUG Presentation on SQL Basics</title><link>http://www.brandonchecketts.com/archives/lug-presentation-on-sql-basics</link> <comments>http://www.brandonchecketts.com/archives/lug-presentation-on-sql-basics#comments</comments> <pubDate>Fri, 18 Dec 2009 03:52:59 +0000</pubDate> <dc:creator>Brandon</dc:creator> <category><![CDATA[General]]></category> <category><![CDATA[LUG]]></category> <category><![CDATA[MySQL]]></category> <category><![CDATA[PHP]]></category> <category><![CDATA[Programming]]></category><guid
isPermaLink="false">http://www.brandonchecketts.com/?p=416</guid> <description><![CDATA[I gave a presentation tonight at my local Linux Users Group meeting on SQL Basics. I had a fun time preparing the presentation and made up a bunch of examples having to do with Santa&#8217;s database. It started out with a simple table for kids who were either naughty or nice. We then added some [...]]]></description> <content:encoded><![CDATA[<p>I gave a presentation tonight at my local <a
href="http://www.uga.edu/chugalug/">Linux Users Group</a> meeting on SQL Basics.   I had a fun time preparing the presentation and made up a bunch of examples having to do with Santa&#8217;s database.</p><p>It started out with a simple table for kids who were either naughty or nice.  We then added some reports to that.   Then imported kids&#8217; wish lists from CSV files.  From there we were able to generate some manufacturing reports for the workshop.</p><p>When we joined the wish list table with the kids table, we were then able to generate a sleigh-loading report which included only gifts for kids who had been good.   Then we got even more complicated and introduced several joins with some complicated mathematics to select gifts for kids within a certain radius from a given zip code.</p><p>The presentation is <a
href="/downloads/CHUGALUG Chrsitmas SQL.ppt">available for download here</a>.  And Brian recorded part of the presentation which is available to view <a
href="http://www.ustream.tv/recorded/3205751">on uStream.tv</a> or here. (We&#8217;re still experimenting with getting the video recording set up correctly)</p><p><object
classid="clsid:d27cdb6e-ae6d-11cf-96b8-444553540000" width="480" height="386" id="utv528934" name="utv_n_851113"><param
name="flashvars" value="loc=%2F&amp;autoplay=false&amp;vid=3205751" /><param
name="allowfullscreen" value="true" /><param
name="allowscriptaccess" value="always" /><param
name="src" value="http://www.ustream.tv/flash/video/3205751" /><embed
flashvars="loc=%2F&amp;autoplay=false&amp;vid=3205751" width="480" height="386" allowfullscreen="true" allowscriptaccess="always" id="utv528934" name="utv_n_851113" src="http://www.ustream.tv/flash/video/3205751" type="application/x-shockwave-flash" /></object></p> ]]></content:encoded> <wfw:commentRss>http://www.brandonchecketts.com/archives/lug-presentation-on-sql-basics/feed</wfw:commentRss> <slash:comments>0</slash:comments> </item> <item><title>PHP Code to Sign any Amazon API Requests</title><link>http://www.brandonchecketts.com/archives/php-code-to-sign-any-amazon-api-requests</link> <comments>http://www.brandonchecketts.com/archives/php-code-to-sign-any-amazon-api-requests#comments</comments> <pubDate>Wed, 01 Jul 2009 04:30:11 +0000</pubDate> <dc:creator>Brandon</dc:creator> <category><![CDATA[General]]></category> <category><![CDATA[Linux System Administration]]></category> <category><![CDATA[PHP]]></category> <category><![CDATA[Programming]]></category><guid
isPermaLink="false">http://www.brandonchecketts.com/?p=378</guid> <description><![CDATA[Starting next month, any requests to the Amazon Product Advertising API need to be cryptographically signed. Amazon has given about three months notice and the deadline is quickly approaching. I use the Amazon web services on several sites and came up a fairly generic way to convert an existing URL to a signed URL. I&#8217;ve [...]]]></description> <content:encoded><![CDATA[<p>Starting next month, any requests to the Amazon Product Advertising API need to be cryptographically signed.  Amazon has given about three months notice and the deadline is quickly approaching.  I use the Amazon web services on several sites and came up a fairly generic way to convert an existing URL to a signed URL.  I&#8217;ve tested with several sites and a variety of functions, and this is working well for me so far:</p><pre>
function signAmazonUrl($url, $secret_key)
{
    $original_url = $url;

    // Decode anything already encoded
    $url = urldecode($url);

    // Parse the URL into $urlparts
    $urlparts       = parse_url($url);

    // Build $params with each name/value pair
    foreach (split('&#038;', $urlparts['query']) as $part) {
        if (strpos($part, '=')) {
            list($name, $value) = split('=', $part, 2);
        } else {
            $name = $part;
            $value = '';
        }
        $params[$name] = $value;
    }

    // Include a timestamp if none was provided
    if (empty($params['Timestamp'])) {
        $params['Timestamp'] = gmdate('Y-m-d\TH:i:s\Z');
    }

    // Sort the array by key
    ksort($params);

    // Build the canonical query string
    $canonical       = '';
    foreach ($params as $key =&gt; $val) {
        $canonical  .= "$key=".rawurlencode(utf8_encode($val))."&#038;";
    }
    // Remove the trailing ampersand
    $canonical       = preg_replace("/&#038;$/", '', $canonical);

    // Some common replacements and ones that Amazon specifically mentions
    $canonical       = str_replace(array(' ', '+', ',', ';'), array('%20', '%20', urlencode(','), urlencode(':')), $canonical);

    // Build the sign
    $string_to_sign             = "GET\n{$urlparts['host']}\n{$urlparts['path']}\n$canonical";
    // Calculate our actual signature and base64 encode it
    $signature            = base64_encode(hash_hmac('sha256', $string_to_sign, $secret_key, true));

    // Finally re-build the URL with the proper string and include the Signature
    $url = "{$urlparts['scheme']}://{$urlparts['host']}{$urlparts['path']}?$canonical&#038;Signature=".rawurlencode($signature);
    return $url;
}
</pre><p>To use it, just wrap your Amazon URL with the signAmazonUrl() function and pass it your original string and secret key as arguments.  As an example:</p><pre>
$xml = file_get_contents('http://webservices.amazon.com/onca/xml?some-parameters');
</pre><p>becomes</p><pre>
$xml = file_get_contents(signAmazonUrl('http://webservices.amazon.com/onca/xml?some-parameters', $secret_key));
</pre><p>Like most all of the variations of this, it does require the hash functions be installed to use the <a
href="http://us3.php.net/hash_hmac">hash_hmac()</a> function.  That function is generally available in PHP 5.1+.  Older versions will need to install it with Pecl.  I tried using a couple of versions that try to create the Hash in pure PHP code, but none worked and installing it via Pecl was pretty simple.</p><p>(Note that I&#8217;ve slightly revised this code a couple of times to fix small issues that have been noticed)</p> ]]></content:encoded> <wfw:commentRss>http://www.brandonchecketts.com/archives/php-code-to-sign-any-amazon-api-requests/feed</wfw:commentRss> <slash:comments>19</slash:comments> </item> <item><title>Array versus String in CURLOPT_POSTFIELDS</title><link>http://www.brandonchecketts.com/archives/array-versus-string-in-curlopt_postfields</link> <comments>http://www.brandonchecketts.com/archives/array-versus-string-in-curlopt_postfields#comments</comments> <pubDate>Fri, 29 May 2009 17:53:04 +0000</pubDate> <dc:creator>Brandon</dc:creator> <category><![CDATA[General]]></category> <category><![CDATA[PHP]]></category> <category><![CDATA[Programming]]></category><guid
isPermaLink="false">http://www.brandonchecketts.com/?p=362</guid> <description><![CDATA[The PHP Curl Documentation for CURLOPT_POSTFIELDS makes this note: This can either be passed as a urlencoded string like &#8216;para1=val1&#038;para2=val2&#038;&#8230;&#8217; or as an array with the field name as key and field data as value. If value is an array, the Content-Type header will be set to multipart/form-data. I&#8217;ve always discounted the importance of that, [...]]]></description> <content:encoded><![CDATA[<p>The <a
href="http://us2.php.net/curl_setopt">PHP Curl Documentation</a> for CURLOPT_POSTFIELDS makes this note:</p><blockquote><p> This can either be passed as a urlencoded string like &#8216;para1=val1&#038;para2=val2&#038;&#8230;&#8217; or as an array with the field name as key and field data as value. If value  is an array, the Content-Type header will be set to multipart/form-data.</p></blockquote><p>I&#8217;ve always discounted the importance of that, and in most cases it doesn&#8217;t generally matter.  The destination server and application likely know how to deal with both multipart/form-data and application/x-www-form-urlencoded equally well.  However, the data is passed in a much different way using these two different mechanisms.</p><h3>application/x-www-form-urlencoded</h3><p>application/x-www-form-urlencoded is what I generally think of when doing POST requests.  It is the default when you submit most forms on the web. It works by appending a blank line and then your urlencoded data to the end of the POST request.  It also sets the Content-Length header to the length of your data.   A request submitted with application/x-www-form-urlencoded looks like this (somewhat simplified):</p><pre>
POST /some-form.php HTTP/1.1
Host: www.brandonchecketts.com
Content-Length: 23
Content-Type: application/x-www-form-urlencoded

name=value&#038;name2=value2
</pre><h3>multipart/form-data</h3><p>multipart/form-data is much more complicated, but more flexible.  Its flexibility is required when uploading files.   It works in a manner similar to MIME types.  The HTTP Request looks like this (simpified):</p><pre>
POST / HTTP/1.1
Host: www.brandonchecketts.com
Content-Length: 244
Expect: 100-continue
Content-Type: multipart/form-data; boundary=----------------------------26bea3301273
</pre><p>And then subsequent packets are sent containing the actual data.  In my simple case with two name/value pairs, it looks like this:</p><pre>
HTTP/1.1 100 Continue
------------------------------26bea3301273
Content-Disposition: form-data; name="name"

value
------------------------------26bea3301273
Content-Disposition: form-data; name="name2"

value2
------------------------------26bea3301273--
</pre><h3>CURL usage</h3><p>So, when sending POST requests in PHP/cURL, it is important to urlencode it as a string first.</p><p>This will generate the multipart/form-data version</p><pre>
$data = array('name' => 'value', 'name2' => 'value2');
curl_setopt($curl_object, CURLOPT_POSTFIELDS,  $data)
</pre><p>And this simple change will ensure that it uses the application/x-www-form-urlencoded version:</p><pre>
$data = array('name' => 'value', 'name2' => 'value2');
$encoded = '';
foreach($data as $name => $value){
    $encoded .= urlencode($name).'='.urlencode($value).'&#038;';
}
// chop off the last ampersand
$encoded = substr($encoded, 0, strlen($encoded)-1);
curl_setopt($curl_object, CURLOPT_POSTFIELDS,  $encoded)
</pre>]]></content:encoded> <wfw:commentRss>http://www.brandonchecketts.com/archives/array-versus-string-in-curlopt_postfields/feed</wfw:commentRss> <slash:comments>3</slash:comments> </item> <item><title>KnitMeter is now a Facebook App</title><link>http://www.brandonchecketts.com/archives/knitmeter-is-now-a-facebook-app</link> <comments>http://www.brandonchecketts.com/archives/knitmeter-is-now-a-facebook-app#comments</comments> <pubDate>Fri, 29 May 2009 15:04:24 +0000</pubDate> <dc:creator>Brandon</dc:creator> <category><![CDATA[MySQL]]></category> <category><![CDATA[PHP]]></category> <category><![CDATA[Programming]]></category> <category><![CDATA[Websites]]></category><guid
isPermaLink="false">http://www.brandonchecketts.com/?p=360</guid> <description><![CDATA[KnitMeter.com is a site that I wrote quickly for my wife to keep track of how much she has knit. It generate a little &#8216;widget&#8217; image that can be placed on blogs, forums, etc and says how many miles of yarn you have knit in some period. The site has been live for about a [...]]]></description> <content:encoded><![CDATA[<p><a
href="http://knitmeter.com/">KnitMeter.com</a> is a site that I wrote quickly for my wife to keep track of how much she has knit.  It generate a little &#8216;widget&#8217; image that can be placed on blogs, forums, etc and says how many miles of yarn you have knit in some period.  The site has been live for about a year and a half now and has a couple thousand registered users.</p><p>I have been receiving an increasing number of requests to add a method for adding a KnitMeter it to Facebook.  I&#8217;ve experimented with a couple of other ideas on Facebook and found that it was pretty straightforward to write an app.   KnitMeter seems like a decent candidate for a social app, so I started working on it about a week ago.  And I&#8217;m happy to say that I just made the application live late last night.  It is available at <a
href="http://apps.facebook.com/knitmeter/">http://apps.facebook.com/knitmeter/</a>.</p><p>Features include:</p><ul><li>Ability to add projects and add knitted lengths to a project (or not)</li><li>Settings for inputting lengths in feet, yards, or meters</li><li>Display how much you&#8217;ve knit in feet, yards, meters, kilometers, or miles</li><li>When entering a new length, you can choose to have it publish a &#8216;story&#8217; on your profile page</li><li>You can add a tab on your profile page that shows each of your projects as well as a total</li><li>You can add a KnitMeter &#8216;box&#8217; to the side of your profile page, or on your &#8216;boxes&#8217; tab.</li></ul><p>I recreated the database from scratch and defined it a little better, so I have a little bit of work to do in migrating the existing site and database over to the new structure.  Once that is done users will be able to import their data from the existing KnitMeter.com by providing their email/password.</p> ]]></content:encoded> <wfw:commentRss>http://www.brandonchecketts.com/archives/knitmeter-is-now-a-facebook-app/feed</wfw:commentRss> <slash:comments>3</slash:comments> </item> </channel> </rss>
<!-- Performance optimized by W3 Total Cache. Learn more: http://www.w3-edge.com/wordpress-plugins/

Minified using disk
Page Caching using disk (user agent is rejected)
Database Caching 8/17 queries in 1.086 seconds using disk

Served from: www.brandonchecketts.com @ 2012-02-04 02:24:41 -->
