<?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/"
xmlns:series="http://unfoldingneurons.com/"
><channel><title>Larry Ullman &#187; e-commerce</title> <atom:link href="http://www.larryullman.com/tag/e-commerce/feed/" rel="self" type="application/rss+xml" /><link>http://www.larryullman.com</link> <description>Translating Geek Into English</description> <lastBuildDate>Mon, 21 May 2012 11:03:07 +0000</lastBuildDate> <language>en</language> <sy:updatePeriod>hourly</sy:updatePeriod> <sy:updateFrequency>1</sy:updateFrequency> <item><title>Speaking at 2012 Turkey e-Commerce Conference &amp; Expo</title><link>http://www.larryullman.com/2012/03/26/speaking-at-2012-turkey-e-commerce-conference-expo/</link> <comments>http://www.larryullman.com/2012/03/26/speaking-at-2012-turkey-e-commerce-conference-expo/#comments</comments> <pubDate>Mon, 26 Mar 2012 11:25:57 +0000</pubDate> <dc:creator>Larry</dc:creator> <category><![CDATA[Web Development]]></category> <category><![CDATA[e-commerce]]></category> <category><![CDATA[ecom]]></category> <category><![CDATA[speak]]></category> <category><![CDATA[travel]]></category><guid
isPermaLink="false">http://www.larryullman.com/?p=3065</guid> <description><![CDATA[On May 30, 2012, I&#8217;ll be speaking at the e-Commerce Conference and Expo in Istanbul, Turkey (note: the linked site is in Turkish, but if you view it in Google Chrome, for example, it will translate the pages for you). This is a one-day event, from 9:30 am until 5:00 pm. From 1:40 to 2:25, I&#8217;ll [...]]]></description> <content:encoded><![CDATA[<p>On May 30, 2012, I&#8217;ll be speaking at the <a
href="http://e-commerceexpo.com/">e-Commerce Conference and Expo</a> in Istanbul, Turkey (note: the linked site is in Turkish, but if you view it in Google Chrome, for example, it will translate the pages for you). This is a one-day event, from 9:30 am until 5:00 pm. From 1:40 to 2:25, I&#8217;ll be presenting &#8220;Creating a Successful E-commerce Venture, or Failing Gracefully&#8221; as the conference&#8217;s technology session. At the end of this post is the presentation&#8217;s description.</p><p>If you&#8217;re in Turkey specifically, or nearby, I&#8217;d recommend you attend. And if anyone has any recommendations as to what I should do while I&#8217;m in Istanbul, please let me know!</p><p><span
id="more-3065"></span>The sad fact is that most online ventures, particularly e-commerce ones, will fail. It is irresponsible to go into a new project without being aware of that fact, and without acknowledging that the same fate could befall you or your organization. But it is exactly by recognizing the possibility, if not likelihood, of failure, that you better your chance of success. Or, if success is not to be, then the odds of failing without being crippled by the experience.</p><p>In this speech, writer and Web development expert Larry Ullman presents his best advice for succeeding in your e-commerce ventures. The speech begins with the big picture of what e-commerce is, in all its facets, and puts forth a healthy and prosperous perspective that you should have when starting a new project. The speech then goes into making the right, smart technical decisions, before concluding with case studies from Larry&#8217;s own experiences.</p><p>Some of the specific points covered include:<br
/> • Establishing project goals<br
/> • Allowing a site to expand organically<br
/> • Understanding and enforcing security<br
/> • Avoiding the common causes of failure</p><p>Whether you&#8217;re looking to create or expand an online extension of a conventional business, or are dreaming of creating the next Amazon, you&#8217;re sure to hear lots of practical, specific, and real-world advice in this speech.</p> ]]></content:encoded> <wfw:commentRss>http://www.larryullman.com/2012/03/26/speaking-at-2012-turkey-e-commerce-conference-expo/feed/</wfw:commentRss> <slash:comments>2</slash:comments> </item> <item><title>Using PayPal&#8217;s WebSite Payments Pro with &#8220;Effortless E-Commerce with PHP and MySQL&#8221;</title><link>http://www.larryullman.com/2012/03/07/using-paypals-website-payments-pro-with-effortless-e-commerce-with-php-and-mysql/</link> <comments>http://www.larryullman.com/2012/03/07/using-paypals-website-payments-pro-with-effortless-e-commerce-with-php-and-mysql/#comments</comments> <pubDate>Wed, 07 Mar 2012 15:25:15 +0000</pubDate> <dc:creator>Larry</dc:creator> <category><![CDATA[MySQL]]></category> <category><![CDATA[PHP]]></category> <category><![CDATA[Web Development]]></category> <category><![CDATA[e-commerce]]></category> <category><![CDATA[ecom]]></category> <category><![CDATA[paypal]]></category><guid
isPermaLink="false">http://www.larryullman.com/?p=3132</guid> <description><![CDATA[In Part 3 of my &#8220;&#8221; book, I use Authorize.net to process payments for a site that sells physical goods. Authorize.net accepts credit cards and can be directly integrated into your site, so that the customer never leaves (unlike, for example, PayPal&#8217;s Website Payments Standard, used in Part 2 of the book, which goes through [...]]]></description> <content:encoded><![CDATA[<p>In Part 3 of my &#8220;<a
href="http://www.larryullman.com/books/effortless-e-commerce-with-php-and-mysql/">Effortless E-Commerce with PHP and MySQL</a>&#8221; book, I use <a
href="http://www.authorize.net/">Authorize.net</a> to process payments for a site that sells physical goods. Authorize.net accepts credit cards and can be directly integrated into your site, so that the customer never leaves (unlike, for example, PayPal&#8217;s Website Payments Standard, used in Part 2 of the book, which goes through PayPal&#8217;s site). The code in the book was written in a very modular style, with the intent that you can use the components you need, and swap others in and out. A reader specifically wanted to know how you would use PayPal&#8217;s Website Payments Pro instead of Authorize.net, and that&#8217;s what I&#8217;ll explain here.<span
id="more-3132"></span></p><p>PayPal&#8217;s Website Payments Pro provides two APIs for processing payments: <em>Direct Payment</em> and <em>Express Checkout</em>. Both allow you to accept debit and credit cards (the specific cards will differ slightly from one region to the next), while Express Checkout also allows users to pay with their PayPal account. In both cases, the customer never leaves your site, unlike when using PayPal&#8217;s Website Payments Standard. PayPal does require you to use both APIs in order to use Website Payments Pro. To keep this post from getting too long, I&#8217;ll only address the Direct Payment, which most easily correlates to the Authorize.net code in the book. If you need help with the Express Checkout aspect, let me know.</p><p>To understand how to use Website Payments Pro instead of Authorize.net for the second example, let&#8217;s first look at how Authorize.net is used. The customer begins the checkout process on <strong>checkout.php</strong>. This script takes and validates the user&#8217;s shipping information. Upon successful validation, the user is redirected to <strong>billing.php</strong>, which takes and validates the billing information, including the credit card. Upon successful validation, the payment is processed by including two scripts: <strong>gateway_setup.php</strong> and <strong>gateway_process.php</strong>. For extra security, these two files are stored in a private folder outside of the Web root directory.</p><p>Within<strong> gateway_setup.php</strong>, a bunch of parameters are set within an array named <strong>$data</strong>:</p><pre class="brush: php; title: ; notranslate">&lt;?php
$data = array();
$data['x_type'] = 'AUTH_ONLY';
$data['x_card_num'] = $cc_number;
$data['x_exp_date'] = $cc_exp;
// etc. </pre><p>Then the <strong>gateway_process.php</strong> script adds some more details to the array:</p><pre class="brush: php; title: ; notranslate">// Your account info:
$data['x_login'] = '75sqQ96qHEP8';
$data['x_tran_key'] = '7r83Sb4HUd58Tz5p';
// etc. </pre><p>Finally, <strong>gateway_process.php</strong> converts that data into a useable format for the <a
href="http://curl.haxx.se/">cURL</a> request, performs the cURL request, and reads the response into the <strong>$response</strong> variable. Finally, this variable is converted into an array:</p><pre class="brush: php; title: ; notranslate">$response_array = explode($data[&quot;x_delim_char&quot;],$response);</pre><p>That&#8217;s the end of the <strong>gateway_process.php</strong> script. The script that invokes it—<strong>billing.php—</strong>will then use <strong>$response_array</strong> to take the next logical steps.</p><p>In order to switch the payment gateway in use, you must replace the code in <strong>gateway_setup.php</strong> and <strong>gateway_process.php</strong>. This is much easier than you might think. For PayPal&#8217;s Website Payments Pro, you&#8217;ll need to change the code in those two files so that instead of creating, for example, <strong>$data['x_card_num']</strong>, it creates <strong>$data['ACCT']</strong>. The proper values and their meanings can be found in the <a
href="https://www.x.com/developers/paypal/documentation-tools/api/dodirectpayment-api-operation-nvp">PayPal documentation</a>.  This means that <strong>gateway_setup.php</strong> would contain:</p><pre class="brush: php; title: ; notranslate">&lt;?php
$data['PAYMENTACTION'] = 'Authorization';

// Billing info:
$data['ACCT'] = $cc_number;
$data['EXPDATE'] = $cc_exp;
$data['CREDITCARDTYPE'] = $cc_type;
$data['CVV2'] = $cc_cvv;
$data['FIRSTNAME'] = $cc_first_name;
$data['LASTNAME'] = $cc_last_name;
$data['STREET'] = $cc_address;
$data['STATE'] = $cc_state;
$data['CITY'] = $cc_city;
$data['ZIP'] = $cc_zip;
$data['COUNTRY'] = 'US'; // Or other, if accepting international orders.
$data['IPADDRESS'] = $_SERVER['REMOTE_ADDR'];</pre><p>As in the book, these orders are being authorized first and captured later. The actual transfer of funds takes place in a second step, when the order ships. For simplicity sake, you could change the <strong>PAYMENTACTION</strong> to <em>Sale</em>, assuming that would be appropriate (and legal) in your situation. PayPal also wants you to pass along the customer&#8217;s IP address, for fraud prevention purposes. And you&#8217;ll need to get the credit card type from the user, which isn&#8217;t requested in the book&#8217;s original code.</p><p>Next, <strong>gateway_process.php</strong> needs your own information:</p><pre class="brush: php; title: ; notranslate">// Your account info:
$data['SIGNATURE'] = 'your API signature';
$data['USER'] = 'your API username';
$data['PWD'] = 'your API password';</pre><p>This information will be determined when you sign up for Website Payments Pro with your PayPal business account.<br
/> Next, there&#8217;s the payment gateway stuff:</p><pre class="brush: php; title: ; notranslate">// PayPal Website Payments Pro Stuff:
$data['VERSION'] = '85.0';

// Transaction stuff:
$data['METHOD'] = 'DoDirectPayment';</pre><p>And then there&#8217;s the order information:</p><pre class="brush: php; title: ; notranslate">// Order info:
$data['AMT'] = $order_total;
$data['CURRENCYCODE'] = 'USD';
$data['INVNUM'] = $order_id;
$data['CUSTOM'] = $customer_id;</pre><p>The <strong>CUSTOM</strong> option lets you send your own data along, in this case the customer ID (although the customer ID could also be retrieved later via the transaction ID).</p><p>(Note: Dividing the data into these two files may seem odd, but it&#8217;s done so that the administrative side can easily use the same <strong>gateway_process.php</strong> script, after running a <strong>gateway_setup_admin.php</strong> script. If you need help with the admin process, to capture a prior authorization, let me know.)</p><p>Also, the <strong>GATEWAY_API_URL</strong> constant in <strong>gateway_process.php</strong> needs to be changed to PayPal&#8217;s proper URL: <em>https://api-3t.sandbox.paypal.com/nvp</em> for testing, <em>https://api-3t.paypal.com/nvp</em> for live purposes.</p><p>After identifying all the values, the <strong>gateway_process.php</strong> script converts that data into a string of URL-encoded name-value pairs. That does not need to be changed, nor does the cURL request made at the end of that script.</p><p>In response to the request, PayPal will return a string which contains more name-value pairs: <em>TIMESTAMP=X&amp;ACK=Success&amp;VERSION=85&amp;&#8230;</em> This must be broken into an array:</p><pre class="brush: php; title: ; notranslate">$a = explode('&amp;', $response);
$response_array = array();
foreach ($a as $item) {
 list($key, $value) = explode('=', $item);
 $response_array[$key] = $value;
}</pre><p>This code is a bit different and more complex than the Authorize.net code, as Authorize.net only returns a string broken up by the pipe character (|). But at this point, &lt;strong&gt;$response_array&lt;/strong&gt; is usable. Unfortunately, &lt;strong&gt;billing.php&lt;/strong&gt; will need to be modified, because that script assumes a numerically indexed array. First, you&#8217;ll need to change the call to the stored procedure:</p><pre class="brush: php; title: ; notranslate">$r = mysqli_query($dbc, &quot;CALL add_transaction($order_id, '{$data['PAYMENTACTION']}', $response_array['AMT'], $response_array['ACK'], '$response_array['PAYMENTADVICECODE']', $response_array['TRANSACTIONID'], '$response')&quot;);</pre><p>After that code, different reactions occur based upon the success of the transaction. To check that, use <strong>$response_array['ACK']</strong>, which should have a value of <em>Success</em>. Other values include <em>SuccessWithWarning</em>, <em>Failure</em>, and <em>FailureWithWarning</em>. The response array will store the actual reasons in order elements in those situations. The unique transaction ID will be stored in <strong>$response_array['TRANSACTIONID']</strong>. This would be needed for the capture phase, if using that route. Again, if you need help with updating the admin pieces, let me know.</p><p>So that&#8217;s the gist of how you would use PayPal&#8217;s Website Payments Pro instead of Authorize.net for direct payment with the second e-commerce example in the book. As already mentioned, PayPal does insist that you create an Express Checkout process, too. It&#8217;s actually slightly simpler than this code because the user&#8217;s billing and shipping information is already stored in PayPal. To integrate this option, you&#8217;d add PayPal&#8217;s Express Checkout button to your <strong>cart.php</strong> page, and that would take the user to a different page on your site, where he or she enters his or her PayPal email address and password. This is then sent to PayPal for authorization, along with the order particulars. For more, see PayPal&#8217;s documentation.</p> ]]></content:encoded> <wfw:commentRss>http://www.larryullman.com/2012/03/07/using-paypals-website-payments-pro-with-effortless-e-commerce-with-php-and-mysql/feed/</wfw:commentRss> <slash:comments>3</slash:comments> </item> <item><title>Top 100 E-Commerce Tips</title><link>http://www.larryullman.com/2012/02/03/top-100-e-commerce-tips/</link> <comments>http://www.larryullman.com/2012/02/03/top-100-e-commerce-tips/#comments</comments> <pubDate>Fri, 03 Feb 2012 15:31:35 +0000</pubDate> <dc:creator>Larry</dc:creator> <category><![CDATA[JavaScript]]></category> <category><![CDATA[MySQL]]></category> <category><![CDATA[PHP]]></category> <category><![CDATA[Web Development]]></category> <category><![CDATA[e-commerce]]></category> <category><![CDATA[ecom]]></category><guid
isPermaLink="false">http://www.larryullman.com/?p=2982</guid> <description><![CDATA[I just recently came across this somewhat old post titled Top 100 E-commerce Tips from WebmasterWorld. Despite the fact that the article was published over four years ago, and it&#8217;s based upon a slightly older forum thread, there&#8217;s still a lot of material in the article worth reading if you do any e-commerce. Even though [...]]]></description> <content:encoded><![CDATA[<p>I just recently came across this somewhat old post titled <a
href="http://www.soloseo.com/blog/2007/06/18/top-100-e-commerce-tips-webmasterworld/">Top 100 E-commerce Tips from WebmasterWorld</a>. Despite the fact that the article was published over four years ago, and it&#8217;s based upon a slightly older forum thread, there&#8217;s still a lot of material in the article worth reading if you do any e-commerce. Even though there are a full 100 tips here, they&#8217;re short—most are just a single sentence—and quite valid. Admittedly, I disagree with a couple, and feel like a few could be tossed out, but there are many good points made, and many reminders of things that perhaps you&#8217;ve forgotten to emphasize on your most recent e-commerce. project.</p> ]]></content:encoded> <wfw:commentRss>http://www.larryullman.com/2012/02/03/top-100-e-commerce-tips/feed/</wfw:commentRss> <slash:comments>0</slash:comments> </item> <item><title>Security &amp; Privacy Made Simpler</title><link>http://www.larryullman.com/2011/12/24/security-privacy-made-simpler/</link> <comments>http://www.larryullman.com/2011/12/24/security-privacy-made-simpler/#comments</comments> <pubDate>Sat, 24 Dec 2011 15:42:04 +0000</pubDate> <dc:creator>Larry</dc:creator> <category><![CDATA[MySQL]]></category> <category><![CDATA[PHP]]></category> <category><![CDATA[e-commerce]]></category> <category><![CDATA[ecom]]></category> <category><![CDATA[ecommerce]]></category> <category><![CDATA[privacy]]></category> <category><![CDATA[security]]></category><guid
isPermaLink="false">http://www.larryullman.com/?p=2931</guid> <description><![CDATA[When I was writing my book, I naturally did a bunch of research, particularly with regards to the various laws that apply. Understanding the programming behind an e-commerce site is relatively simple; understanding all the applicable laws and implications of doing e-commerce is complex. One of the sites I found to be quite useful was the U.S. [...]]]></description> <content:encoded><![CDATA[<p>When I was writing my <em></em><a
href="http://www.larryullman.com/books/effortless-e-commerce-with-php-and-mysql/">Effortless E-Commerce with PHP and MySQL</a> book, I naturally did a bunch of research, particularly with regards to the various laws that apply. Understanding the programming behind an e-commerce site is relatively simple; understanding all the applicable laws and implications of doing e-commerce is complex. One of the sites I found to be quite useful was the U.S. <a
href="http://www.bbb.org">Better Business Bureau</a> (BBB).</p><p>I&#8217;m currently going through some items in my &#8220;to read&#8221; folder, and am reading, or perhaps re-reading, the Better Business Bureau&#8217;s PDF titled &#8220;<a
href="http://www.bbb.org/us/corporate-engagement/security/">Security &amp; Privacy &#8211; Made Simpler</a>&#8220;. If you do any e-commerce, or even just Web development, it&#8217;s worth reading. It&#8217;s a 22-page document that discusses almost every facet of e-commerce, such as:</p><ul><li>Developing a security and privacy plan</li><li>Creating and communicating your security and privacy policies</li><li>Good employee screening and policies</li><li>Common hack/theft strategies</li><li>General Internet security</li><li>Proper handling of customer data</li><li>Payment processing</li><li>What to do in the event of a data breach</li><li>A preview of international e-commerce considerations</li></ul><p>The document also has many resources listed in these and other categories. You can download the PDF from that page, but there are also related FAQs and more on the BBB&#8217;s site.</p> ]]></content:encoded> <wfw:commentRss>http://www.larryullman.com/2011/12/24/security-privacy-made-simpler/feed/</wfw:commentRss> <slash:comments>0</slash:comments> </item> <item><title>“Ajax-ifying a Shopping Cart” Article Published Online</title><link>http://www.larryullman.com/2011/03/11/%e2%80%9cajax-ifying-a-shopping-cart%e2%80%9d-article-published-online/</link> <comments>http://www.larryullman.com/2011/03/11/%e2%80%9cajax-ifying-a-shopping-cart%e2%80%9d-article-published-online/#comments</comments> <pubDate>Fri, 11 Mar 2011 02:48:24 +0000</pubDate> <dc:creator>Larry</dc:creator> <category><![CDATA[MySQL]]></category> <category><![CDATA[PHP]]></category> <category><![CDATA[Web Development]]></category> <category><![CDATA[ajax]]></category> <category><![CDATA[article]]></category> <category><![CDATA[e-commerce]]></category> <category><![CDATA[ecom]]></category><guid
isPermaLink="false">http://www.larryullman.com/?p=2375</guid> <description><![CDATA[Peachpit Press has just published online another article I wrote titled “Ajax-ifying a Shopping Cart.” The article can be used to expand some of the content in my “Effortless E-Commerce with PHP and MySQL” book. This is the fourth and final article I wrote for Peachpit Press in support of this book (plus the five [...]]]></description> <content:encoded><![CDATA[<p>Peachpit Press has just published online another article I wrote titled “<a
href="http://www.peachpit.com/articles/article.aspx?p=1684314">Ajax-ifying a Shopping Cart</a>.” The article can be used to expand some of the content in my “Effortless E-Commerce with PHP and MySQL” book. This is the fourth and final article I wrote for Peachpit Press in support of this book (plus the five blog postings).</p> ]]></content:encoded> <wfw:commentRss>http://www.larryullman.com/2011/03/11/%e2%80%9cajax-ifying-a-shopping-cart%e2%80%9d-article-published-online/feed/</wfw:commentRss> <slash:comments>0</slash:comments> </item> <item><title>“Creating an Ajax-Enabled Rating System for Your Website” Article Published Online</title><link>http://www.larryullman.com/2011/03/06/%e2%80%9ccreating-an-ajax-enabled-rating-system-for-your-website%e2%80%9d-article-published-online/</link> <comments>http://www.larryullman.com/2011/03/06/%e2%80%9ccreating-an-ajax-enabled-rating-system-for-your-website%e2%80%9d-article-published-online/#comments</comments> <pubDate>Sun, 06 Mar 2011 01:50:18 +0000</pubDate> <dc:creator>Larry</dc:creator> <category><![CDATA[MySQL]]></category> <category><![CDATA[PHP]]></category> <category><![CDATA[Web Development]]></category> <category><![CDATA[article]]></category> <category><![CDATA[e-commerce]]></category> <category><![CDATA[ecom]]></category><guid
isPermaLink="false">http://www.larryullman.com/?p=2370</guid> <description><![CDATA[Peachpit Press has just published online another article I wrote titled “Creating an Ajax-Enabled Rating System for Your Website.” The article can be used to expand some of the content in my “Effortless E-Commerce with PHP and MySQL” book.]]></description> <content:encoded><![CDATA[<p>Peachpit Press has just published online another article I wrote titled “<a
href="http://www.peachpit.com/articles/article.aspx?p=1681764">Creating an Ajax-Enabled Rating System for Your Website</a>.” The article can be used to expand some of the content in my “Effortless E-Commerce with PHP and MySQL” book.</p> ]]></content:encoded> <wfw:commentRss>http://www.larryullman.com/2011/03/06/%e2%80%9ccreating-an-ajax-enabled-rating-system-for-your-website%e2%80%9d-article-published-online/feed/</wfw:commentRss> <slash:comments>0</slash:comments> </item> <item><title>“Building an E-Commerce Site with PHP: Making Product Recommendations” Article Published Online</title><link>http://www.larryullman.com/2011/02/17/%e2%80%9cbuilding-an-e-commerce-site-with-php-making-product-recommendations%e2%80%9d-article-published-online/</link> <comments>http://www.larryullman.com/2011/02/17/%e2%80%9cbuilding-an-e-commerce-site-with-php-making-product-recommendations%e2%80%9d-article-published-online/#comments</comments> <pubDate>Thu, 17 Feb 2011 16:00:35 +0000</pubDate> <dc:creator>Larry</dc:creator> <category><![CDATA[MySQL]]></category> <category><![CDATA[PHP]]></category> <category><![CDATA[Web Development]]></category> <category><![CDATA[article]]></category> <category><![CDATA[e-commerce]]></category> <category><![CDATA[ecom]]></category><guid
isPermaLink="false">http://www.larryullman.com/?p=2305</guid> <description><![CDATA[Peachpit Press has just published online another article I wrote titled “Building an E-Commerce Site with PHP: Making Product Recommendations.” The article can be used to expand some of the content in my “Effortless E-Commerce with PHP and MySQL” book.]]></description> <content:encoded><![CDATA[<p>Peachpit Press has just published online another article I wrote titled “<a
href="http://www.peachpit.com/articles/article.aspx?p=1678915">Building an E-Commerce Site with PHP: Making Product Recommendations</a>.” The article can be used to expand some of the content in my “Effortless E-Commerce with PHP and MySQL” book.</p> ]]></content:encoded> <wfw:commentRss>http://www.larryullman.com/2011/02/17/%e2%80%9cbuilding-an-e-commerce-site-with-php-making-product-recommendations%e2%80%9d-article-published-online/feed/</wfw:commentRss> <slash:comments>0</slash:comments> </item> <item><title>Rewriting the E-Commerce Stored Procedures with Standard PHP-MySQL #3, Chapter 10</title><link>http://www.larryullman.com/2010/12/28/rewriting-the-e-commerce-stored-procedures-with-standard-php-mysql-3-chapter-10/</link> <comments>http://www.larryullman.com/2010/12/28/rewriting-the-e-commerce-stored-procedures-with-standard-php-mysql-3-chapter-10/#comments</comments> <pubDate>Tue, 28 Dec 2010 15:24:28 +0000</pubDate> <dc:creator>Larry</dc:creator> <category><![CDATA[MySQL]]></category> <category><![CDATA[PHP]]></category> <category><![CDATA[Web Development]]></category> <category><![CDATA[e-commerce]]></category> <category><![CDATA[ecom]]></category> <category><![CDATA[stored procedure]]></category><guid
isPermaLink="false">http://www.larryullman.com/?p=2171</guid> <description><![CDATA[This is my third post in a series in which I’m rewriting the stored procedures used in my “Effortless E-Commerce with PHP and MySQL” book as standard PHP and MySQL. Although stored procedures offer lots of benefits over standard PHP-MySQL logic, not everyone has an environment that supports stored procedures, so I’m writing these posts [...]]]></description> <content:encoded><![CDATA[<p>This is my third post in a series in which I’m rewriting the stored procedures used in my “Effortless E-Commerce with PHP and MySQL” book as standard PHP and MySQL. Although stored procedures offer lots of benefits over standard PHP-MySQL logic, not everyone has an environment that supports stored procedures, so I’m writing these posts to help out those readers. <a
href="http://www.larryullman.com/2010/12/07/rewriting-the-e-commerce-stored-procedures-with-standard-php-mysql/">In my first post</a>, I rewrote the examples from Chapter 8, “Creating a Catalog”. Those examples are really simple, running only basic SELECT queries. <a
href="http://www.larryullman.com/2010/12/18/rewriting-the-e-commerce-stored-procedures-with-standard-php-mysql-2-chapter-9/">In the second post</a>, I presented an alternative version of the stored procedures—and the PHP scripts that call them—for Chapter 9, “Building a Shopping Cart.” Those procedures aren&#8217;t too complex either. In this post, I&#8217;ll rewrite the stored procedures and update the PHP scripts that call them for Chapter 10, &#8220;Checking Out.&#8221; This chapter has the most complicated—and important—stored procedures, so the PHP scripts will need to be reworked more than in the other chapters. All three chapters are from the third part of the book, in which an e-commerce site is developed for the sake of selling physical products (viz., coffee).<span
id="more-2171"></span></p><p>The first procedure in Chapter 10 is <strong>add_customer()</strong>, called in the <strong>checkout.php</strong> script, after the customer has successfully completed the shipping form. The code in the PHP script calls the procedure, which will add a record to the <strong>customers</strong> table. The procedure also returns the customer ID via an outbound argument named <strong>@cid</strong>. This value needs to be stored in the session for later use. Here is the original code:</p><pre class="brush: php; title: ; notranslate">$r = mysqli_query($dbc, &quot;CALL add_customer('$e', '$fn', '$ln', '$a1', '$a2', '$c', '$s', $z, $p, @cid)&quot;);

// Confirm that it worked:
if ($r) {

// Retrieve the customer ID:
$r = mysqli_query($dbc, 'SELECT @cid');
if (mysqli_num_rows($r) == 1) {

    list($_SESSION['customer_id']) = mysqli_fetch_array($r);</pre><p>Without a stored procedure, you would replace that code with:</p><pre class="brush: php; title: ; notranslate">$r = mysqli_query($dbc, &quot;INSERT INTO customers VALUES (NULL, '$e', '$fn', '$ln', '$a1', '$a2', '$c', '$s', $z, $p, NOW())&quot;);

// Confirm that it worked:
if (mysqli_num_rows($r) == 1) {

    // Retrieve the customer ID:
    $_SESSION['customer_id'] = mysqli_insert_id($r);</pre><p>There is one caveat, however: the variables aren&#8217;t safe to use in the query as they haven&#8217;t been sanctified (they&#8217;ve been validated, though). So I would run all the strings through an escaping function, such as <strong>mysqli_real_escape_string()</strong> first. You could do so when assigning values to the variables earlier in the script. You&#8217;ll also need to remove one closing curly bracket from the original PHP script, as this structure has one fewer conditionals.</p><p>Next, the customer is taken to <strong>billing.php</strong>, where they&#8217;re presented with a form for entering their billing information. The form data is then validated and the <strong>add_order()</strong> procedure is called. This procedure has the most logic, as it needs to:</p><ul><li>Add a record to the <strong>orders</strong> table.</li><li>Get the new order ID value</li><li>Add one record to the <strong>order_contents</strong> table for each item in the order</li><li>Calculate the subtotal of the order</li><li>Calculate the total of the order (which includes the shipping)</li><li>Add the total of the order to the <strong>orders</strong> table</li><li>Return both the order total and the order ID</li></ul><p>The original stored procedure does all this using two INSERT queries, three SELECT queries, and one UPDATE. (This is an excellent example of the benefit of stored procedures, as the PHP script only needs to execute two queries to do all of the above.)</p><p>The <strong>billing.php</strong> script has the following code:</p><pre class="brush: php; title: ; notranslate">$r = mysqli_query($dbc, &quot;CALL add_order({$_SESSION['customer_id']}, '$uid', {$_SESSION['shipping']}, $cc_last_four, @total, @oid)&quot;);

// Confirm that it worked:
if ($r) {

    // Retrieve the order ID and total:
    $r = mysqli_query($dbc, 'SELECT @total, @oid');
    if (mysqli_num_rows($r) == 1) {
        list($order_total, $order_id) = mysqli_fetch_array($r);

        // Store the information in the session:
        $_SESSION['order_total'] = $order_total;
        $_SESSION['order_id'] = $order_id;</pre><p>You&#8217;d need to replace that code with all of the following:</p><pre class="brush: php; title: ; notranslate">$r = mysqli_query($dbc, &quot;INSERT INTO orders (customer_id, shipping, credit_card_number, order_date) VALUES
({$_SESSION['customer_id']}, {$_SESSION['shipping']}, $cc_last_four, NOW())&quot;);

if (mysqli_num_rows($r) == 1) {

    // Get the order ID:
    $_SESSION['order_id'] = mysqli_insert_id($r);

    // Add the items to the order_contents table:
    $r = mysqli_query($dbc, &quot;INSERT INTO order_contents (order_id, product_type, product_id, quantity, price_per)
SELECT {$_SESSION['order_id']}, c.product_type, c.product_id, c.quantity, IFNULL(sales.price, ncp.price) FROM carts AS c
INNER JOIN non_coffee_products AS ncp ON c.product_id=ncp.id
LEFT OUTER JOIN sales ON (sales.product_id=ncp.id AND sales.product_type='other' AND ((NOW() BETWEEN sales.start_date AND sales.end_date) OR (NOW() &gt; sales.start_date AND sales.end_date IS NULL)) )
WHERE c.product_type=&quot;other&quot; AND c.user_session_id='$uid'
UNION
SELECT {$_SESSION['order_id']}, c.product_type, c.product_id, c.quantity, IFNULL(sales.price, sc.price) FROM carts AS c
INNER JOIN specific_coffees AS sc ON c.product_id=sc.id
LEFT OUTER JOIN sales ON (sales.product_id=sc.id AND sales.product_type='coffee' AND ((NOW() BETWEEN sales.start_date AND sales.end_date) OR (NOW() &gt; sales.start_date AND sales.end_date IS NULL)) )
WHERE c.product_type=&quot;coffee&quot; AND c.user_session_id='$uid'&quot;);

    if (mysqli_affected_rows($r) &gt; 0) {

        // Calculate and fetch the subtotal:
        $r = mysqli_query($dbc, &quot;SELECT SUM(quantity*price_per) FROM order_contents WHERE order_id={$_SESSION['order_id]}&quot;);
        list($subtotal) = mysqli_fetch_array($r, MYSQLI_NUM);

       // Calculate, update, and store the order total:
       $r = mysqli_query($dbc, &quot;UPDATE orders SET total = ($subtotal + {$_SESSION['shipping']}) WHERE id={$_SESSION['order_id]}&quot;);
       $_SESSION['order_total'] = $subtotal + $_SESSION['shipping'];</pre><p>So there&#8217;s all the stored procedure logic in PHP. For an explanation of the queries, see the book. To use this in a script, you&#8217;ll need to complete all the conditionals as appropriate.</p><p>Later, the <strong>billing.php</strong> script calls the <strong>add_transaction()</strong> procedure, after processing the payment:</p><pre class="brush: php; title: ; notranslate">$r = mysqli_query($dbc, &quot;CALL add_transaction($order_id, '{$data['x_type']}', $response_array[9], $response_array[0], '$reason', $response_array[6], '$response')&quot;);</pre><p>That one line simply gets replaced with:</p><pre class="brush: php; title: ; notranslate">$r = mysqli_query($dbc, &quot;INSERT INTO transactions VALUES (NULL, {$_SESSION['order_id'], {$data['x_type']}, $response_array[9], $response_array[0], '$reason', $response_array[6], '$response', NOW())&quot;);</pre><p>This takes us to <strong>final.php</strong>, where the <strong>clear_cart()</strong> procedure is called:</p><pre class="brush: php; title: ; notranslate">$r = mysqli_query($dbc, &quot;CALL clear_cart('$uid')&quot;);</pre><p>Replace that line with:</p><pre class="brush: php; title: ; notranslate">$r = mysqli_query($dbc, &quot;DELETE FROM carts WHERE user_session_id='$uid'&quot;);</pre><p>And that&#8217;s it for <strong>final.php</strong>.</p><p>Now three scripts in Chapter 10—<strong>checkout.php</strong>, <strong>billing.php</strong>, and <strong>email_receipt.php</strong>—also invoke the <strong>get_order_contents()</strong> procedure. I explain how to replace it with standard PHP-MySQL in the second post in this series.</p><p>That&#8217;s it for converting all of the stored procedures in the book with standard PHP and MySQL. As you can see, it&#8217;s generally not that hard, depending upon how complex the stored procedure itself is.</p><p>Let me know if you have any questions and thanks for your interest in the book!</p> ]]></content:encoded> <wfw:commentRss>http://www.larryullman.com/2010/12/28/rewriting-the-e-commerce-stored-procedures-with-standard-php-mysql-3-chapter-10/feed/</wfw:commentRss> <slash:comments>0</slash:comments> </item> <item><title>Rewriting the E-Commerce Stored Procedures with Standard PHP-MySQL #2, Chapter 9</title><link>http://www.larryullman.com/2010/12/18/rewriting-the-e-commerce-stored-procedures-with-standard-php-mysql-2-chapter-9/</link> <comments>http://www.larryullman.com/2010/12/18/rewriting-the-e-commerce-stored-procedures-with-standard-php-mysql-2-chapter-9/#comments</comments> <pubDate>Sat, 18 Dec 2010 17:05:07 +0000</pubDate> <dc:creator>Larry</dc:creator> <category><![CDATA[MySQL]]></category> <category><![CDATA[PHP]]></category> <category><![CDATA[Web Development]]></category> <category><![CDATA[e-commerce]]></category> <category><![CDATA[ecom]]></category> <category><![CDATA[stored procedure]]></category><guid
isPermaLink="false">http://www.larryullman.com/?p=2151</guid> <description><![CDATA[This is my second post in a series in which I&#8217;m rewriting the stored procedures used in my &#8220;&#8221; book as standard PHP and MySQL. Although stored procedures offer lots of benefits over standard PHP-MySQL logic, not everyone has an environment that supports stored procedures, so I&#8217;m writing these posts to help out those readers. [...]]]></description> <content:encoded><![CDATA[<p>This is my second post in a series in which I&#8217;m rewriting the stored procedures used in my &#8220;<a
href="http://www.larryullman.com/books/effortless-e-commerce-with-php-and-mysql/">Effortless E-Commerce with PHP and MySQL</a>&#8221; book as standard PHP and MySQL. Although stored procedures offer lots of benefits over standard PHP-MySQL logic, not everyone has an environment that supports stored procedures, so I&#8217;m writing these posts to help out those readers. <a
href="http://www.larryullman.com/2010/12/07/rewriting-the-e-commerce-stored-procedures-with-standard-php-mysql/">In my first post</a>, I rewrote the examples from Chapter 8, &#8220;Creating a Catalog&#8221;. Those examples are really simple, running only basic SELECT queries. In this post, I&#8217;ll present an alternative version of the stored procedures—and the PHP scripts that call them—for Chapter 9, &#8220;Building a Shopping Cart.&#8221; Both chapters are from the third part of the book, in which an e-commerce site is developed for the sake of selling physical products (viz., coffee).<span
id="more-2151"></span>Chapter 9 is all about managing a shopping cart and, with exactly the same functionality, a wish list. The associated tables—<strong>carts</strong> and <strong>wish_lists</strong>—are identical in definition.  The shopping cart stores the items that will be purchased soon; the wish list stores items that the customer may purchase eventually (through the use of cookies, the wish list can remember user items for weeks).</p><p>There are four stored procedures for each of these two tables. Each procedure corresponds to basic <em>CRUD</em> functionality: <em>Create</em> (i.e., INSERT), <em>Retrieve</em> (SELECT), <em>Update</em>, and <em>Delete</em>. In Chapter 9, all eight procedures are invoked from either <strong>cart.php</strong> or <strong>wishlist.php</strong> (Chapter 10, &#8220;Checking Out,&#8221; also has some scripts that will use them). Both scripts use a long-ish <strong>if-elseif</strong> conditional that checks for values in the URL to know when to perform INSERT and DELETE procedures. Such conditionals will be true when the user, for example, clicks an &#8220;Add to Cart&#8221; link on a product listing page or clicks a &#8220;Remove from Cart&#8221; link on the shopping cart page. UPDATE procedures are run when the shopping cart (or wish list) form is POSTed back to the page, presumably with new quantities provided for the items in the cart (or wish list).</p><div
id="attachment_2156" class="wp-caption aligncenter" style="width: 310px"><a
href="http://cloudfront.larryullman.com/wp-content/uploads/2010/12/sp_rewrite2_1.png"><img
class="size-medium wp-image-2156 " title="A Product Listing in the Catalog" src="http://cloudfront.larryullman.com/wp-content/uploads/2010/12/sp_rewrite2_1-300x141.png" alt="A Product Listing in the Catalog" width="300" height="141" /></a><p
class="wp-caption-text">A Product Listing in the Catalog</p></div><div
id="attachment_2157" class="wp-caption aligncenter" style="width: 310px"><a
href="http://cloudfront.larryullman.com/wp-content/uploads/2010/12/sp_rewrite2_2.png"><img
class="size-medium wp-image-2157 " title="The Shopping Cart Form" src="http://cloudfront.larryullman.com/wp-content/uploads/2010/12/sp_rewrite2_2-300x195.png" alt="The Shopping Cart Form" width="300" height="195" /></a><p
class="wp-caption-text">The Shopping Cart Form</p></div><p>Both PHP scripts, after whatever other stored procedures may or may not be called, execute the SELECT procedure. Let&#8217;s look at that first. (To make this post shorter, I&#8217;m only going to talk about changes required to the <strong>cart.php</strong> script from here on out; changes required for <strong>wishlist.php</strong> would be almost exactly the same.)</p><p>Near the very end of <strong>cart.php</strong>, the SELECT stored procedure is executed using this code:</p><pre class="brush: php; title: ; notranslate">$r = mysqli_query($dbc, &quot;CALL get_shopping_cart_contents('$uid')&quot;);</pre><p>Earlier in the script, the <strong>$uid</strong> variable is created, which is a unique reference to the current user. You can think of it like a session ID, although it&#8217;s not actually used by PHP sessions. To replace the stored procedure, you would just change the above line to be:</p><pre class="brush: php; title: ; notranslate">$r = mysqli_query($dbc, &quot;SELECT CONCAT(&quot;O&quot;, ncp.id) AS sku, c.quantity, ncc.category, ncp.name, ncp.price, ncp.stock, sales.price AS sale_price
FROM carts AS c INNER JOIN non_coffee_products AS ncp ON c.product_id=ncp.id
INNER JOIN non_coffee_categories AS ncc ON ncc.id=ncp.non_coffee_category_id
LEFT OUTER JOIN sales ON (sales.product_id=ncp.id AND sales.product_type='other'
AND ((NOW() BETWEEN sales.start_date AND sales.end_date) OR (NOW() &gt; sales.start_date AND sales.end_date IS NULL)) )
WHERE c.product_type=&quot;other&quot; AND c.user_session_id='$uid'
UNION SELECT CONCAT(&quot;C&quot;, sc.id), c.quantity, gc.category, CONCAT_WS(&quot; - &quot;, s.size, sc.caf_decaf, sc.ground_whole), sc.price, sc.stock, sales.price
FROM carts AS c INNER JOIN specific_coffees AS sc ON c.product_id=sc.id INNER JOIN sizes AS s ON s.id=sc.size_id
INNER JOIN general_coffees AS gc ON gc.id=sc.general_coffee_id LEFT OUTER JOIN sales ON (sales.product_id=sc.id
AND sales.product_type='coffee' AND ((NOW() BETWEEN sales.start_date AND sales.end_date) OR (NOW() &gt; sales.start_date AND sales.end_date IS NULL)) )
WHERE c.product_type=&quot;coffee&quot; AND c.user_session_id='$uid'&quot;);</pre><p>In short, all you need to do is take the big query from the stored procedure and execute it directly. Two uses of &#8220;uid&#8221; in the stored procedure, representing the internal stored procedure variable, need to be replaced with the PHP variable <strong>$uid</strong>, and wrapped in quotes (the variable within the stored procedure does not use a dollar sign, as it&#8217;s not a PHP variable, and doesn&#8217;t need to be wrapped in quotes as queries executed within stored procedures work like prepared statements).</p><p>Moving on, the <strong>cart.php</strong> script invokes the <strong>remove_from_cart()</strong> stored procedure once:</p><pre class="brush: php; title: ; notranslate">$r = mysqli_query($dbc, &quot;CALL remove_from_cart('$uid', '$sp_type', $pid)&quot;);</pre><p>Replace that with:</p><pre class="brush: php; title: ; notranslate">$r = mysqli_query($dbc, &quot;DELETE FROM carts WHERE user_session_id='$uid' AND product_type='$sp_type' AND product_id=$pid&quot;);</pre><p>Again, this is just executing the query directly, after replacing the stored procedure variables in the query with PHP variables. Note that all of these variables have already been validated prior to this point. The <strong>cart.php</strong> script also invokes <strong>remove_from_wish_list()</strong> once, which will also need to be replaced with the appropriate query.</p><p>The UPDATE stored procedure is called in <strong>cart.php</strong>, upon the form submission. In a <strong>foreach</strong> loop, you&#8217;ll find this code:</p><pre class="brush: php; title: ; notranslate">$r = mysqli_query($dbc, &quot;CALL update_cart('$uid', '$sp_type', $pid, $qty)&quot;);</pre><p>Unlike the other procedures I&#8217;ve written about thus far, the <strong>update_cart()</strong> stored procedure has a bit of logic to it. Namely, it will update the quantity in the cart if the new quantity is greater than 0 or execute the <strong>remove_from_cart()</strong> procedure if the quantity equals 0. So that logic must be present in the PHP code that replaces the above line:</p><pre class="brush: php; title: ; notranslate">if ($qty &gt; 0) {
    $r = mysqli_query($dbc, &quot;UPDATE carts SET quantity=$qty, date_modified=NOW() WHERE user_session_id='$uid' AND product_type='$sp_type' AND product_id=$pid&quot;);
} elseif ($qty == 0) {
    $r = mysqli_query($dbc, &quot;DELETE FROM carts WHERE user_session_id='$uid' AND product_type='$sp_type' AND product_id=$pid&quot;);
}</pre><p>Arguably, I&#8217;d be inclined to use prepared statements there instead (whenever you have a query being executed within a loop, it&#8217;s a good candidate for prepared statements), but I don&#8217;t want to over-complicate the changes I&#8217;m already suggesting.</p><p>This leaves us with the last stored procedure, <strong>add_to_cart()</strong>. You might think this would be a simple INSERT query, but there&#8217;s some logic required by it. This procedure will be called when the customer clicks a link. In that case, a simple INSERT is all that&#8217;s necessary. However, if the user clicks the same link again later—thereby adding to the cart something already in the cart, another INSERT <em>should not be</em> executed. The decision I made in the book is to assume that the customer purposefully wanted to add another quantity of the same item to the cart in such instances. So the stored procedure runs an UPDATE query when the item exists in the cart.</p><p>The first time the <strong>add_to_cart()</strong> procedure is executed in <strong>cart.php</strong> looks like this:</p><pre class="brush: php; title: ; notranslate">$r = mysqli_query($dbc, &quot;CALL add_to_cart('$uid', '$sp_type', $pid, 1)&quot;);</pre><p>The final 1 indicates that one quantity of the item is being added, which is the default behavior when an &#8220;Add to Cart&#8221; link is clicked. You would replace that code with:</p><pre class="brush: php; title: ; notranslate">$r = mysqli_query($dbc, &quot;SELECT id FROM carts where user_session_id='$uid' AND product_type='$sp_type' AND product_id=$pid&quot;);
if (mysqli_num_rows($r) == 1) { // Exists in cart, UPDATE!
    list($cid) = mysqli_fetch_array($r, MYSQLI_NUM);
    $r = mysqli_query($dbc, &quot;UPDATE carts SET quantity=quantity+1, date_modified=NOW() WHERE id=$cid&quot;);
} else { // Not in cart, INSERT!
    $r = mysqli_query($dbc, &quot;INSERT INTO carts (user_session_id, product_type, product_id, quantity) VALUES ('$uid', '$sp_type', $pid, 1)&quot;);
}</pre><p>The first query is basically asking if the user already has this item in their cart. If so, the cart&#8217;s <strong>id</strong> value is selected and assigned to a MySQL variable, <strong>@cid</strong>. The conditional then checks if one row was returned. If so, an UPDATE query is run, using the just-created MySQL variable in the WHERE clause (if my use of <strong>@cid</strong> is confusing, I can add explanations of its purpose and usage). If one row wasn&#8217;t returned, an INSERT query is executed.</p><p>Now the <strong>cart.php</strong> script also calls the <strong>add_to_cart()</strong> stored procedure in another instance: If the customer has something in their wish list and they click the &#8220;Move to Cart&#8221; link, the item gets added to the cart and removed from the wish list. The use of <strong>add_to_cart()</strong> is exactly the same, except that whatever quantity of the item is in the user&#8217;s wish list needs to be transferred, too. In that case, the <strong>$qty</strong> variable represents that value. So you&#8217;d also replace this line:</p><pre class="brush: php; title: ; notranslate">$r = mysqli_query($dbc, &quot;CALL add_to_cart('$uid', '$sp_type', $pid, $qty)&quot;);</pre><p>With the code above, except you&#8217;d use <strong>$qty</strong> instead of 1.</p><p>And that&#8217;s it! These procedures are a bit more complicated than those in Chapter 8, as they have some internal logic (whereas Chapter 8&#8242;s procedures are merely SELECT statements). But it&#8217;s still not hard to rewrite these procedures using standard PHP-MySQL, as I&#8217;ve just shown. In a subsequent post, I&#8217;ll rewrite the procedures from Chapter 10 using standard PHP-MySQL. One of those procedures has quite a lot of logic to it, and will be the most complicated to translate.</p> ]]></content:encoded> <wfw:commentRss>http://www.larryullman.com/2010/12/18/rewriting-the-e-commerce-stored-procedures-with-standard-php-mysql-2-chapter-9/feed/</wfw:commentRss> <slash:comments>3</slash:comments> </item> <item><title>What is Larry Thinking? #34 =&gt; E-Commerce and Newsletters!</title><link>http://www.larryullman.com/2010/12/12/what-is-larry-thinking-34-e-commerce-and-newsletters/</link> <comments>http://www.larryullman.com/2010/12/12/what-is-larry-thinking-34-e-commerce-and-newsletters/#comments</comments> <pubDate>Sun, 12 Dec 2010 18:52:18 +0000</pubDate> <dc:creator>Larry</dc:creator> <category><![CDATA[MySQL]]></category> <category><![CDATA[PHP]]></category> <category><![CDATA[Web Development]]></category> <category><![CDATA[e-commerce]]></category> <category><![CDATA[ecom]]></category> <category><![CDATA[newsletter]]></category><guid
isPermaLink="false">http://www.larryullman.com/?p=2134</guid> <description><![CDATA[In this edition&#8230; About The Previous Newsletter About This Newsletter On the Web => Myows &#124; Free Online Copyright Protection On the Web => URL Rewriting for Beginners On the Web => Chapter from &#8220;Effortless E-Commerce with PHP and MySQL&#8221; On the Blog => More Links About HTML5 On the Blog => Rewriting the E-Commerce [...]]]></description> <content:encoded><![CDATA[<p>In this edition&#8230;</p><ul><li><a
href="#about1">About The Previous Newsletter</a></li><li><a
href="#about2">About This Newsletter</a></li><li><a
href="#web1">On the Web => Myows | Free Online Copyright Protection</a></li><li><a
href="#web2">On the Web => URL Rewriting for Beginners</a></li><li><a
href="#web3">On the Web => Chapter from &#8220;Effortless E-Commerce with PHP and MySQL&#8221;</a></li><li><a
href="#blog1">On the Blog => More Links About HTML5</a></li><li><a
href="#blog2">On the Blog => Rewriting the E-Commerce Stored Procedures</a></li><li><a
href="#qa1">Q&amp;A => What do you think the future looks like for Flex developers?</a></li><li><a
href="#qa2">Q&amp;A => Would you ever consider doing video tutorials?</a></li><li><a
href="#thinking">What is Larry Thinking? => The Evolution of a Newsletter</a></li><li><a
href="#giveaway">Book Giveaway => &#8220;Effortless E-Commerce&#8230;&#8221; and &#8220;Effortless Flex&#8230;&#8221;</a></li><li><a
href="#news">Larry Ullman&#8217;s Book News => &#8220;Effortless E-Commerce&#8221;, &#8220;PHP for the Web&#8221;, and More!</a></li></ul><h2 id="about1">About the Previous Newsletter</h2><p>So the first thing to acknowledge is how the last newsletter turned out…As I mentioned at the beginning of that newsletter, it was the first newsletter sent using a new system (specifically, a commercial <a
href="http://www.wordpress.org">WordPress</a> plug-in named <a
href="http://www.satollo.net/plugins/newsletter-pro">Newsletter Pro</a>. To start, I wrote the entire newsletter, entered it into the new system, and sent myself a test newsletter. In that test newsletter, I tested all the links. So far, so good. Then I thought: I should add internal links so &#8220;In this edition&#8221; list at the top is anchored to the articles below. Naturally, being such a minor detail, I didn&#8217;t bother to test this again. And that&#8217;s where I went astray! <em>Always test again.</em> <strong>Always.</strong> As many of you discovered, those links didn&#8217;t work at all (the others in the newsletter did, or should have).</p><p>The cause of the problem is this: one of the features of Newsletter Pro is the ability to track links. I thought it might be interesting to use such a feature. Unfortunately, as I found out, the system is not smart enough to distinguish between absolute URLs and internal anchors.  So there&#8217;s that then.</p><p>Second, I forgot to include an <em>unsubscribe</em> link in the previous newsletter. That&#8217;s not the end of the world, but an unsubscribe link should be prominent (in some countries, that&#8217;s a legal requirement, too).</p><p>Third, as some of you found out, the PDF links in the E-Commerce-related posts on my Web site weren&#8217;t working (well, not until I discovered this myself and corrected the issue). This had to do with how WordPress handles relative links (i.e., not consistently well).</p><p>All in all, not so good on my part. My apologies for the mistakes and the lack of professionalism. To be fair, I think of the newsletter as something that should be colloquial and casual, but still… I&#8217;ll try to do better. Speaking of which…</p><h2 id="about2">About This Newsletter</h2><p>This is the first newsletter using a new, new system! Considering the problems I had with the previous newsletter, and because of secondary concerns about the Newsletter Pro plug-in (more on this later in this edition), I decided to re-investigate the mailing list options. I&#8217;m now using commercial email marketing software from <a
href="http://www.campaignmonitor.com/">Campaign Monitor</a>. As you can hopefully already tell, the end result should be much more professional. Also, towards that end, I believe this newsletter should be easily viewable in plain text, if that&#8217;s your preference.</p><p>As for this edition&#8217;s content, there are links to some good stuff, including an entire chapter from my &#8220;Effortless E-Commerce with PHP and MySQL&#8221; book available for free online. I also answer a couple of questions and talk in depth about how this newsletter has evolved over the years. If that&#8217;s not enough to pique your interest, you may want to check out the book giveaway. There are three titles available!</p><p>As always, thanks for reading and let me know what questions, comments, or issues you may have. Especially the issues, because new systems bring new problems!</p><h2 id="web1">On the Web => Myows | Free Online Copyright Protection</h2><p>In previous newsletters, I&#8217;ve talked about copyright issues with respect to writing, Web sites, and other content. You don&#8217;t actually need to indicate that anything is copyrighted in order to protect it, but having proof of authorship is critical in pursuing copyright violations. Towards that end, one solution is <a
href="http://myows.com/">Myows</a>, a free, online copyright management and protection system. I haven&#8217;t personally used it but expect that some of you will appreciate what Myows offers.</p><h2 id="web2">On the Web => URL Rewriting for Beginners</h2><p>One of the most important technologies people need to familiarize themselves with after learning dynamic Web development is the Web server itself. Whether it&#8217;s Apache, IIS, Abyss, or whatever, harnessing the power of, or simply being able to properly configure, the Web server is a crucial skill set. Among that set is URL Rewriting. There are a number of reasons to use URL Rewriting, the most common being the desire to change a URL from something technically useful, such as www.example.com/browse.php?cat=2 to something semantically useful, such as www.example.com/browse/Hard+Drives/. To get started, check out <a
href="http://www.addedbytes.com/for-beginners/url-rewriting-for-beginners/">this nice tutorial on the subject</a>.</p><h2 id="web3">On the Web => Chapter from &#8220;Effortless E-Commerce with PHP and MySQL&#8221;</h2><p>Peachpit Press, publisher of my book &#8220;Effortless E-Commerce with PHP and MySQL&#8221;, has <a
href="http://www.peachpit.com/articles/article.aspx?p=1653370">posted a chapter from the book on their Web site</a> (technically New Riders is the publisher, but Peachpit owns New Riders). The posted content represents the entire Chapter 4, &#8220;User Accounts,&#8221; which is the second chapter in <em>Part Two: Selling Virtual Products</em>. The posted content covers how user accounts will be managed in the site (in the particular example, only paid, registered users may access content). The material walks through the creation of several helper functions, then develops an entire registration, logging in, logging out, and password management system. The chapter concludes with some security improvements one could make.</p><h2 id="blog1">On the Blog => More Links About HTML5</h2><p>A couple of weeks ago I posted a slew of links that I have come across involving HTML5. If you&#8217;re curious about the subject (and if you do any Web development, you really should be), <a
href="http://www.larryullman.com/2010/11/23/more-links-about-html5/">check them out</a>.</p><h2 id="blog2">On the Blog => Rewriting the E-Commerce Stored Procedures</h2><p>In the second e-commerce example in my &#8220;Effortless E-Commerce with PHP and MySQL&#8221; book, stored procedures are used for all of the public-side database-related functionality. This includes: the displaying of product categories, specific items, and sale items; cart and wish list management (adding items, updating quantities, removing items); and order submissions. However, not everyone can use stored procedures, in particular those on some shared hosting environments.</p><p>One reader recently said (in the forums) that they couldn&#8217;t use stored procedures with their host, so I volunteered to rewrite some of the stored procedures as standard PHP and MySQL. <a
href="http://www.larryullman.com/2010/12/07/rewriting-the-e-commerce-stored-procedures-with-standard-php-mysql/">In the first post towards that end</a>, I rewrote the procedures, and corresponding PHP scripts, from Chapter 8, &#8220;Creating a Catalog&#8221;. Over the next month or so, I&#8217;ll rewrite the stored procedures, and the PHP scripts that use them, from Chapters 9 and 10.</p><h2 id="qa1">Q&amp;A => What do you think the future looks like for Flex developers?</h2><p>Rob asked this question, specifically referencing the &#8220;Apple/Flash logjam&#8221;. In other words, with Apple being difficult (to use a polite word) about Flash (not) running on its mobile devices, how does this impact Flex/Flash Builder developers? This is a good question.</p><p>Without opining too much on the Great Apple/Adobe War of &#8216;10, I feel there&#8217;s got to come a time when Flash will run on Apple&#8217;s devices. Perhaps Adobe will work some with Apple to make Flash run more reliably. Perhaps Apple will cave to pressure (or Department of Justice investigations) and change their position. Probably both will happen and then some. But eventually Flash will run on iPods, iPhones, and iPads. This I believe. And Flash is already available on non-Apple devices, which I think constitutes a larger percentage of the overall market (e.g., even though no individual Android phone sells better than the iPhone, there are more Android-based phones sold than iPhones). The next version of Flex is adding extra features specifically targeting the mobile market, so Adobe is clearly not laying low on that front.</p><p>But Flash on mobile devices is just one consideration. While there is increasing interest in what can be done through mobile devices, the fact is that non-mobile devices are still a vastly larger market, and I can&#8217;t see that changing for some time. Flash has a huge share of the video market and it&#8217;s one of the very few plug-ins that comes included with most browsers. (In fact, Google and Adobe have been working on a version of Flash that&#8217;s more tightly integrated with Chrome, even updating Flash automatically when a new version comes out.)</p><p>And although it&#8217;s a smaller market than Web-based applications, you can use Flex to create cross-platform desktop applications via Adobe AIR. I&#8217;m a pretty big fan of this feature, but I admit I&#8217;m a bit of an outlier on this particular topic.</p><p>So, in short, I&#8217;m not particularly concerned about the future for Flex developers. Flex is a very good product with lots of uses and Flash has an extensive user base. Even Apple&#8217;s stubbornness or the forthcoming HTML5 (which will be broadly supported when exactly?) can&#8217;t change that.</p><h2 id="qa2">Q&amp;A => Would you ever consider doing video tutorials?</h2><p>Parker asked this question. I acknowledge that video tutorials are an excellent way to learn and are becoming increasingly more common, but it&#8217;s just not my thing. I think of myself as a writer, not a video instructor (or voice-only screencasts, for that matter). Coincidentally, Peachpit Press wanted me to add little video clips for the electronic version of my &#8220;PHP for the Web: Visual QuickStart Guide&#8221; (4th Edition) and I said &#8220;No&#8221; to that as well. I appreciate the interest, however!</p><h2 id="thinking">What is Larry Thinking? => The Evolution of a Newsletter</h2><p>Largely because of the changes to my Web site (going from www.DMCInsights.com to www.LarryUllman.com and changing from a largely custom system to one based upon WordPress), I&#8217;ve lately been thinking about the evolution of this newsletter. As I&#8217;ve said many times over by now, I&#8217;m not a marketing type of person. Although I&#8217;d love it if everyone in the world bought a copy of everyone of my books (why not two copies?), I&#8217;m not a salesman. I just don&#8217;t want to talk people into buying anything. In my mind, I write what&#8217;s hopefully a good book and people will buy it because it&#8217;s good. But just as creating a great Web site doesn&#8217;t mean people will go visit it, writing a good book doesn&#8217;t necessarily mean it will sell. So I believe this newsletter started off, in 2007, as a marketing tool, in part. Still, I never wanted it to be a &#8220;Buy! Buy! Buy!&#8221; kind of thing, but rather &#8220;here&#8217;s some other information you might appreciate and oh, by the way, here&#8217;s what&#8217;s going on with my books&#8221;. Although a number of the references in these newsletters are book related, I&#8217;ve always put the &#8220;Larry Ullman&#8217;s Book News&#8221; section last, so as not to be overbearing. That&#8217;s my thinking with the newsletter, anyway, but it&#8217;s interesting to see how it&#8217;s changed in three years.</p><p>When I began this newsletter, I didn&#8217;t think much about where it would go or how popular it might become. For most of the past three years I used the free <a
href="http://www.phplist.com/">PHPList</a>. While not great, PHPList is pretty good, especially for being free. It handles subscriptions, both HTML and plain text versions, and, in theory, bounces. Unfortunately, the subscription form required that the user click a link to go to another page (admittedly, I could have changed my design to correct this flaw). Also, I had to maintain two template versions of the site, as PHPList couldn&#8217;t integrate into my other code. (When you add in the fact that the blog was separate from the main site, the DMC Insights, Inc. site had three sets of template files to maintain, all to create a similar look. Ugh!)</p><p>When I recently moved to a complete WordPress solution for my site, I wanted something that could be integrated into WordPress. I got that with Newsletter Pro, a commercial plug-in (it&#8217;s only like $20). Newsletter Pro integrated perfectly with WordPress and by placing a subscription form front and center, there were frequent new subscribers. Then I went to use the plug-in to send a newsletter for the first time and had the aforementioned links problem (what&#8217;s the HTML entity for egg on one&#8217;s face?) Granted, another review of the newsletter on my part would have caught that, but I was also having a hard time figuring out how to customize the newsletter&#8217;s HTML template. Forced into sending HTML-only email, a custom template became a pseudo-requirement in my mind. But the developer of the Newsletter Pro plugin isn&#8217;t great about documentation or support (even though it&#8217;s a commercial product), so I suspected the template customization was one of several significant hurdles to come. Plus the Newsletter Pro system didn&#8217;t seem to handle bounces properly and the spam filters for some users were blocking the content (even though they were subscribers). I decided to look into alternative systems.</p><p>In the process of researching how to make HTML emails look sharp across the variety of email clients, I came upon Campaign Monitor, which provides email marketing software. Unlike the solutions I&#8217;ve used thus far, it&#8217;s a commercial route, but perhaps it&#8217;s time for that, if only for a bit more professionalism and peace of mind. It&#8217;s going to cost me maybe $20/month to send out one newsletter per month, which seems fair enough. And because of spam protections and the like, the Campaign Monitor system should have better luck getting my newsletter into everyone&#8217;s inbox. Campaign Monitor will send out both HTML and plain text versions, and I can still use a WordPress plugin to tie the subscription into my main site. As I&#8217;ve said many times over, I hate spending money, but with over 1,200 subscribers, I can&#8217;t afford to go the cheap route anymore. And if you&#8217;re curious how big the newsletter has become: you&#8217;re one of over 1,200 subscribers! I don&#8217;t know that that is a lot, but it seems like a grand number to me.</p><p>Of course, the key to a good newsletter is the content. In creating the new version of my site, I imported all 32 previous newsletters into WordPress. The first thing that struck me was how long they&#8217;ve become! There&#8217;s a classic quote from Blaise Pascal that, translated into English, goes &#8220;I have made this letter longer only because I have not had the leisure of making it shorter.&#8221; Which is to say it takes time to be concise. That is part of the issue for me. Another factor is that the newsletter used to be one main topic, plus maybe a paragraph on three or four others. Now the newsletter is one main topic, plus a paragraph on three or four others and a couple of paragraphs on three or four more. But I&#8217;m not getting any complaints and as I&#8217;m only sending out one newsletter per month, longer makes more sense (i.e., hopefully there&#8217;s something in each newsletter for everyone). On the other hand, perhaps if I were to send them out more frequently, there&#8217;d be less I feel the need to say in each.</p><p>In terms of how I produce the newsletter, I originally created it in my trusty text editor. I&#8217;d look at my email, my browser&#8217;s bookmarks, my blog postings, and so forth, compile a random collection of thoughts and questions, write it out, add HTML, etc. For 30 newsletters, that&#8217;s the &#8220;system&#8221; I used. A couple of newsletters back I started using <a
href="http://www.literatureandlatte.com/scrivener.php">Scrivener</a>, an excellent word processing application for Macs. One benefit of Scrivener is that it organizes projects so that I can have both my research (i.e., my collection of potential topics) and my writing in the same application, saving me from switching from program to program. Once a draft was complete, I&#8217;d still output the text and open it in my programming text editor where I could add the HTML. For this newsletter, I&#8217;ve finally started using <a
href="http://daringfireball.net/projects/markdown/">Markdown</a>, a markup syntax supported by Scrivener and many other applications (I may write my JavaScript book using Markdown or <a
href="http://fletcherpenney.net/multimarkdown/">Multimarkdown</a>, too). With Markdown, I use very simple symbols and formatting—but absolutely no HTML tags—and can still output HTML. I think adopting Markdown is going to save me a lot of time and if you do any writing yourself that&#8217;s intended for one or more destinations, it&#8217;s worth your time to check it out, as well.</p><p>So looking back, what have I learned in three years? One, my word do I have a lot to say! Two, I&#8217;m extremely fortunate to have the <em>following</em> I do (I hate to use that word, but I couldn&#8217;t think of a better, less egocentric one offhand). Third, the odds of getting questions and comments goes up dramatically when I&#8217;m giving away books! (Although with 1,200 subscribers, it&#8217;d be overwhelming if everyone replied to every newsletter.) Fourth, when you don&#8217;t really have a long-term plan, you can&#8217;t be too surprised by where you end up. Fifth, sometimes spending a little money is worth it. And sometimes not! Finally, and most importantly, the evolution of the newsletter has been a good reminder to me that you have to be willing to constantly reconsider how you do things. The right solution today is virtually guaranteed not to be the best solution tomorrow. Thinking otherwise is how you get left behind.</p><h2 id="giveaway">Book Giveaway => &#8220;Effortless E-Commerce&#8230;&#8221; and &#8220;Effortless Flex&#8230;&#8221;</h2><p><em>You must be subscribed to the newsletter in order to qualify for the book giveaway.</em></p><h2 id="news">Larry Ullman&#8217;s Book News => &#8220;Effortless E-Commerce&#8221;, &#8220;PHP for the Web&#8221;, and More!</h2><p>As mentioned in my previous newsletter, five chapters from my &#8220;Effortless E-Commerce with PHP and MySQL&#8221; book have extra content, available as PDFs. I&#8217;m also writing some extra code and posts, such as showing how the stored procedures used in the book&#8217;s second example would be written using standard PHP and MySQL (mentioned above). You can find all of this and any other extra that come up specifically for that book through <a
href="http://www.LarryUllman.com/tag/ecom/">www.LarryUllman.com/tag/ecom/</a>.</p><p>On a similar note, I just agreed to write four articles and five blog posts for <a
href="http://www.Peachpit.com">Peachpit Press&#8217;s Web site</a>, all supporting the &#8220;Effortless E-Commerce with PHP and MySQL&#8221; book. The blog posts will discuss the five most important security criteria for e-commerce sites, similar to a question that I answered in a blog comment. The four articles will explain how to implement extra features in an e-commerce site. The specific features are: adding customer reviews, product recommendations, an Ajax-enabled shopping cart, and an Ajax-enabled product rating system. I&#8217;m writing these over the next month and they&#8217;ll go online in early 2011. I&#8217;ll post links to them on my Web site as they go live.</p><p>I just completed Chapter 7 of my next book: the fourth edition of &#8220;PHP for the Web: Visual QuickStart Guide&#8221;. Largely the revision will fix any minor problems, update the code for the latest version of PHP, and add a &#8220;Review and Pursue&#8221; section to the end of each chapter. That section will consist of both questions (based upon the chapter&#8217;s content) and prompts for what else the reader can try using the information they just learned. If there&#8217;s room, I&#8217;m thinking about adding one short example chapter, similar to those at the end of the PHP and MySQL book.</p><p>My self-published JavaScript book is still on the docket and should be actively pursued starting in January. I have a couple of months before I&#8217;ll need to work on the fourth edition of my &#8220;PHP and MySQL for Dynamic Web Sites: Visual QuickPro Guide,&#8221; so I&#8217;ll try to do as much as possible on the JavaScript book in that interim.</p> ]]></content:encoded> <wfw:commentRss>http://www.larryullman.com/2010/12/12/what-is-larry-thinking-34-e-commerce-and-newsletters/feed/</wfw:commentRss> <slash:comments>0</slash:comments> </item> </channel> </rss>
<!-- Served from: www.larryullman.com @ 2012-05-21 14:43:48 by W3 Total Cache -->
