<?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>Snipe.Net &#187; php</title>
	<atom:link href="http://www.snipe.net/tags/php/feed/" rel="self" type="application/rss+xml" />
	<link>http://www.snipe.net</link>
	<description>Bitterness never tasted so sweet</description>
	<lastBuildDate>Tue, 24 Jan 2012 04:30:40 +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>Firefox Addons for Penetration/XSS Testing</title>
		<link>http://www.snipe.net/2010/10/firefox-addons-xss-testing/</link>
		<comments>http://www.snipe.net/2010/10/firefox-addons-xss-testing/#comments</comments>
		<pubDate>Thu, 14 Oct 2010 19:25:48 +0000</pubDate>
		<dc:creator>snipe</dc:creator>
				<category><![CDATA[Featured]]></category>
		<category><![CDATA[PHP/mySQL]]></category>
		<category><![CDATA[Web Development]]></category>
		<category><![CDATA[addons]]></category>
		<category><![CDATA[exploits]]></category>
		<category><![CDATA[firefox]]></category>
		<category><![CDATA[hacked]]></category>
		<category><![CDATA[penetration testing]]></category>
		<category><![CDATA[php]]></category>
		<category><![CDATA[security]]></category>
		<category><![CDATA[xss]]></category>

		<guid isPermaLink="false">http://www.snipe.net/?p=2843</guid>
		<description><![CDATA[2010 was supposed to be the year of the Tiger, but it&#8217;s felt more like the year of Pwny so far. This article covers some Firefox add-ons that help you test your own apps, whether you&#8217;re working with a penetration tester, or by default, you are the penetration tester. I&#8217;ll start with the obvious candidates [...]]]></description>
			<content:encoded><![CDATA[<p>2010 was supposed to be the year of the Tiger, but it&#8217;s felt more like the year of Pwny so far. This article covers some Firefox add-ons that help you test your own apps, whether you&#8217;re working with a penetration tester, or by default, you <em>are</em> the penetration tester.<br />
<span id="more-2843"></span></p>
<p>I&#8217;ll start with the obvious candidates that you probably already have installed if you&#8217;re a developer. I&#8217;ve also added a few that are useful for post-hack diagnostics and recovery.</p>
<h4>General</h4>
<p><strong><a href="https://addons.mozilla.org/en-US/firefox/addon/1843/">Firebug</a></strong> &#8211; Firebug is great for web development in general, but the debugging tools can help track down calls to rogue javascript on external servers, among many other things.</p>
<p><strong><a href="https://addons.mozilla.org/en-US/firefox/addon/60/">Web Developer Toolbar</a></strong> &#8211; Another great web dev tool, the Web Developer Toolbar makes it easy to turn javascript and cookies on and off selectively, view form fields and disable restrictions and much, much more. </p>
<p><strong><a href="https://addons.mozilla.org/en-US/firefox/addon/5914/">DNS Cache</a></strong> &#8211; simple addon that lets you clear or disable Firefox&#8217;s DNS cache. Not specifically for pen testing, but useful nonetheless.</p>
<p><strong><a href="https://addons.mozilla.org/en-US/firefox/addon/14503/">Notable</a> </strong>- love this addon, which lets you do a full-page screenshot with annotations over at <a href="https://www.notableapp.com/">notableapp.com</a>. As you&#8217;re testing, there&#8217;s a good chance you&#8217;re going to need to show your other devs or account managers a screenshot so they can see the vulnerability being exploited. While something simple like Fireshot would work fine (or native screenshots), I like using Notable for complex situations that require explanations on multiple points on the page. Exports to annotated PDF.</p>
<p><strong><a href="https://addons.mozilla.org/en-US/firefox/addon/46698/">Groundspeed</a></strong> &#8211; simple form toolkit that allows you to edit form fields (hidden to text, etc), remove length restrictions, change/remove javascript event handlers, and change form target so that it opens in a new tab.</p>
<h4>Code Injection</h4>
<p><strong><a href="https://addons.mozilla.org/en-US/firefox/addon/7597/">SQL Inject Me</a></strong> &#8211; helps test for SQL injection vulnerabilities.</p>
<p><strong><a href="https://addons.mozilla.org/en-US/firefox/addon/7598/">XSS Me</a></strong> &#8211; used to test for reflected Cross-Site Scripting (XSS). It does NOT currently test for stored XSS.</p>
<p><strong><a href="https://addons.mozilla.org/en-US/firefox/addon/7595/">Access Me</a></strong> &#8211; used to test some access vulnerabilities related to web applications. The tool works by sending several versions of the last page request. A request with the session removed will be sent. A request using the HTTP HEAD verb and a request using a made up SECCOM verb will be sent. A combination of session and HEAD/SECCOM will also be sent.</p>
<p><strong><a href="https://addons.mozilla.org/en-US/firefox/addon/10345/">JS Deobfuscator</a></strong> &#8211; many attacks inject obfuscated javascript into a page so that it becomes harder for you to simply grep the source for something obvious, like the domain name to which the bad script is redirecting the user. This addon helps deobfuscate the javascript so you can see what&#8217;s really going on.</p>
<p><strong><a href="https://addons.mozilla.org/en-US/firefox/addon/3899/">Hackbar</a></strong> &#8211; helps with testing sql injections, XSS holes and site security. Ugly as sin, but it works well.</p>
<h4>Header and URL Monitoring/Tampering</h4>
<p>Note that some of these addons do similar things &#8211; try them and stick with whichever one you like best.</p>
<p><strong><a href="https://addons.mozilla.org/en-US/firefox/addon/6647/">HttpFox</a></strong> &#8211; monitors and analyzes all incoming and outgoing HTTP traffic between the browser and the web servers.</p>
<p><strong><a href="https://addons.mozilla.org/en-US/firefox/addon/3829/">Live HTTP Headers</a></strong> &#8211; view HTTP headers of a page and while browsing.</p>
<p><strong><a href="https://addons.mozilla.org/en-US/firefox/addon/967/">Modify Headers</a></strong> &#8211; add, modify and filter http request headers. You can modify the user-agent string, add headers to spoof a mobile request (e.g. x-up-calling-line-id) and much more.</p>
<p><strong><a href="https://addons.mozilla.org/en-US/firefox/addon/966/">Tamper Data</a></strong> &#8211; use tamperdata to view and modify HTTP/HTTPS headers and post parameters, trace and time http response/requests and security test web applications by modifying POST parameters.</p>
<p><strong><a href="https://addons.mozilla.org/en-US/firefox/addon/59/">User Agent Switcher</a></strong> &#8211; allows you to easily toggle between pre-set user agent strings, or set your own.</p>
<h4>Environment Detection</h4>
<p><strong><a href="https://addons.mozilla.org/en-US/firefox/addon/4276/">Header Spy</a></strong> &#8211; lightweight addon that displays information about the website&#8217;s server in your statusbar. This is not as useful for pen testing as it is for impressing the crap out of clients who don&#8217;t know what server they&#8217;re running. <img src='http://www.snipe.net/wp-includes/images/smilies/icon_razz.gif' alt=':P' class='wp-smiley' /> </p>
<p><strong><a href="https://addons.mozilla.org/en-US/firefox/addon/8946/">Host Spy</a></strong> &#8211; integrated shortcut to show you who a website&#8217;s IP neighbors are on shared hosting.</p>
<p><strong><a href="https://addons.mozilla.org/en-US/firefox/addon/590/">ShowIP</a></strong> &#8211; Small addons that shows the IP address of the website in your statusbar and a link to some additional tools.</p>
<p><strong><a href="https://addons.mozilla.org/en-US/firefox/addon/3572/">URL Flipper</a></strong> &#8211; quickly and easily increment and decrement numbers and strings in URLs for navigating through URL sequences (for example, user ids or session info in the query string.)</p>
<p><strong><a href="https://addons.mozilla.org/en-US/firefox/addon/10229/">Wappalyzer</a></strong> &#8211; uncovers the technologies used on websites. It detects CMS and e-commerce systems, message boards, JavaScript frameworks, hosting panels, analytics tools and several more.</p>
<h4>Searching</h4>
<p><strong><a href="https://addons.mozilla.org/en-US/firefox/addon/49858/">Offensive Security Exploit Database</a> </strong> &#8211; this adds the excellent database of exploits at <a href="http://www.exploit-db.com">exploit-db.com</a> as one of your search engine options.</p>
<p>I&#8217;ve also just created a <strong>search plugin for XSSed.Com</strong>, <del datetime="2010-10-15T01:43:53+00:00">but it&#8217;s pending approval at Mozilla, so not sure when that will be ready for you</del> which can be <strong><a href="https://addons.mozilla.org/en-US/firefox/addon/241845/">downloaded here</a></strong>. It&#8217;s not exactly rocket science to add a new search site to your browser search bar, but I figured it was quick and easy to whip up. Feel free to check out the <a href="https://addons.mozilla.org/en-US/firefox/files/browse/101135">source code for the plugin here</a>.</p>
<h4>Too Many Addons Got You Down?</h4>
<p>If you&#8217;re finding your plugins are slowing down Firefox too much, you might want to create a separate Firefox profile specifically for testing, and switch to that profile when you&#8217;re ready to start hammering away. Also bear in mind that you might need to tweak some settings on these, or only enable them right before you use them, as the toolbars and sidebars can be a bit bulky.</p>
<p>Also keep in mind that the Net option on the web developers toolbar, or any of the header analyzer addons can be very helpful in general testing between dev and live environments (load the page on live and make sure nothing is being pulled from the dev address) and also to make sure your SSL requests are being handled correctly.</p>
<h4>Some Additional Thoughts&#8230;</h4>
<p>When folks ask me how I do penetration testing &#8211; whether I use software, or do it by hand &#8211; the best way I can answer is &#8220;both&#8221;. Software will only ever get you so far, but it&#8217;s a critical tool in helping you figure out where the vulnerabilities are. It&#8217;s not unlike using a metal detector to find treasure. When the metal detector is doing its job, it finds, well, metal. Not necessarily treasure, although fancier metal detectors have additional software that helps try to identify the buried object by shape and size. You still have to physically dig up the item and rely on your knowledge and experience to determine whether or not it really is treasure, or just junk. The metal detector simply finds something that meets a basic set of requirements, to save you from having to dig up every square inch of the beach. </p>
<p>When testing web applications for vulnerabilities, software does very much the same thing. It simply automates tasks that you could do by hand but that would take an unreasonable amount of time, but ultimately when it finds something, you still need to know enough about what you&#8217;re looking at to determine how big a threat it actually is. Most of the time the software will attempt the to try the lowest-level exploit, for example, the ability to execute arbitrary javascript in a page. Your testing tools may demonstrate that you can create a javascript alertbox on the page, but it&#8217;s your knowledge and experience that will help you determine the full extent of the vulnerability, for example whether that arbitrary javascript could be used to redirect a user to a new page, hijack the user&#8217;s session data, etc.</p>
<p>The reason I ended this post with a long-winded ramble is because I wanted to make it clear that just having the tools isn&#8217;t enough. Actually using them, and knowing what to do with the results are important. Understanding the basic mechanics of how exploits work is the only way you can make sure your applications are written to mitigate them. Having the tools installed but never understanding or using them is like buying a metal detector and keeping in the closet and then wondering why you haven&#8217;t found anything valuable yet.</p>
<p><strong>If you&#8217;re interested in learning more about web application penetration testing and security, check out the following books:</strong></p>
<ul>
<li><a href="http://www.amazon.com/gp/product/0470170778?ie=UTF8&#038;tag=snipenet&#038;linkCode=as2&#038;camp=1789&#038;creative=390957&#038;creativeASIN=0470170778">The Web Application Hacker&#8217;s Handbook: Discovering and Exploiting Security Flaws</a></li>
<li><a href="http://www.amazon.com/gp/product/0596514832?ie=UTF8&#038;tag=snipenet&#038;linkCode=as2&#038;camp=1789&#038;creative=390957&#038;creativeASIN=0596514832">Web Security Testing Cookbook: Systematic Techniques to Find Problems Fast</a></li>
<li><a href="http://www.amazon.com/gp/product/1590597842?ie=UTF8&#038;tag=snipenet&#038;linkCode=as2&#038;camp=1789&#038;creative=390957&#038;creativeASIN=1590597842">Foundations of Security: What Every Programmer Needs to Know</a></li>
<li><a href="http://www.amazon.com/gp/product/1597495883?ie=UTF8&#038;tag=snipenet&#038;linkCode=as2&#038;camp=1789&#038;creative=390957&#038;creativeASIN=1597495883">Ninja Hacking: Unconventional Penetration Testing Tactics and Techniques</a></li>
</ul>
<h4>How Do You XSS?</h4>
<p>These addons are not obviously meant to be a replacement for more capable and thorough penetration testing tools such as metaploit, netsparker, etc. They&#8217;re just meant to be a convenient way for developers to test code during and after development.</p>
<p>There is a  more comprehensive collection of addons listed <a href="https://addons.mozilla.org/en-US/firefox/collections/adammuntner/webappsec/?page=1">here</a>, but this is what I use. If you&#8217;ve got a favorite that I&#8217;ve missed, please be sure to share in the comments!</p>

 <script type="text/javascript">
	<!--
		function onover(what){
	document.getElementById('blurbtext').innerHTML=''+what+'';
	}
	function onout(){
	document.getElementById('blurbtext').innerHTML='&nbsp;';
	}
	-->
	</script>



<h3 style="padding-bottom: 0px; margin-bottom: 0px;">Also check out: <br /><span id="blurbtext"><br /></span></h3>

<div id="relatedposts">




		
               

        
        
        
		<div class="yarppimg"><a href="http://www.snipe.net/2009/01/easier-cross-browser-testing/" rel="bookmark">
		<img src="http://www.snipe.net/wp-content/themes/snipe/thumb.php?src=http://www.snipe.net/wp-content/uploads/2009/01/cross_browser-compatible2.jpg&amp;h=90&amp;w=90&amp;zc=1&amp;q=95" alt="Easier Cross-Browser Testing" height="90" width="90" onmouseover="onover('Easier Cross-Browser Testing')" onmouseout="onout()" /></a></div>

			
               

        
        
        
		<div class="yarppimg"><a href="http://www.snipe.net/2007/01/firefox-extensions-i-cant-live-without/" rel="bookmark">
		<img src="http://www.snipe.net/wp-content/themes/snipe/thumb.php?src=http://www.snipe.net/wp-content/uploads/2008/06/firefox_eats_ie.jpg&amp;h=90&amp;w=90&amp;zc=1&amp;q=95" alt="Firefox extensions I can&#8217;t live without" height="90" width="90" onmouseover="onover('Firefox extensions I can&#8217;t live without')" onmouseout="onout()" /></a></div>

			
               

        
        
        
		<div class="yarppimg"><a href="http://www.snipe.net/2008/06/hacking-firefox/" rel="bookmark">
		<img src="http://www.snipe.net/wp-content/themes/snipe/thumb.php?src=http://www.snipe.net/wp-content/uploads/2008/06/firefox.jpg&amp;h=90&amp;w=90&amp;zc=1&amp;q=95" alt="Hacking Firefox" height="90" width="90" onmouseover="onover('Hacking Firefox')" onmouseout="onout()" /></a></div>

	</div>

]]></content:encoded>
			<wfw:commentRss>http://www.snipe.net/2010/10/firefox-addons-xss-testing/feed/</wfw:commentRss>
		<slash:comments>4</slash:comments>
		</item>
		<item>
		<title>Microsoft Web Developer&#8217;s Summit 2009</title>
		<link>http://www.snipe.net/2009/12/mswds09/</link>
		<comments>http://www.snipe.net/2009/12/mswds09/#comments</comments>
		<pubDate>Sun, 06 Dec 2009 03:20:31 +0000</pubDate>
		<dc:creator>snipe</dc:creator>
				<category><![CDATA[Featured]]></category>
		<category><![CDATA[PHP/mySQL]]></category>
		<category><![CDATA[Web Development]]></category>
		<category><![CDATA[microsoft]]></category>
		<category><![CDATA[mswds]]></category>
		<category><![CDATA[open source]]></category>
		<category><![CDATA[php]]></category>
		<category><![CDATA[webdev]]></category>
		<category><![CDATA[windows]]></category>

		<guid isPermaLink="false">http://www.snipe.net/?p=2557</guid>
		<description><![CDATA[I had the opportunity this week to go out to Redmond, Washington to attend the Microsoft Web Developer&#8217;s Summit at the MS headquarters. For this summit, about 25 leaders in the PHP (and PHP project) community were invited out to sit down with members of the MS product development teams and provide critical, honest feedback [...]]]></description>
			<content:encoded><![CDATA[<p>I had the opportunity this week to go out to Redmond, Washington to attend the Microsoft Web Developer&#8217;s Summit at the MS headquarters. For this summit, about 25 leaders in the PHP (and PHP project) community were invited out to sit down with members of the MS product development teams and provide critical, honest feedback about Microsoft.<br />
<span id="more-2557"></span></p>
<h3>Background</h3>
<p>The MSWDS is one of only four significant annual events within the PHP community (others include tek, DPC and ZendCon), and this summit is a bit harder to get invited to. Unlike most other conferences, where all you need is the cash to pony up for a conference pass and a hotel room to crash in, invites are very limited and attendees are selected because they have had some interaction with the folks at Microsoft, and are believed to be leaders and influencers within the open source community. To be blunt, these summits cost Microsoft a lot of money, so they need to make sure they&#8217;re getting the best bang for their buck.</p>
<p><img src="http://www.snipe.net/wp-content/uploads/2009/12/IMG_0065-sm.jpg" alt="IMG_0065-sm" title="IMG_0065-sm" width="200" height="126" class="alignright size-full wp-image-2577" />Keeping that in mind, it would be easy to assume that we were being brought out there so that Microsoft could pitch us on the latest and greatest Microsoft products, trying to get the movers and shakers of open source to drink the corporate kool-aid and switch to Microsoft products. While more acceptance of Microsoft products within the open source community is obviously a goal, they are making a concerted effort to learn from us &#8211; what we need, where they are falling short, and how we can move forward together.</p>
<h3>Discussions and Format</h3>
<p>The summit itself was a total of three days, with the last day being optional for those open source developers who were willing to sign an NDA to discuss some of Microsoft&#8217;s emerging technology. During the three days, different representatives from Microsoft&#8217;s product teams sat down with us and asked for our comments, thoughts and ideas about where they&#8217;re at, and where we think they should be going. We met with folks from the <a href="http://microsoft.com/web/">IIS Web Platform</a> team, the <a href="http://www.microsoft.com/sqlserver/2008/en/us/default.aspx">SQL server</a> team, as well as some representatives from <a href="http://www.codeplex.com/">Codeplex</a>, <a href="http://silverlight.net/">Silverlight</a>, <a href="http://technet.microsoft.com/en-us/library/bb978526.aspx">Powershell</a>, <a href="http://www.asp.net/%28S%28waglea45zymnbmbli4vgme45%29%29/ajax/">ASP.NET Ajax</a> (which is not exclusive to ASP.NET, despite the name), and <a href="http://www.bing.com/maps/explore/">Bing maps</a>. </p>
<p>We had a chance to air grievances, which was cathartic in some ways, but I think it was more important to us to be able to sit down with the actual teams who are working on this technology at Microsoft, and really get into the specific challenges we face. The approach was not generally pitchy, and with very few exceptions, a great deal of effort was put into making all of us from the open source community feel like respected authorities in our field whose opinions really matter. </p>
<p>Something they did this year which was apparently not done last year was to include representatives from well-known PHP-based projects who are not normally parts of the PHP community. I honestly hadn&#8217;t realized that the many of the folks over Joomla, WordPress and Drupal often don&#8217;t consider themselves as part of the greater PHP community, and getting a chance to discuss that with them brought up some interesting perspectives. I don&#8217;t think the guys representing these projects were there in an official capacity, but their point of view was one that had honestly not occurred to me before, so that was a really interesting and unexpected benefit. There was some debate on whether or not these types of projects should be a more involved part of the PHP community, with good points on both sides, but I think most walked away with some ideas on how to move forward in making those lines of communication more accessible and open.</p>
<h3>My Perspective</h3>
<p>Of course the ultimate question from Microsoft was &#8220;What would it take for you to switch to Microsoft products for your clients?&#8221; My smartass remark was, of course &#8220;A fucking miracle.&#8221; But everyone in the room knew I was joking. I hope. If we weren&#8217;t willing to work with Microsoft on improving their products to work with open source better, we wouldn&#8217;t have been there. </p>
<p>As often as Microsoft has been an easy target in the past, and as much bad blood as there may have been in the past, there <em>are</em> people at Microsoft that care about working with the open source community, and who are making progress to get there. It is our job as technology professionals to fairly evaluate technology and make recommendations based on what makes the most sense technologically and financially. It is NOT our job to make religious decisions based on zealotry. </p>
<p>That means that if and when Microsoft can meet my needs and/or the needs of my clients, it can and should be part of that evaluation or I&#8217;m not doing my job. Does that mean I&#8217;m ready to switch back? No. Not yet, anyway. But I believe they are listening, and I saw some things during this summit that make me far more likely to start including some parts of Microsoft&#8217;s products into the technology I suggest as being potentially viable for client projects, which is a far cry closer than I was last week. Specifically, some of the stuff I learned about Silverlight, Bing&#8217;s geolocation products and Windows Azure (Microsoft&#8217;s cloud hosting platform) was pretty impressive. As I get to play with these products a little more, I&#8217;ll be blogging about them with my fair evaluation of pros and cons, so stay tuned.</p>
<p>I&#8217;m also excited to see where the <a href="http://www.microsoft.com/web/Downloads/platform.aspx">Microsoft Web Platform Installer product</a> heads. Right now, the WebPI product is a very easy to use, slick solution for the less techy individual who wants to, for example, deploy a WordPress blog in 5 minutes or less and may not have the savvy to do the install themselves &#8211; basically a MS version of Cpanel/Fantastico, which we have had available to us as web administrators for over a decade. That product is less interesting to me right now, but some of the directions they could go in for more advanced users like us hold real potential. We had some suggestions that were well-received, and if they are actually implemented in the way I envision them, it could honestly turn the table and make some of the Microsoft web server products something that I could consider recommending, or even using myself. (I should also mention that Cpanel is the most horrific, insecure, hack-prone web control panel I&#8217;ve ever used, and I am NOT endorsing it as a solution.)</p>
<p>The reality is that competition inspires innovation, and Microsoft getting better means progress for everyone. I saw a post on Twitter that basically implied that open source representatives attending this conference were traitors or sellouts. I don&#8217;t see it that way at all. We have amazing open source products like Firefox because the open source community worked together to create a better product, and Microsoft responded by making vast improvements to Internet Explorer, building in more security and standards compliance. <strong>When we work together to innovate, everybody wins.</strong></p>
<p>Another transition I&#8217;ve been seeing in Microsoft which was really made more obvious by this summit is that there is a less omnipresent feeling of &#8220;all or nothing&#8221; within many Microsoft departments. As open source advocates, we enjoy having choices. Previously with Microsoft, you&#8217;d get the most benefit from their products by committing to an entirely Microsoft development process (&#8220;drinking <em>all</em> of the kool-aid, since the best stuff is the sugary goop at the bottom&#8221;), with benefits sharply falling off if you opted to pick and choose. This philosophy has always been distinctly in opposition with the open source philosophy, and I believe was likely the cause for some of the distrust coming from the open source community. Seeing this transition into a paradigm of being able to cherry-pick what we like for some things and sticking with open source solutions we like better for others is a step in the right direction, in my opinion. </p>
<p>An additional unexpected benefit to sitting down with all these MS product people was that I got a chance to better understand some of the legal/licensing challenges Microsoft faces. I&#8217;m not making excuses for them, but I hadn&#8217;t considered some of the obstacles in the way of people at MS who care about working with us. Microsoft is a big target with deep pockets, and they have to cover their own asses. I was quicker to dismiss some of the corporate decisions as being &#8220;evil&#8221; prior to sitting down with some of them and understanding why they do what they do. Don&#8217;t get me wrong &#8211; some of their decisions (*cough*sudo*cough*) still don&#8217;t make sense to me and I believe they are wrong, but I think I have a better understanding of where they sit than I did before</p>
<h3>Wrapping Up</h3>
<p>Overall, I would consider this summit a great success, and I hope I get to participate again in the future. There are several people who really deserve a shout-out for all of the hard work that went into this and are directly responsible for it&#8217;s success. From the PHP community, <a href="http://blog.calevans.com/">Cal Evans</a> was a co-host and an absolute rock star, always quick to make sure things ran smoothly and kick-start conversations and redirect us back when we went off on tangents. From Microsoft, Karri Dunn, Tonya Young, Josh Holmes, Peter Laudati, Lauren Cooney, and others were amazing. I may be forgetting a few &#8211; I am still a little wiped from the week and the traveling.</p>
<p>Was this an instant fix? Certainly not. Do we all have a lot more work to do before we&#8217;re &#8220;there&#8221;? Absolutely. But as Cal Evans put it on his own blog roundup, &#8220;The more people I get to know at Microsoft, the less I’m able to despise the company.&#8221; They took the time to find out what we think, even when it may not have been what they wanted to hear. Time will tell whether or not they actually act on it. </p>
<h3>Other PHP Representatives Blog Post Roundups</h3>
<p>I&#8217;ll be updating this list as more people finish their blog post roundups, so you can get take their on the summit. Many of them are far smarter than I am, so it&#8217;s worth reading what they have to say.</p>
<ul>
<li><a href="http://blog.calevans.com/2009/12/05/mswds09/">Cal Evans</a> (<a href="http://twitter.com/CalEvans">@CalEvans</a>)</li>
<li><a href="http://blog.phpdeveloper.org/?p=246">Chris Cornutt</a> (<a href="http://twitter.com/enygma">@enygma</a>)</li>
<li><a href="http://blog.maartenballiauw.be/post/2009/12/07/Microsoft-Web-Development-Summit-2009.aspx">Maarten Balliauw</a> (<a href="http://twitter.com/maartenballiauw">@maartenballiauw</a>)</li>
<li><a href="http://www.rafaeldohms.com.br/2009/12/04/microsoft-web-developer-summit-2009-in-review/en/">Rafael Dohms</a> (<a href="http://twitter.com/rdohms">@rdohms</a>)</li>
<li><a href="http://blueparabola.com/blog/microsoft-web-developer-summit-2009">Keith Casey</a> (<a href="http://twitter.com/CaseySoftware">@CaseySoftware</a>)</li>
<li><a href="http://blog.wampserver.com/index.php/2009/12/05/microsoft-web-development-summit-2009/">Romain Bourdon</a> (in French) (<a href="http://twitter.com/le_vrai_roms">@le_vrai_roms</a>)</li>
<li><a href="http://blog.tabini.ca/2009/12/09/microsoft-is-and-microsoft-does/">Marco Tabini</a> (<a href="http://twitter.com/mtabini">@mtabini</a>)</li>
<li><a href="http://community.joomla.org/blogs/community/1088-slowing-back-down-mswds-and-jdc09-reflection.html">Sam Moffatt</a> (<a href="http://twitter.com/Pasamio">@Pasamio</a>)</li>
<li><a href="http://blog.echolibre.com/2009/12/microsoft-web-developer-summit/">Helgi Þormar Þorbjörnsson</a> (<a href="http://twitter.com/h">@h</a>)</li>
</ul>
<h3>MS Representative Blogs</h3>
<p>If you&#8217;d like to see more about the fabulous people at MS who are working hard to move the company forward in a way that works with open source, check out their blogs. I&#8217;m proud to call these guys friends, and as long as we continue to have people like this working for Microsoft, I think the lines of communication and cooperation between both sides of the aisle will keep moving forward.</p>
<ul>
<li><a href="http://www.davebost.com/blog/">Dave Bost</a> (<a href="http://twitter.com/DaveBost">@DaveBost</a>)  &#8211; Developer Evangelist</li>
<li><a href="http://www.joshholmes.com/blog/">Josh Holmes</a> (<a href="http://twitter.com/JoshHolmes">@JoshHolmes</a>) &#8211; UX Architect Evangelist</li>
<li><a href="http://blogs.iis.net/tobintitus/">Tobin Titus</a> (<a href="http://twitter.com/tobint">@tobint</a>) &#8211; MSDN Site Manager</li>
<li><a href="http://blogs.msdn.com/peterlau/">Peter Laudati</a> (<a href="http://twitter.com/jrzyshr">@jrzyshr</a>) &#8211; Developer Evangelist</li>
<li><a href="http://blogs.msdn.com/markbrown/">Mark Brown</a> (<a href="http://twitter.com/markjbrown">@MarkJBrown</a>) &#8211; Product Manager for Microsoft Web Platform</li>
<li>William Coleman (<a href="http://twitter.com/will_coleman">@will_coleman</a>) &#8211; Developer Evangelist</li>
<li>Lauren Cooney (<a href="http://twitter.com/lcooney ">@lcooney</a>) &#8211; GPM for Web Platforms at Microsoft</li>
<li>Jas Sandhu (<a href="http://twitter.com/jassand">@jassand</a>) &#8211; Interop Strategy Evangelist</li>
<li><a href="http://ruslany.net/">Ruslan Yakushev</a> (<a href="http://twitter.com/ruslany">@ruslany</a>) &#8211; Program Manager on IIS team in charge of FastCGI and PHP support</li>
<li><a href="http://hanselman.com">Scott Hanselman</a> (<a href="http://twitter.com/shanselman">@shanselman</a>)  &#8211; Principal Program Manager Lead</li>
</ul>
<p>Funnily, as I&#8217;m writing this, <em>Futurama: Into the Wild Green Yonder</em> has been on television, and the scene that just played is the one where Calculon says &#8220;I&#8217;d like to thank the academy, my agent, and most of all my operating system &#8211; Windows 7, for everything it &#8211;&#8221; at which point his OS locks up. Windows 7 is actually a great product, and I run it on my Mac using Bootcamp and VM Fusion, but I thought the timing was amusing.</p>
<p><em>Kool-aid photo taken in <a href="http://www.snipe.net/2009/02/getting-to-know-belize/">Belize</a> by me &#8211; just thought it was funny. Lead post image by <a href="http://eliw.com/">Eli White</a>.</em></p>

 <script type="text/javascript">
	<!--
		function onover(what){
	document.getElementById('blurbtext').innerHTML=''+what+'';
	}
	function onout(){
	document.getElementById('blurbtext').innerHTML='&nbsp;';
	}
	-->
	</script>



<h3 style="padding-bottom: 0px; margin-bottom: 0px;">Also check out: <br /><span id="blurbtext"><br /></span></h3>

<div id="relatedposts">




		
               

        
        
        
		<div class="yarppimg"><a href="http://www.snipe.net/2009/02/practical-mod_rewrite/" rel="bookmark">
		<img src="http://www.snipe.net/wp-content/themes/snipe/thumb.php?src=http://www.snipe.net/wp-content/uploads/2009/02/dave.jpg&amp;h=90&amp;w=90&amp;zc=1&amp;q=95" alt="Practical Mod_Rewrite for Web Developers" height="90" width="90" onmouseover="onover('Practical Mod_Rewrite for Web Developers')" onmouseout="onout()" /></a></div>

			
               

        
        
        
		<div class="yarppimg"><a href="http://www.snipe.net/2011/01/facebook-https-opt-in/" rel="bookmark">
		<img src="http://www.snipe.net/wp-content/themes/snipe/thumb.php?src=http://www.snipe.net/wp-content/uploads/2011/01/Facebook-Needle.jpg&amp;h=90&amp;w=90&amp;zc=1&amp;q=95" alt="Facebook Introduces HTTPS Opt-In for Users, Impacts App Developers" height="90" width="90" onmouseover="onover('Facebook Introduces HTTPS Opt-In for Users, Impacts App Developers')" onmouseout="onout()" /></a></div>

			
               

        
        
        
		<div class="yarppimg"><a href="http://www.snipe.net/2008/07/identify-and-fix-sql-injection-vulnerabilities-in-web-applications/" rel="bookmark">
		<img src="http://www.snipe.net/wp-content/themes/snipe/thumb.php?src=http://www.snipe.net/wp-content/uploads/2008/07/screenshot.jpg&amp;h=90&amp;w=90&amp;zc=1&amp;q=95" alt="Identify and Fix SQL Injection Vulnerabilities in Web Applications" height="90" width="90" onmouseover="onover('Identify and Fix SQL Injection Vulnerabilities in Web Applications')" onmouseout="onout()" /></a></div>

	</div>

]]></content:encoded>
			<wfw:commentRss>http://www.snipe.net/2009/12/mswds09/feed/</wfw:commentRss>
		<slash:comments>6</slash:comments>
		</item>
		<item>
		<title>Web 2-Point-Owned: Apple.Com&#8217;s XSS Exploit</title>
		<link>http://www.snipe.net/2009/11/apple-coms-xss-exploit/</link>
		<comments>http://www.snipe.net/2009/11/apple-coms-xss-exploit/#comments</comments>
		<pubDate>Wed, 04 Nov 2009 03:20:06 +0000</pubDate>
		<dc:creator>snipe</dc:creator>
				<category><![CDATA[Featured]]></category>
		<category><![CDATA[Web Development]]></category>
		<category><![CDATA[exploits]]></category>
		<category><![CDATA[php]]></category>
		<category><![CDATA[security]]></category>
		<category><![CDATA[xss]]></category>

		<guid isPermaLink="false">http://www.snipe.net/?p=2505</guid>
		<description><![CDATA[Earlier today, we got a glimpse of what happens when a big company forgets to cross their t&#8217;s and dot their i&#8217;s. And in programming, that means failing to validate user-entered data before displaying it on-screen. My friend Peter Bukowinski first brought the exploit to my attention, posting a link to Apple.Com&#8217;s iTunes affiliate search [...]]]></description>
			<content:encoded><![CDATA[<p>Earlier today, we got a glimpse of what happens when a big company forgets to cross their t&#8217;s and dot their i&#8217;s. And in programming, that means failing to validate user-entered data before displaying it on-screen.</p>
<p><span id="more-2505"></span></p>
<p>My friend <a href="http://twitter.com/pmbuko" target="_blank">Peter Bukowinski</a> first brought the exploit to my attention, posting a link to Apple.Com&#8217;s iTunes affiliate search interface. The link he sent me led to a page that looked like this:</p>
<p><a href="http://www.snipe.net/wp-content/uploads/2009/11/Screen-shot-2009-11-03-at-5.13.10-PM.png"><img class="aligncenter size-large wp-image-2506" title="Screen shot 2009-11-03 at 5.13.10 PM" src="http://www.snipe.net/wp-content/uploads/2009/11/Screen-shot-2009-11-03-at-5.13.10-PM-560x426.png" alt="Screen shot 2009-11-03 at 5.13.10 PM" width="560" height="426" /></a></p>
<p>Notice that the url in the browser bar is actually apple.com &#8211; this was not a parody site.</p>
<p>Evidently, Apple&#8217;s developers had neglected to validate the data being sent through the query string. The actual url was:</p>
<p><em>http://www.apple.com/itunes/affiliates/download/?artistName=your+mom&amp;thumbnailUrl=http://www.moneysavingmom.com/money_saving_mom/images/2008/09/02/joblogo.gif&amp;itmsUrl=http://www.bjs.com/&amp;albumName=a+better+blowjob</em></p>
<p>So by editing the variables passed through the url, you could have a little harmless fun at Apple&#8217;s expense:</p>
<p><a href="http://www.snipe.net/wp-content/uploads/2009/11/Screen-shot-2009-11-03-at-5.24.38-PM.png"><img class="aligncenter size-large wp-image-2508" title="Screen shot 2009-11-03 at 5.24.38 PM" src="http://www.snipe.net/wp-content/uploads/2009/11/Screen-shot-2009-11-03-at-5.24.38-PM-560x426.png" alt="Screen shot 2009-11-03 at 5.24.38 PM" width="560" height="426" /></a></p>
<p>As you can see, by editing the query string and changing the variables for artistName, thumbnailUrl and itmsUrl, we could make the page hosted on Apple.Com&#8217;s server display whatever mischief we want. The variables were being echoed out directly on the page without any validation, filling in the blanks in their iTunes affiliate page template: [image] Looking for [blank] by [blank]?</p>
<h2>But What is XSS?</h2>
<p>Honestly, if you&#8217;re a web developer and you don&#8217;t know what XSS is by now, you suck at your job and should probably go back to spanking it to porn in your mom&#8217;s basement and leave the coding to the grownups. It&#8217;s been around long enough that you forfeit your right to call yourself a web-anything if you don&#8217;t know what it is by now. That said&#8230;</p>
<p>From the <a href="http://www.cgisecurity.com/xss-faq.html" target="_blank">Cross-Site Scripting FAQ on cgisecurity.com</a>:</p>
<blockquote><p>Cross site scripting (also known as XSS) occurs when a web application gathers malicious data from a user. The data is usually gathered in the form of a hyperlink which contains malicious content within it. The user will most likely click on this link from another website, instant message, or simply just reading a web board or email message. Usually the attacker will encode the malicious portion of the link to the site in HEX (or other encoding methods) so the request is less suspicious looking to the user when clicked on. After the data is collected by the web application, it creates an output page for the user containing the malicious data that was originally sent to it, but in a manner to make it appear as valid content from the website. Many popular guestbook and forum programs allow users to submit posts with html and javascript embedded in them. If for example I was logged in as &#8220;john&#8221; and read a message by &#8220;joe&#8221; that contained malicious javascript in it, then it may be possible for &#8220;joe&#8221; to hijack my session just by reading his bulletin board post.</p></blockquote>
<p><strong>Cross-Site Scripting is nothing new, not even on large, popular websites.</strong> While this example on Apple.Com resulted only in a humorous page being available under a large company&#8217;s domain, many XSS attacks can be far more sinister &#8211; and the attack had far more potential than our harmless prank, as users on Reddit.Com noticed that the exploit <a href="http://www.reddit.com/r/programming/comments/a0n3q/apple_xss_exploit/" target="_blank">did allow malicious scripting  including JavaScript injection and IFrame injection</a> (thanks to <a href="http://twitter.com/shocm">@shocm</a> for bringing the Reddit thread to my attention).</p>
<p>It looks as though Apple&#8217;s server sanitized the &lt;script&gt;&lt;/script&gt; tag, but there are at least a half-dozen ways to inject javascript without using a &lt;script&gt; tag, many of which are outlined on the <a href="http://ha.ckers.org/xss.html" target="_blank">XSS Cheat Sheet</a>.</p>
<p>This type of exploit is a <a href="http://en.wikipedia.org/wiki/Cross-site_scripting#Traditional_versus_DOM-based_vulnerabilities" target="_blank">DOM-based exploit</a>. Wikipedia does a good job of summing it up:</p>
<blockquote><p>Traditionally, cross-site scripting vulnerabilities would occur in server-side code responsible for preparing the HTML response to be served to the user. With the advent of web 2.0 applications, a new class of XSS flaws emerged, however: DOM-based vulnerabilities come to be during the content processing stages delegated to the client, typically in client-side JavaScript. The name refers to the standard model for representing HTML or XML contents, called the Document Object Model or DOM for short. The model is the primary way for JavaScript programs to manipulate the state of a web page, and populate it with dynamically computed data.</p>
<p>A typical example is a piece of JavaScript accessing and extracting data from the URL via the location.* DOM, or receiving raw non-HTML data from the server via XMLHttpRequest, and then using this information to write dynamic HTML without proper escaping, entirely on client side.</p></blockquote>
<p>Netcraft featured an <strong><a href="http://news.netcraft.com/archives/2008/05/16/paypal_xss_vulnerability_undermines_ev_ssl_security.html" target="_blank">XSS vulnerability on PayPal&#8217;s website</a> </strong>discoverd by a Finnish security researcher in May 2008:</p>
<p><a href="http://www.snipe.net/wp-content/uploads/2009/11/paypal-xss-ev-ssl-certificate-resized.png"><img class="aligncenter size-full wp-image-2511" title="paypal-xss-ev-ssl-certificate-resized" src="http://www.snipe.net/wp-content/uploads/2009/11/paypal-xss-ev-ssl-certificate-resized.png" alt="paypal-xss-ev-ssl-certificate-resized" width="500" height="318" /></a></p>
<p>An exploit was reported in March 2007 on YouTube&#8217;s website, allowing a similar type of JavaScript attack:</p>
<p><a href="http://www.snipe.net/wp-content/uploads/2009/11/youtube-xss-cordobo.png"><img class="aligncenter size-full wp-image-2512" title="youtube-xss-cordobo" src="http://www.snipe.net/wp-content/uploads/2009/11/youtube-xss-cordobo.png" alt="youtube-xss-cordobo" width="367" height="247" /></a></p>
<p>And an <strong><a href="http://www.youtube.com/watch?v=Ui0MOD9dYok" target="_blank">XSS exploit of eBay was documented in this YouTube video</a></strong>, also in 2007, and Twitter has suffered several XSS exploit attacks as recently as this year. But those are just a small handful of examples from a really long list.</p>
<p>In fact, <strong>just today, an article came out in The Register, detailing an <a href="http://www.theregister.co.uk/2009/11/04/website_cookie_stealing/" target="_blank">XSS cookie hijacking attack</a> that affects many large websites, including Google and Facebook. </strong>From the article:</p>
<blockquote><p>A security researcher has discovered a weakness in a core browser protocol that compromises the security of Google, Facebook, and other websites by allowing an attacker to tamper with the cookies they set.</p>
<p>The weakness stems from RFC 2965, which dictates that browsers must allow subdomains (think www.google.com) to set and read cookies for their parent (google.com). The specification also states that if a cookie for a subdomain doesn&#8217;t already exist, the browser should use the cookie belonging to the parent instead.</p>
<p>The arrangement makes it possible for attackers to steal or even alter the cookies that websites use to authenticate their users. Attackers would first have to identify an XSS, or cross-site scripting, bug in some part of the site they are targeting. But because virtually any subdomain will suffice, the scenario isn&#8217;t unrealistic, two web security experts said.</p></blockquote>
<p>Apple&#8217;s development team responded quickly to the exploit on their site &#8211; a little too quickly in my opinion, since I was preparing to have a little more fun with it, but they had patched it by the time I got home. It should still serve as a reminder to developers of just how important data scrubbing and validation is, no matter whether your site is big or small, with 2 hits a day or 2 million.</p>
<h2>XSS Vulnerabilities Compromise User Data &#8211; And Your Reputation</h2>
<p><strong>As the eBay exploit video shows (and as anyone on Twitter saw this year), XSS attacks are not just embarrassing &#8211; they can be used for phishing scams, tricking users to login to a fake site, exposing their login credentials or worse. </strong>PayPal and bank phishing schemes often prompt the user to &#8220;confirm&#8221; their bank account information or credit card information &#8220;for security purposes&#8221;.</p>
<p>Other XSS exploits may trick users into thinking their computer has been infected by a virus, prompting them to download &#8220;free software&#8221; to clean their system &#8211; meanwhile the software the panicking user is downloading actually is the virus. And even though you might never fall for something so blatantly obviously, lots and lots of people do, every day.</p>
<p>Often attackers will inject JavaScript, VBScript, ActiveX, HTML, or Flash into a vulnerable application to fool a user in order to gather data from them. Everything from <strong>account hijacking</strong>, <strong>changing user settings</strong>, <strong>cookie theft/poisoning</strong>, or false advertising is possible. <strong>New malicious uses are being found every day for XSS attacks. </strong>XSS exploits can even be used to facilitate &#8220;Denial Of Service&#8221; attacks (or DoS attacks), and potential &#8220;auto-attacking&#8221; of hosts if a user simply reads a post on an infected message board.</p>
<p>While XSS attacks themselves cannot compromise files on your server, XSS holes can allow Javascript insertion, which may allow for limited execution. If an attacker were to exploit a browser flaw (browser hole) it could then be possible to execute commands on the client&#8217;s side. If command execution were possible it would only be possible on the client side. In simple terms <strong>XSS holes can be used to help exploit other holes that may exist in your browser or server</strong>.</p>
<h2>User-Submitted Data and Your Database</h2>
<p>Trusting user variables without cleaning or validating them opens you up to a whole host of problems if your application is powered by a database.</p>
<p>For example, the following SQL command is used to validate user login requests:</p>
<p>[sourcecode language="sql"]$sql_query = &#8220;select * from users where user=&#8217;$user&#8217; and password=&#8217;$pass&#8217;&#8221;[/sourcecode]</p>
<p>If the user-submitted data is not properly validated, an attacker can exploit this query and pass the login screen by simply submitting specially crafted variables.</p>
<p>For example, attacker can submit the following data as a $user variable: admin&#8217; or &#8217;1&#8242;=&#8217;1 . When this $user variable is glued together with the query, it will look as followed:</p>
<p>[sourcecode language="sql"]$sql_query = &#8220;select * from users where user=&#8217;admin&#8217; or &#8217;1&#8242;=&#8217;1&#8242; and password=&#8217;$pass&#8217;&#8221;[/sourcecode]</p>
<p>Now, the attacker can safely pass the login screen because or &#8217;1&#8242;=&#8217;1&#8242; causes the query to always return a &#8220;true&#8221; value while ignoring the password value.</p>
<p>Using similar techniques, an attacker can <strong>retrieve database records</strong>, <strong>pass login screens</strong>, and <strong>change database contents</strong>, for example by <strong>creating new administrative users</strong>. Using similar techniques, a malicious attack will be able to execute arbitrary shell commands, read or write arbitrary commands, and more.</p>
<p><strong>It is our responsibility to protect our users (and the trust they put in us, deserved or not)</strong>, and XSS vulnerabilities open the doors to all manner of mischief. At their most benign, they can result in a site defacement. At their worst, they compromise the very safety and livelihood of the people that fall for them &#8211; not to mention the impact on your company&#8217;s reputation.</p>
<p><strong>If you think your site is too small for hackers to bother with, think again.</strong> There are plenty of script kiddies out there that will happily run their exploit toolkit scripts and crawl page after page, testing for exploits. They are able to find common exploits in sites they have never physically even visited through this method.  And once they find a vulnerability, word spreads fast.</p>
<p><strong>It should also serve as a reminder to us as a internet users to be a little less trusting.</strong> It seems obvious, but we are so trained to respond to visual cues and prompts for activities we do every day &#8211; logging into a website, checking out with PayPal, etc &#8211; that we can sometimes become careless. We sometimes trust the big guys a little too much, assuming that because they&#8217;re that big, they&#8217;ve got to have their shit together. Even when we know better, our interactions online have become somewhat mechanical.</p>
<p>While browsers are getting better at helping us realize if we&#8217;re entering data into a site that is suspect, ultimately the responsibility falls back upon us to pay attention to what we&#8217;re doing and to whom we give our valuable information.</p>
<h2>So as a developer, what can you do to protect your software and sites from XSS attacks?</h2>
<p>Here are a few good places to start.</p>
<h3>Stuff to Read:</h3>
<ul>
<li><strong>Learn more about XSS and how it works</strong> on the <a href="http://www.cgisecurity.com/xss-faq.html" target="_blank">Cross-Site Scripting FAQ</a> on cgisecurity.com.</li>
<li><strong>Learn more about <a href="http://www.greensql.net/publications/backdoor-webserver-using-mysql-sql-injection" target="_blank">Backdooring a Webserver using MySQL</a></strong>, which details how a user could read/write files to your server and execute commands using mySQL.</li>
<li><strong>Check out the <a href="http://www.owasp.org/index.php/Main_Page" target="_blank">OWASP (Open Web Application Security) website</a></strong> and stay up to date</li>
</ul>
<h3>Stuff to Do: <strong></strong></h3>
<p><strong>Always clean and validate ANY data you receive from the user</strong></p>
<p>Use the <strong>appropriate escaping for the programming languages and databases you use</strong></p>
<p><strong>Educate yourself on as many examples of XSS (both theoretical and in-the-wild) as you can</strong>, so you know what to look for. Wikipedia details a few common methods worth checking out on their <a href="http://en.wikipedia.org/wiki/Cross-site_scripting">Cross-Site Scripting page</a>. The only real defense you have against attacks is to keep yourself informed and current on what the bad guys are up to. This isn&#8217;t one of those things that you can read about once and rest on your laurels. You must be vigilant and aggressive about staying on top of what&#8217;s going on. It&#8217;s your job.</p>
<p><strong>Bookmark and test your scripts against the <a href="http://ha.ckers.org/xss.html" target="_blank">code samples on the XSS Cheatsheet</a></strong> on ha.ckers.org. This cheatsheet is specifically geared towards exploits that can potentially get past standard filtering that developers might do on their data, such as strip_tags. Also check out the <a href="http://www.justinshattuck.com/2007/01/18/mysql-injection-cheat-sheet/">MySQL Injection Cheat Sheet </a>and the <a href="http://ferruh.mavituna.com/sql-injection-cheatsheet-oku/" target="_blank">SQL Injection Cheat Sheet</a>.</p>
<p><strong>P</strong><strong>eriodically check your webserver access logs and error logs</strong> and look for anything that looks like someone might be trying to find a backdoor. Look for people trying to pass data that doesn&#8217;t belong, sending variables that are common configuration file names, and so on.</p>
<p><strong>T</strong><strong>urn OFF error reporting displayed to the browser on production environments</strong>, and instead log errors to a file. Error messages can expose information about your file structure and your database structure.</p>
<p><strong>Pay attention!</strong> Keep your ear to the ground on sites like <a href="http://ha.ckers.org/" target="_blank">ha.ckers.org</a> and other (mostly) whitehat exploit blogs and communities. This is your livelihood. Do your job.</p>
<p><strong>If you&#8217;re using open source software, make sure you keep up to date with new releases. </strong>Many popular open source projects (such as WordPress, phpNuke, phpBB, etc) are frequent targets for malicious scripting. Be sure to hide references to your software version numbers from the public, since certain versions may have exploits that are well known, and attackers will know exactly how to target your site if they know what version you&#8217;re running.</p>
<p><strong>Shell out the $39 for the 300 page e-Book <em><a href="http://www.detectmalice.com/" target="_blank">Detecting Malice</a></em>, written by Robert Hansen</strong> (aka RSnake, on Twitter at <a href="http://twitter.com/RSnake">@RSnake</a>) <strong>and actually read it</strong>. I can&#8217;t believe I&#8217;m actually endorsing a freaking e-Book, but its really that good. I don&#8217;t know Robert personally, I&#8217;m not endorsing it as a favor or because I like him as a person. For all I know he eats puppies for breakfast. But his book is fantastic.</p>
<p>And finally, Test test test test test!</p>
<p>There&#8217;s even an <a href="http://twitter.com/xssexploits" target="_blank">interesting Twitter account that highlights high-profile XSS exploits</a> &#8211; it&#8217;s low-volume, but it&#8217;s surprising how many turn up that never make the news.</p>
<p>Incidentally, something I discovered while having a little fun on Apple.Com&#8217;s site &#8211; <strong>if you do a <a href="http://images.google.com/images?hl=en&amp;safe=off&amp;q=%22hot%20tar%20enema%22&amp;um=1&amp;ie=UTF-8&amp;sa=N&amp;tab=wi" target="_blank">Google Images search for &#8216;hot tar enema&#8221;</a>, only four images come up, and one of them is a photo of Rush Limbaugh</strong>. I&#8217;m not even making that up. Also funny, since I tweeted about that this afternoon, <a href="http://www.google.com/search?hl=en&amp;safe=off&amp;q=%22hot+tar+enema%22&amp;aq=f&amp;oq=&amp;aqi=" target="_blank">my tweet is now the number one Google search result for &#8220;hot tar enema&#8221;</a>. Aren&#8217;t you jealous?</p>

 <script type="text/javascript">
	<!--
		function onover(what){
	document.getElementById('blurbtext').innerHTML=''+what+'';
	}
	function onout(){
	document.getElementById('blurbtext').innerHTML='&nbsp;';
	}
	-->
	</script>



<h3 style="padding-bottom: 0px; margin-bottom: 0px;">Also check out: <br /><span id="blurbtext"><br /></span></h3>

<div id="relatedposts">




		
               

        
        
        
		<div class="yarppimg"><a href="http://www.snipe.net/2008/07/what-exactly-is-the-point-of-twitter/" rel="bookmark">
		<img src="http://www.snipe.net/wp-content/themes/snipe/thumb.php?src=http://www.snipe.net/wp-content/uploads/2008/06/twitter21.png&amp;h=90&amp;w=90&amp;zc=1&amp;q=95" alt="What Exactly is the Point of Twitter?" height="90" width="90" onmouseover="onover('What Exactly is the Point of Twitter?')" onmouseout="onout()" /></a></div>

			
               

        
        
        
		<div class="yarppimg"><a href="http://www.snipe.net/2010/10/firefox-addons-xss-testing/" rel="bookmark">
		<img src="http://www.snipe.net/wp-content/themes/snipe/thumb.php?src=http://www.snipe.net/wp-content/uploads/2010/10/beach-xss.jpg&amp;h=90&amp;w=90&amp;zc=1&amp;q=95" alt="Firefox Addons for Penetration/XSS Testing" height="90" width="90" onmouseover="onover('Firefox Addons for Penetration/XSS Testing')" onmouseout="onout()" /></a></div>

			
               

        
        
        
		<div class="yarppimg"><a href="http://www.snipe.net/2006/06/checkboxesmultiple-select-boxes-in-php/" rel="bookmark">
		<img src="http://www.snipe.net/wp-content/themes/snipe/thumb.php?src=http://www.snipe.net/wp-content/uploads/2008/06/drupal-taxonomy-as-checkboxes.png&amp;h=90&amp;w=90&amp;zc=1&amp;q=95" alt="Checkboxes/Multiple Select Boxes in PHP" height="90" width="90" onmouseover="onover('Checkboxes/Multiple Select Boxes in PHP')" onmouseout="onout()" /></a></div>

	</div>

]]></content:encoded>
			<wfw:commentRss>http://www.snipe.net/2009/11/apple-coms-xss-exploit/feed/</wfw:commentRss>
		<slash:comments>4</slash:comments>
		</item>
		<item>
		<title>Funky characters in HTML mail using PHPMailer</title>
		<link>http://www.snipe.net/2009/10/funky-characters-in-html-mail-using-phpmailer/</link>
		<comments>http://www.snipe.net/2009/10/funky-characters-in-html-mail-using-phpmailer/#comments</comments>
		<pubDate>Sat, 10 Oct 2009 17:44:51 +0000</pubDate>
		<dc:creator>snipe</dc:creator>
				<category><![CDATA[Featured]]></category>
		<category><![CDATA[PHP/mySQL]]></category>
		<category><![CDATA[Web Development]]></category>
		<category><![CDATA[bom]]></category>
		<category><![CDATA[byte order mark]]></category>
		<category><![CDATA[email]]></category>
		<category><![CDATA[html email]]></category>
		<category><![CDATA[php]]></category>
		<category><![CDATA[phpmailer]]></category>

		<guid isPermaLink="false">http://www.snipe.net/?p=2223</guid>
		<description><![CDATA[While working on a client project, I ended up having to send HTML email notifications to users. During testing, I discovered some stray characters at the beginning of the email. If you have to send HTML email, there are certainly lots of good libraries available for download to make your life easier. I opted to [...]]]></description>
			<content:encoded><![CDATA[<p>While working on a client project, I ended up having to send HTML email notifications to users. During testing, I discovered some stray characters at the beginning of the email.</p>
<p><span id="more-2223"></span>If you have to send HTML email, there are certainly lots of good libraries available for download to make your life easier. I opted to use <strong><a href="http://phpmailer.worxware.com/" target="_blank">PHPMailer by Worx International</a></strong>, since it&#8217;s one I have used in the past, and getting up and running with it takes about 3 minutes, tops.</p>
<p>What makes it particularly nice is that you don&#8217;t have to do anything special to format your HTML to be ready for mailing. If your workflow is anything like mine, you design an HTML email and code it into HTML, and then post it somewhere for the client to review. Since this HTML file already exists on your server, using PHPMailer is a breeze, since all you have to do to start sending HTML email is point the program to the HTML file you already created.</p>
<p>After you upload the PHPMailer library, all it takes is a few lines of code, and you&#8217;re done:</p>
<p>[sourcecode lang=php]require_once $_SERVER['DOCUMENT_ROOT'].&#8217;/phpMailer/class.phpmailer.php&#8217;;</p>
<p>$mail             = new PHPMailer(); // defaults to using php &#8220;mail()&#8221;<br />
$body             = $mail->getFile(&#8216;../invites/email.html&#8217;);<br />
$mail->From       = $from_email;<br />
$mail->FromName   = $from_name;</p>
<p>$mail->Subject    = &#8220;Test email subject&#8221;;<br />
$mail->AltBody    = &#8220;To view the message, please use an HTML compatible email viewer!&#8221;;<br />
$mail->MsgHTML($body);</p>
<p>$mail->AddAddress($to_email, $to_name);		</p>
<p>if(!$mail->Send()) {<br />
	echo &#8220;
<li>Mailer Error: &#8221; . $mail->ErrorInfo;<br />
} else {<br />
	echo &#8220;</li>
<li>Message sent!&#8221;;<br />
}[/sourcecode]</p>
<p>One thing I noticed while sending out the test emails is that there were weird characters, specifically <strong><em>ï»¿</em></strong>)  showing up at the very beginning of the HTML email, despite there not being any stray characters or empty spaces at the top of the HTML email source file.</p>
<p><img class="aligncenter size-full wp-image-2225" title="email" src="http://www.snipe.net/wp-content/uploads/2009/10/email.gif" alt="email" width="540" height="595" /></p>
<p>I  verified that the HTML email file was in UTF-8 with Unix line endings &#8211; still those funky characters remained. They were appearing in the emails regardless of email client &#8211; Entourage, Thunderbird, Postbox, everything.</p>
<p>I removed the encoding and doctype declarations from the HTML email file. No joy. Googling led me to lots if interesting articles on encoding and character sets for PHPMailer, but nothing particularly useful.</p>
<p>Finally I happened upon an FAQ article on the W3C website related to &#8220;<a href="http://www.w3.org/International/questions/qa-utf8-bom" target="_blank">Display problems caused by the UTF-8 BOM</a>&#8220;. Of course! The byte order mark. I haven&#8217;t had to send out HTML emails in a long time and had just switched from using Coda to BBedit for code editing, and completely forgot about that.</p>
<p>Some applications insert a particular combination of bytes at the beginning of a file to indicate that the text contained in the file is Unicode. This combination of bytes is known as a signature or Byte Order Mark (BOM). Some applications &#8211; such as a text editor or a browser &#8211; will display the BOM as an extra line in the file, others will display unexpected characters, such as ï»¿.</p>
<p>The BOM is always at the beginning of the file, and so you would normally expect to see the display issues at the top of a page. However, you may also find blank lines appearing within the page if you include text from a separate file that begins with a UTF-8 signature.</p>
<p>After further investigation in BBedit, I realized that BBedit offers an encoding type of &#8220;Unicode (UTF-8, no BOM)&#8221;, I switched to this encoding for the HTML source email file, re-saved, sent another test, and all was right with the world.</p>
<p><img src="http://www.snipe.net/wp-content/uploads/2009/10/editor-560x392.png" alt="editor" title="editor" width="560" height="392" class="aligncenter size-large wp-image-2227" /></p>
<p>(Pardon all the blurring &#8211; this project was for a high-profile Facebook application, and I am paranoid about exposing database or file structures to the outside world.)</p>
<h3>Some additional notes from W3C</h3>
<p>If you have an editor which shows the characters that make up the UTF-8 signature you may be able to delete them by hand. <strong>Chances are, however, that the BOM is there in the first place because you didn&#8217;t see it.</strong></p>
<p><strong>Check whether your editor allows you to specify whether a UTF-8 signature is added or kept during a save. </strong>Such an editor provides a way of removing the signature by simply reading the file in then saving it out again. For example, if Dreamweaver detects a BOM the Save As dialogue box will have a check mark alongside the text &#8220;Include Unicode Signature (BOM)&#8221;. Just uncheck the box and save.</p>
<p>You will find that some text editors such as Windows Notepad will automatically add a UTF-8 signature to any file you save as UTF-8.</p>
<p><strong>A UTF-8 signature at the beginning of a CSS file can sometimes cause the initial rules in the file to fail on certain user agents.</strong></p>
<p>In some browsers, the presence of a UTF-8 signature will cause the browser to interpret the text as UTF-8 regardless of any character encoding declarations to the contrary.</p>
<p>So there you have it. Not exactly rocket surgery, but it was frustrating for the short time I was trying to troubleshoot, so I&#8217;m putting it into the internet ether to hopefully save someone else a few minutes.</p>
<h3>Related Links</h3>
<ul>
<li><a href=http://www.w3.org/International/questions/qa-utf8-bom">W3C UTF-8 Byte Order Mark FAQ</a>
	</li>
<li><a href="http://www.unicode.org/unicode/faq/utf_bom.html">Unicode.Org UTF-8 Byte Order Mark FAQ</a>
</li>
</ul>
</li>

 <script type="text/javascript">
	<!--
		function onover(what){
	document.getElementById('blurbtext').innerHTML=''+what+'';
	}
	function onout(){
	document.getElementById('blurbtext').innerHTML='&nbsp;';
	}
	-->
	</script>



<h3 style="padding-bottom: 0px; margin-bottom: 0px;">Also check out: <br /><span id="blurbtext"><br /></span></h3>

<div id="relatedposts">




		
               

        
        
        
		<div class="yarppimg"><a href="http://www.snipe.net/2002/06/sending-htmlplain-text-mail-simultaneously-using-php/" rel="bookmark">
		<img src="http://www.snipe.net/wp-content/themes/snipe/thumb.php?src=http://www.snipe.net/wp-content/uploads/2008/06/htmlmail.jpg&amp;h=90&amp;w=90&amp;zc=1&amp;q=95" alt="Sending HTML/Plain Text Mail Simultaneously using PHP" height="90" width="90" onmouseover="onover('Sending HTML/Plain Text Mail Simultaneously using PHP')" onmouseout="onout()" /></a></div>

			
               

        
        
        
		<div class="yarppimg"><a href="http://www.snipe.net/2008/10/is-imappop3-gmail-or-gtalk-periodically-rejecting-your-password/" rel="bookmark">
		<img src="http://www.snipe.net/wp-content/themes/snipe/thumb.php?src=http://www.snipe.net/wp-content/uploads/2008/10/gmail-soap.jpg&amp;h=90&amp;w=90&amp;zc=1&amp;q=95" alt="Is IMAP/POP3 Gmail or Gtalk periodically rejecting your password?" height="90" width="90" onmouseover="onover('Is IMAP/POP3 Gmail or Gtalk periodically rejecting your password?')" onmouseout="onout()" /></a></div>

			
               

        
        
        
		<div class="yarppimg"><a href="http://www.snipe.net/2004/06/dynamic-watermarkstext-overlay-on-images-in-php/" rel="bookmark">
		<img src="http://www.snipe.net/wp-content/themes/snipe/thumb.php?src=http://www.snipe.net/wp-content/uploads/2008/06/picture-31.png&amp;h=90&amp;w=90&amp;zc=1&amp;q=95" alt="Dynamic Watermarks/Text Overlay on Images in PHP" height="90" width="90" onmouseover="onover('Dynamic Watermarks/Text Overlay on Images in PHP')" onmouseout="onout()" /></a></div>

	</div>

]]></content:encoded>
			<wfw:commentRss>http://www.snipe.net/2009/10/funky-characters-in-html-mail-using-phpmailer/feed/</wfw:commentRss>
		<slash:comments>3</slash:comments>
		</item>
		<item>
		<title>PHP Regex to Make Twitter Links Clickable</title>
		<link>http://www.snipe.net/2009/09/php-twitter-clickable-links/</link>
		<comments>http://www.snipe.net/2009/09/php-twitter-clickable-links/#comments</comments>
		<pubDate>Thu, 10 Sep 2009 09:44:42 +0000</pubDate>
		<dc:creator>snipe</dc:creator>
				<category><![CDATA[PHP/mySQL]]></category>
		<category><![CDATA[Web Development]]></category>
		<category><![CDATA[php]]></category>
		<category><![CDATA[regex]]></category>
		<category><![CDATA[snippets]]></category>
		<category><![CDATA[twitter]]></category>

		<guid isPermaLink="false">http://www.snipe.net/?p=2169</guid>
		<description><![CDATA[This is just a quicky post, not one of my usual long, rambling diatribes. This week is madness, even by my own absurd standards, but I didn&#8217;t want to miss jotting this down in case it might be helpful to others. I&#8217;ve had varying degrees of success trying to find a series of preg_replace statements [...]]]></description>
			<content:encoded><![CDATA[<p>This is just a quicky post, not one of my usual long, rambling diatribes. This week is madness, even by my own absurd standards, but I didn&#8217;t want to miss jotting this down in case it might be helpful to others.<br />
<span id="more-2169"></span><br />
I&#8217;ve had varying degrees of success trying to find a series of preg_replace statements that would correctly replace output generated by Twitter&#8217;s RSS feeds (which do not contain any linking HTML) to autolink hyperlinks, @replies and hashtags, so I finally sat down and sorted it out myself. </p>
<p>The code below should correctly autolink all of the autolinkables in your PHP script:</p>
<ul>
<li>links @username to the user&#8217;s Twitter profile page</li>
<li>links regular links to wherever they should link to</li>
<li>links hashtags to a Twitter search on that hashtag</li>
</ul>
<p>[sourcecode language='php']function twitterify($ret) {<br />
  $ret = preg_replace(&#8220;#(^|[\n ])([\w]+?://[\w]+[^ \"\n\r\t< ]*)#&#8221;, &#8220;\\1<a href=\"\\2\" target=\"_blank\">\\2</a>&#8220;, $ret);<br />
  $ret = preg_replace(&#8220;#(^|[\n ])((www|ftp)\.[^ \"\t\n\r< ]*)#&#8221;, &#8220;\\1<a href=\"http://\\2\" target=\"_blank\">\\2</a>&#8220;, $ret);<br />
  $ret = preg_replace(&#8220;/@(\w+)/&#8221;, &#8220;<a href=\"http://www.twitter.com/\\1\" target=\"_blank\">@\\1</a>&#8220;, $ret);<br />
  $ret = preg_replace(&#8220;/#(\w+)/&#8221;, &#8220;<a href=\"http://search.twitter.com/search?q=\\1\" target=\"_blank\">#\\1</a>&#8220;, $ret);<br />
return $ret;<br />
}[/sourcecode]</p>
<p>Someday I&#8217;ll try to find the time to write a regex primer/tutorial. Regex is another one of the things, <a href="http://www.snipe.net/series/subversion-primer/">like SVN</a>, that seems scary and incomprehensible to many people, but eventually it clicks and makes sense. In the meantime, if you&#8217;re interested in learning more about using Regex in PHP, check out the following resources:</p>
<h3>More Regexy Goodness:</h3>
<ul>
<li><a href="http://www.regular-expressions.info/php.html">Using Regular Expressions in PHP</a> via regular-expressions.info</li>
<li><a href="http://www.phpro.org/tutorials/Introduction-to-PHP-Regex.html">Introduction to PHP Regex</a> via phpro.org</li>
<li><a href="http://www.webcheatsheet.com/php/regular_expressions.php">Using Regular Expressions in PHP</a> via webcheatsheets.com</li>
<li><a href="http://www.catswhocode.com/blog/15-php-regular-expressions-for-web-developers">15 PHP Regular Expressions for Web Developers</a> via catswhocode.com</li>
</ul>
<p>Make sure you leave yourself some time to actually try out some examples, and dissect the examples they give so that you really grok what&#8217;s happening. Once it clicks, it seems so simple, you won&#8217;t believe you ever let it beat you up and take your lunch money.</p>
<p>Image by <a href="http://www.xkcd.com/">xkcd</a>, via <a href="http://store.xkcd.com/xkcd/#RegularExpressionsShirt">their awesome web store</a>. The comic rocks my geeky face off. I buy my clothes there. So should you. </p>
<p>PS &#8211; still really, really hate posting code in WordPress. Even in HTML mode, it keeps converting my fscking special characters, which then get double/triple/etc converted.  </p>

 <script type="text/javascript">
	<!--
		function onover(what){
	document.getElementById('blurbtext').innerHTML=''+what+'';
	}
	function onout(){
	document.getElementById('blurbtext').innerHTML='&nbsp;';
	}
	-->
	</script>



<h3 style="padding-bottom: 0px; margin-bottom: 0px;">Also check out: <br /><span id="blurbtext"><br /></span></h3>

<div id="relatedposts">




		
               

        
        
        
		<div class="yarppimg"><a href="http://www.snipe.net/2007/11/stupid-monsters-someone-was-paid-to-make/" rel="bookmark">
		<img src="http://www.snipe.net/wp-content/themes/snipe/thumb.php?src=http://www.snipe.net/wp-content/uploads/2008/06/dd-beasts-senmurv-gay-pride.jpg&amp;h=90&amp;w=90&amp;zc=1&amp;q=95" alt="Stupid Monsters Someone Was Paid to Make" height="90" width="90" onmouseover="onover('Stupid Monsters Someone Was Paid to Make')" onmouseout="onout()" /></a></div>

			
               

        
        
        
		<div class="yarppimg"><a href="http://www.snipe.net/2009/07/writing-your-first-twitter-application-with-oauth/" rel="bookmark">
		<img src="http://www.snipe.net/wp-content/themes/snipe/thumb.php?src=http://www.snipe.net/wp-content/uploads/2009/07/Imonmonies128410148226846250.jpg&amp;h=90&amp;w=90&amp;zc=1&amp;q=95" alt="Writing Your First Twitter Application with OAuth" height="90" width="90" onmouseover="onover('Writing Your First Twitter Application with OAuth')" onmouseout="onout()" /></a></div>

			
               

        
        
        
		<div class="yarppimg"><a href="http://www.snipe.net/2009/06/no-follow-back-girl/" rel="bookmark">
		<img src="http://www.snipe.net/wp-content/themes/snipe/thumb.php?src=http://www.snipe.net/wp-content/uploads/2009/06/fail-lol.jpg&amp;h=90&amp;w=90&amp;zc=1&amp;q=95" alt="Why I Won&#8217;t Follow You Back on Twitter" height="90" width="90" onmouseover="onover('Why I Won&#8217;t Follow You Back on Twitter')" onmouseout="onout()" /></a></div>

	</div>

]]></content:encoded>
			<wfw:commentRss>http://www.snipe.net/2009/09/php-twitter-clickable-links/feed/</wfw:commentRss>
		<slash:comments>62</slash:comments>
		</item>
		<item>
		<title>Writing Your First Twitter Application with OAuth</title>
		<link>http://www.snipe.net/2009/07/writing-your-first-twitter-application-with-oauth/</link>
		<comments>http://www.snipe.net/2009/07/writing-your-first-twitter-application-with-oauth/#comments</comments>
		<pubDate>Thu, 23 Jul 2009 23:26:12 +0000</pubDate>
		<dc:creator>snipe</dc:creator>
				<category><![CDATA[Featured]]></category>
		<category><![CDATA[PHP/mySQL]]></category>
		<category><![CDATA[Web Development]]></category>
		<category><![CDATA[api]]></category>
		<category><![CDATA[application development]]></category>
		<category><![CDATA[oauth]]></category>
		<category><![CDATA[php]]></category>
		<category><![CDATA[twitter]]></category>

		<guid isPermaLink="false">http://www.snipe.net/?p=2070</guid>
		<description><![CDATA[If you&#8217;re interested in writing a web-based Twitter application but aren&#8217;t sure where to start, the Twitter OAuth library from Abraham Wiliams makes authenticating with OAuth and Twitter a breeze. Please note: Use of the information in this article is conditional on the fact that you swear NOT to to make any of those goddamned [...]]]></description>
			<content:encoded><![CDATA[<p>If you&#8217;re interested in writing a web-based Twitter application but aren&#8217;t sure where to start, the <a href="http://twitter.abrah.am/" target="_blank">Twitter OAuth library from Abraham Wiliams</a> makes authenticating with OAuth and Twitter a breeze.<br />
<span id="more-2070"></span><br />
<strong>Please note: </strong>Use of the information in this article is conditional on the fact that you swear NOT to to make any of those goddamned Twitter games that spam Twitter timelines or send DMs like Spymaster or Quizzes. If you&#8217;re reading this to learn how to create one of those, please fuck right off. Do not pass go, do not collect $200. Those apps are the anal cancer of Twitter and the people who write them should be clubbed like baby seals.</p>
<p>Right then. Moving on.</p>
<p><a href="http://oauth.net/" target="_blank">OAuth</a> is an open protocol to allow secure API authorization  in a simple and standard method from desktop and web applications. In layman&#8217;s terms, it is a system by which you can allow a user to authenticate with an OAuth-enabled service without providing you with their credentials to that service.</p>
<p>In my Twitter anti-social media douchebag service, <a href="http://www.douchenuker.com" target="_blank">DoucheNuker.Com</a>, we use Twitter&#8217;s OAuth to validate the user and make Twitter API requests on their behalf, specifically sending a DM to the douchebag they are nuking, another DM to @spam to report them to Twitter as a spammer, and then a block request to block the spammer&#8217;s account from being able to follow them in the future.</p>
<h3>Why OAuth?</h3>
<p>Using OAuth allows you to write applications that access the Twitter API but do not require your users to give you their Twitter username and password. This is important for a variety of reasons:</p>
<ul>
<li>If the user changes their Twitter login, they do not have to update that information with you for your application to continue working for them</li>
<li>Using OAuth puts the user in control &#8211; if they ever wish to stop using your application, they can <a href="https://twitter.com/account/connections" target="_blank">disable it through Twitter</a> instead of trusting your application to stop using their login information. Once they disable it through Twitter, any requests by your application will require them to manually approve the connection again.</li>
<li>Increased sense of trust, since the user doesn&#8217;t have to worry about your application stealing their Twitter credentials and using it for nefarious purposes. I personally wouldn&#8217;t trust any web-based application that asks for my Twitter username and password, and given <a href="http://mashable.com/2009/07/15/twitter-security-meltdown/" target="_blank">Twitter&#8217;s recent history of bad press regarding their security</a>, more and more users are following that lead.</li>
</ul>
<h3>Definitions</h3>
<p style="text-align: left;">Before I show you how to use Abraham&#8217;s shmancy library to connect to Twitter&#8217;s OAuth, you should understand the basics of how OAuth works and what it&#8217;s doing. And before we get too caught up in <em>that</em>, it&#8217;s important that we establish some definitions that you&#8217;ll see if you do any additional research into OAuth:</p>
<p style="text-align: left;"><img class="aligncenter size-full wp-image-2084" title="chartkey-2" src="http://www.snipe.net/wp-content/uploads/2009/07/chartkey-2.png" alt="chartkey-2" width="464" height="110" /></p>
<p style="text-align: left;">
<p><strong>User:</strong> The users of your application.<br />
<strong>Consumer:</strong> Your application, which you have registered with Twitter<br />
<strong>Service Provider: </strong>The third-party service the <em>consumer</em> (your application) is authenticating against &#8211; in this case, Twitter.</p>
<p>These terms are used in much of the OAuth documentation, so they&#8217;re worth remembering.</p>
<p>So now that you know the lingo, how does OAuth actually work? For a detailed technical view of what gets passed back and forth, check out the <a href="http://oauth.googlecode.com/svn/spec/branches/1.0/drafts/4/spec.html" target="_blank">core spec documentation on OAuth</a>. Included in that documentation is the detailed chart below.</p>
<p><img class="aligncenter size-large wp-image-2088" title="diagram" src="http://www.snipe.net/wp-content/uploads/2009/07/diagram-560x411.png" alt="diagram" width="560" height="411" /></p>
<p>As you can see, the documentation frequently uses the terms defined above.</p>
<p>If that flow diagram seems a little overwhelming, don&#8217;t sweat it. I have a simplified version just for you (featuring a stoner Twitter user and a Twitter bird with a Thyroid problem), specifically with respect to the bits you need to know to set up your first Twitter application with OAuth. The other things OAuth does <em>are</em> important, but this is the stuff that directly impacts you, and that you need to grok to get started with your app.</p>
<p><img class="aligncenter size-full wp-image-2086" title="chart" src="http://www.snipe.net/wp-content/uploads/2009/07/chart.png" alt="chart" width="550" height="435" /></p>
<p><img class="alignleft size-full wp-image-2090" title="boba_fett" src="http://www.snipe.net/wp-content/uploads/2009/07/boba_fett.png" alt="boba_fett" width="128" height="128" />I was absurdly and inexplicably tempted to randomly throw a Boba Fett icon into that diagram, but was afraid it might confuse people. That said, I have poor impulse control, so here&#8217;s a random Boba Fett icon, so I can sleep tonight. As my friend <a href="http://twitter.com/jramboz" target="_blank">Jason Ramboz</a> says, &#8220;Step 4, Boba Fett freezes the key in carbonite for transport.&#8221;</p>
<p>Moving on.</p>
<p>Now that you&#8217;ve got a good idea of how the basics of OAuth work, you&#8217;re ready to get started with Abraham&#8217;s great Twitter OAuth library. He does provide an example script in the downloadable code, but it might be confusing for people just starting out.</p>
<h3>Getting Started &#8211; Registering Your Application with Twitter</h3>
<p>Before you even start mucking around in any code, you have to <strong><a href="https://twitter.com/oauth_clients/new" target="_blank">register your new application with Twitter</a></strong>. You&#8217;ll need a name and url for your application in order to register it, and you&#8217;ll need to define a callback url. The callback url is the full url of the page Twitter should send the user to after it&#8217;s done authenticating. This file can be named anything you want, but make sure the one you create on your server matches the one you register with Twitter. All of these details can be changed later if you change your mind or need to update something.</p>
<p>Once you&#8217;ve registered your application, Twitter will issue you a <strong>Consumer Key</strong> and a <strong>Consumer Secret</strong> for your new app. You&#8217;ll need these to get your sample code from the Twitter OAuth library working. As you can probably tell by the name, your Consumer Secret should remain private and you should never give it out to anyone. It&#8217;s used in your code so that Twitter can identify your application when you&#8217;re making API calls.</p>
<p>By forcing you to send your consumer key and secret with your API calls, Twitter is able to determine which application is sending the API calls, and can verify that the Twitter user you are attempting to send API requests on behalf of has actually authorized your application to access their account. If the user decides they no longer want to allow your application, they can edit their allowed application preferences and your application will no longer be able to make API calls on their behalf.</p>
<p>You can access a list of all of the applications you have registered with Twitter &#8211; and links to edit their details or view the consumer key and consumer secret &#8211; by going to <a href="https://twitter.com/oauth_clients/" target="_blank">your oauth clients page on Twitter</a>.</p>
<h4>The Twitter OAuth PHP Library Code</h4>
<p><strong>You&#8217;ve got your consumer keys from Twitter, so now you&#8217;re ready to download <a href="https://docs.google.com/View?docID=dcf2dzzs_2339fzbfsf4" target="_blank">Abraham&#8217;s Twitter OAuth library</a> code. </strong>You can pull the code from <a href="http://github.com/abraham/twitteroauth" target="_blank">http://github.com/abraham/twitteroauth</a>. As I mentioned, he does provide an example script, but there&#8217;s not a lot of explanation given to it, so some people might be a little confused by it if its their first foray into Twitter applications with OAuth. We&#8217;re going to whip up something a little more straightforward and simple, so you can easily modify it to suit your needs.</p>
<p>Unpack/unzip the archive you downloaded from github. You&#8217;ll see the two main files, OAuth.php and twitterOAuth.php are in the top level directory, and there is a directory called &#8216;example&#8217;, that has the included example script.</p>
<p><strong>For our example, we&#8217;re going to put the two OAuth files into a directory called &#8216;twitterOAuth&#8217;, which is a sub-directory of where the index.php and callback.php files live. </strong>As you may have guessed, the callback.php file is the one we&#8217;ve registered with Twitter as being our callback url. We&#8217;ll keep common configuration options such as the consumer key and consumer secret, and database credentials in a config.php file.</p>
<p>[source lang='php']/* config.php */</p>
<p>/* Consumer key from twitter */<br />
$consumer_key = &#8216;xxhjgxhjxhhjgxjhjxgjyx768678xx&#8217;; </p>
<p>/* Consumer Secret from twitter */<br />
$consumer_secret = &#8216;jhgjdfgfgjhj76jgjgjhxxxjhxxx&#8217;;<br />
[/source]</p>
<p>Now we create the index.php file, which will be used to generate the authentication link, inviting users to authorize and login using Twitter.</p>
<p>[source lang='php']/* index.php */</p>
<p>session_start();</p>
<p>/* Destroy the session if the user is logging out */<br />
if ((isset($_GET['logout'])) &#038;&#038; ($_GET['logout']==&#8217;true&#8217;)) {<br />
    session_destroy();<br />
    session_unset();<br />
}</p>
<p>/* Include the config file */<br />
require_once(&#8216;config.php&#8217;);</p>
<p>/* include the twitter OAuth library files */<br />
require_once(&#8216;twitterOAuth/twitterOAuth.php&#8217;);<br />
require_once(&#8216;twitterOAuth/OAuth.php&#8217;);</p>
<p>    /*<br />
    Create a new TwitterOAuth object, and then<br />
    get a request token. The request token will be used<br />
    to build the link the user will use to authorize the<br />
    application. </p>
<p>     You should probably use a try/catch here to handle errors gracefully<br />
    */<br />
    $to = new TwitterOAuth($consumer_key, $consumer_secret);<br />
    $tok = $to->getRequestToken();</p>
<p>    $request_link = $to->getAuthorizeURL($tok);</p>
<p>    /*<br />
    Save tokens for later  &#8211; we need these on the callback page to ask for the<br />
    access tokens<br />
    */<br />
    $_SESSION['oauth_request_token'] = $token = $tok['oauth_token'];<br />
    $_SESSION['oauth_request_token_secret'] = $tok['oauth_token_secret'];</p>
<p>echo &#8216;
<p><a href="'.$request_link.'">login using twitter</a> | &#8216;;<br />
echo &#8216;<a href="index.php?logout=true">Logout</a></p>
<p>&#8216;;<br />
[/source]</p>
<p>The callback.php file is the script that Twitter sends the user back to after authenticating. Here you&#8217;ll probably want to set some cookies, store some user data in the database, and start letting the user do whatever it is your application does.</p>
<p>[source lang='php']/* callback.php */</p>
<p>session_start();</p>
<p>/* Include the config file */<br />
require_once(&#8216;config.php&#8217;);</p>
<p>/* include the twitter OAuth library files */<br />
require_once(&#8216;twitterOAuth/twitterOAuth.php&#8217;);<br />
require_once(&#8216;twitterOAuth/OAuth.php&#8217;);</p>
<p>/* check for an auth access token. If there&#8217;s no auth token set, go ahead and fetch one from Twitter,<br />
* using the API call. */<br />
if ((!isset($_SESSION['oauth_access_token'])) || ($_SESSION['oauth_access_token'])==&#8221;) {</p>
<p>	$to = new TwitterOAuth($consumer_key, $consumer_secret, $_SESSION['oauth_request_token'], $_SESSION['oauth_request_token_secret']);<br />
	$tok = $to->getAccessToken();</p>
<p> 	/* Save tokens for later  &#8211; might be wise to<br />
        * store the oauth_token and secret in a database, and<br />
        * only store the oauth_token in a cookie or session for security purposes */<br />
	$_SESSION['oauth_access_token'] = $token = $tok['oauth_token'];<br />
	$_SESSION['oauth_access_token_secret'] = $tok['oauth_token_secret'];</p>
<p>} </p>
<p>/* Connect to the Twitter API */<br />
$to = new TwitterOAuth($consumer_key, $consumer_secret, $_SESSION['oauth_access_token'], $_SESSION['oauth_access_token_secret']);<br />
$content = $to->OAuthRequest(&#8216;https://twitter.com/account/verify_credentials.xml&#8217;, array(), &#8216;GET&#8217;);<br />
$user = simplexml_load_string($content);</p>
<p>if ($user->screen_name!=&#8221;) {<br />
	echo &#8216;<br />
<h2><img src="'.$user-/>profile_image_url.&#8217;&#8221; align=&#8221;left&#8221;>&#8217;;<br />
	echo &#8216;Hello, &#8216;.$user->screen_name.&#8217;</h2>
<p>&#8216;;<br />
	echo &#8216;
<p>You follow &#8216;.$user->friends_count.&#8217; people, &#8216;;<br />
	echo &#8216;you have &#8216;.$user->followers_count.&#8217; &#8216;;<br />
	echo &#8216;people following you, and you joined &#8216;;<br />
	echo &#8216;Twitter on &#8216;.$user->created_at.&#8217;. &#8216;;<br />
	echo &#8216;You have posted &#8216;.$user->statuses_count.&#8217; updates.</p>
<p>&#8216;;<br />
} else {<br />
	echo &#8216;Oops &#8211; an error has occurred.&#8217;;<br />
}</p>
<p>echo &#8216;
<pre>';
print_r($user);
echo '</pre>
<p>&#8216;;[/source]</p>
<p><strong>So we&#8217;ve connected to Twitter&#8217;s API to authenticate a session on behalf of the user, and then put the XML response of the user&#8217;s information into an array called $user, using <a href="http://us3.php.net/simplexml">SimpleXML</a>.</strong> Using SimpleXML, we can call up any node values within the XML using $user->field_name, as you can see above. </p>
<p>I&#8217;ve included a print_r($user) so that you can see the full details of the array being returned, but you&#8217;ll obviously want to comment that out in your live code.</p>
<p>The output array will contain the following fields:</p>
<p>[source lang='html']SimpleXMLElement Object<br />
(<br />
    [id] => 14246782<br />
    [name] => snipe<br />
    [screen_name] => snipeyhead<br />
    [location] => New York<br />
    [description] => Codemonkey, designer, author, speaker, blogger, swordfighter, Warcrafter, sarcasticgeek, scuba diver, blacksmith, crimefighter, Mentat, MBTI: ENTP, Totally NSFW<br />
    [profile_image_url] => http://s3.amazonaws.com/twitter_production/profile_images/303658881/Photo_4-rcrop2_normal.jpg<br />
    [url] => http://www.snipe.net<br />
    [protected] => false<br />
    [followers_count] => 4224<br />
    [profile_background_color] => 340100<br />
    [profile_text_color] => 3C3940<br />
    [profile_link_color] => 6C2125<br />
    [profile_sidebar_fill_color] => AEA797<br />
    [profile_sidebar_border_color] => 943A39<br />
    [friends_count] => 3756<br />
    [created_at] => Fri Mar 28 20:37:35 +0000 2008<br />
    [favourites_count] => 314<br />
    [utc_offset] => 12600<br />
    [time_zone] => Tehran<br />
    [profile_background_image_url] => http://s3.amazonaws.com/twitter_production/profile_background_images/22127710/twitterback2.jpg<br />
    [profile_background_tile] => false<br />
    [statuses_count] => 20570<br />
    [notifications] => false<br />
    [verified] => false<br />
    [following] => false<br />
    [status] => SimpleXMLElement Object<br />
        (<br />
            [created_at] => Mon Jul 27 01:50:36 +0000 2009<br />
            [id] => 2862508774<br />
            [text] => @elazar In case a name gets blocked/banned &#8211; when its reinstated (by someone claiming it, not spamming), it has a new ID#<br />
            [source] => Tweetie<br />
            [truncated] => false<br />
            [in_reply_to_status_id] => 2860170987<br />
            [in_reply_to_user_id] => 9105122<br />
            [favorited] => false<br />
            [in_reply_to_screen_name] => elazar<br />
        )</p>
<p>)[/source]</p>
<p>We&#8217;re not actually doing anything magical here yet, since that information is all available publicly via a user&#8217;s RSS feed, but the key line of code you want to look at in callback.php is this one:</p>
<p>[source lang='php']$content = $to->OAuthRequest(&#8216;https://twitter.com/account/verify_credentials.xml&#8217;, array(), &#8216;GET&#8217;);[/source]</p>
<p>The OAuthRequest function is what actually sends the requests to the API, so you&#8217;ll be using this a lot. In the example above, all we were doing was getting the access tokens, but you&#8217;ll use OAuthRequest for just about everything else, too. For example, to send a Direct Message in Twitter, you&#8217;d use:</p>
<p>[source lang='php']<br />
$params = array(&#8216;user&#8217; => &#8216;username&#8217;, &#8216;text&#8217; => &#8216;this is a test message&#8217;);<br />
$do_dm = simplexml_load_string($to->OAuthRequest(&#8216;http://twitter.com/direct_messages/new.xml&#8217;, $params, &#8216;POST&#8217;));[/source]</p>
<p>To block a user, you&#8217;d do:</p>
<p>[source lang='php']$doblock = simplexml_load_string($to->OAuthRequest(&#8216;http://twitter.com/blocks/create/username.xml&#8217;, array(), &#8216;POST&#8217;));[/source]</p>
<p>To send a status update:<br />
[source lang='php']$content = simplexml_load_string($to->OAuthRequest(&#8216;https://twitter.com/statuses/update.xml&#8217;, array(&#8216;status&#8217; => &#8216;Test OAuth update. #testoauth&#8217;), &#8216;POST&#8217;));[/source]</p>
<h3>Important! Storing user IDs</h3>
<p>Whenever you&#8217;re storing Twitter IDs in a database, be sure to store the Twitter ID number <em>in addition</em> to (or instead of) the Twitter username. While it may seem obvious to use a numeric value over a mixed alphanumeric, Twitter doesn&#8217;t expose user&#8217;s ID numbers without a little digging, so it might be easy to forget that they exist.</p>
<p>There are two main reasons why using the numeric ID is critical:</p>
<ul>
<li>Users can change their Twitter usernames. If they did this, your entire database could potentially be screwed up, since username key you&#8217;re looking for won&#8217;t match any longer.</li>
<li>If an account has been suspended due to spam or imposters, it can potentially be available for registration again after a grace period. If a spammer had a username before, and then a legitimate user reclaimed it, your records could potentially have old data from the previous user&#8217;s account. </li>
</ul>
<p>The second point above became crystal clear while working on DoucheNuker.Com. If a user account was suspended due to spamming, and then a legitimate user took it over, that new, legitimate user could potentially be considered a spammer in our database if we didn&#8217;t store (and query against) the ID number, too. When a username is reissued or reclaimed, it gets a new user ID number, so as long as you store and use the Twitter user&#8217;s ID number, your database can remain agnostic to name changes and reissues. </p>
<p>You&#8217;ll note in the <a href="http://apiwiki.twitter.com/Twitter-API-Documentation" target="_blank">Twitter REST API documentation</a> that almost all API requests allow the option of using the username or the user ID, and some actually require the user ID and cannot be used with just a username.</p>
<h3>Important! Error Messages and Throttling</h3>
<p><strong>You do not want to authenticate against Twitter every single time you load the page, but will instead want to store the request tokens in a database or session so that you don&#8217;t keep hammering Twitter&#8217;s API each time the page loads.</strong> </p>
<p>Remember that the although the <strong>Request Token</strong> you used to generate the authorization link will change often, a user&#8217;s <strong>Access Token </strong>and<strong> Access Secret Token</strong> do not, so you can safely store those in a database and use those instead of re-validating every time.</p>
<p><strong>As of right now, Twitter is throttling validation requests to 15 <em>per Twitter account</em> per hour.</strong> This was implemented to improve Twitter&#8217;s security and make it harder for bad guys to brute force their way into someone else&#8217;s Twitter account. There is discussion about rolling this change back, or only throttling to 15 <em>failed attempts</em> per hour, but as of this moment, if you attempt to authenticate more than 15 times in an hour, you&#8217;ll get a message that says &#8220;Too many requests in this time period. Try again later.&#8221; There is no way around this message for now, so plan your application accordingly. </p>
<p><strong>This limit is entirely separate from the <a href="http://apiwiki.twitter.com/Rate-limiting">Twitter Rate Limit</a> that throttles the number of times you can hit the API.</strong> <a href="http://twitter.com/help/request_whitelisting">Whitelisting your account and IP address with Twitter</a> will NOT circumvent this rate limit, so make sure you design your app in a smart way that will not attempt to authenticate more than absolutely necessary.</p>
<p>The default rate limit for calls to the REST API is 150 requests per hour. The REST API does account- and IP-based rate limiting. Authenticated API calls are charged to the authenticating user&#8217;s limit while unauthenticated API calls are deducted from the calling IP address&#8217; allotment. </p>
<p><strong>You&#8217;ll notice in all of API requests, we&#8217;re using SimpleXML to capture the value of the XML that&#8217;s returned. </strong>We need to do this in order to make sure we&#8217;re capturing any error messages that Twitter returns to us. Without error messages, when stuff doesn&#8217;t work as expected, we&#8217;re flying completely blind. Always make sure to plan your application in a way that handles errors intelligently. Let&#8217;s take a look at the API call to send a Direct Message again:</p>
<p>[source lang='php']$params = array(&#8216;user&#8217; => &#8216;username&#8217;, &#8216;text&#8217; => &#8216;this is a test message&#8217;);<br />
$do_dm = simplexml_load_string($to->OAuthRequest(&#8216;http://twitter.com/direct_messages/new.xml&#8217;, $params, &#8216;POST&#8217;));</p>
<p>/* Check for an error response from Twitter */<br />
if ($do_dm->error!=&#8221;) {<br />
	echo &#8216;<br />
<h2>ERROR: &#8216;.$do_dm->error.&#8217;</h2>
<p>&#8216;;<br />
}[/source]</p>
<p><strong>Now we&#8217;re capturing the error returned from Twitter, and can handle this appropriately with our users. </strong>The error might be indicating that the user cannot send a Direct Message to someone they&#8217;re not following. Or there might be something else amiss &#8211; so you&#8217;ll want to make provisions in your script to help the user understand why something might not be working.</p>
<p><strong>And that&#8217;s honestly all there is to it.</strong> Now that you&#8217;ve got the OAuthRequest function sussed, you just need to check with the <a href="http://twitterapi.pbworks.com/browse/#view=ViewFolder&#038;param=API%20Methods">Twitter API Wiki</a> to determine the correct urls and parameters to send, based on what you&#8217;re trying to do.</p>
<p>I have to say, having worked with a LOT of APIs, including Facebook, Amazon, and at least a half-dozen others, Twitter&#8217;s API is actually the most well-documented and simplest to use. Surprising, really, since Facebook and Amazon have actual business models, so you&#8217;d think they&#8217;d invest just an iota of time into documenting their shit. I&#8217;ve gone into long tirades here on my blog about how miserably awful the Facebook API documentation is, and Amazon&#8217;s API is probably 10x worse. Twitter&#8217;s API is, overall, pretty accurate and up to date. If its your first foray into writing an application with an API, I think Twitter is actually a good place to start &#8211; before you graduate to Facebook and wish you were dead.</p>
<h3>Recap &#8211; Important Links</h3>
<ul>
<li><a href="https://twitter.com/oauth_clients/new" target="_blank">Register your application with Twitter</a></li>
<li><a href="https://twitter.com/oauth_clients/" target="_blank">List of all of your registered apps on Twitter</a></li>
<li><a href="http://apiwiki.twitter.com/Twitter-API-Documentation" target="_blank">Twitter API Documentation</a></li>
<li><a href="http://apiwiki.twitter.com/Rate-limiting" target="_blank">Twitter API Rate Limiting Documentation</a></li>
<li><a href="https://docs.google.com/View?docID=dcf2dzzs_2339fzbfsf4" target="_blank">Download &amp; Docs for Abraham&#8217;s OAuth PHP library</a></li>
<li><a href="http://oauth.net/" target="_blank">OAuth official website</a></li>
</ul>
<p>And that&#8217;s all there is to it. Please use your new powers for good and not evil. No annoying games, no &#8220;increase your followers&#8221; services, etc. If you have any questions, leave &#8216;em in the comments.</p>

 <script type="text/javascript">
	<!--
		function onover(what){
	document.getElementById('blurbtext').innerHTML=''+what+'';
	}
	function onout(){
	document.getElementById('blurbtext').innerHTML='&nbsp;';
	}
	-->
	</script>



<h3 style="padding-bottom: 0px; margin-bottom: 0px;">Also check out: <br /><span id="blurbtext"><br /></span></h3>

<div id="relatedposts">




		
               

        
        
        
		<div class="yarppimg"><a href="http://www.snipe.net/2008/09/planning-a-facebook-application/" rel="bookmark">
		<img src="http://www.snipe.net/wp-content/themes/snipe/thumb.php?src=http://www.snipe.net/wp-content/uploads/2008/12/n40212040147_6720.jpg&amp;h=90&amp;w=90&amp;zc=1&amp;q=95" alt="Planning Your Facebook Application" height="90" width="90" onmouseover="onover('Planning Your Facebook Application')" onmouseout="onout()" /></a></div>

			
               

        
        
        
		<div class="yarppimg"><a href="http://www.snipe.net/2008/12/planning-a-facebook-application-part-two/" rel="bookmark">
		<img src="http://www.snipe.net/wp-content/themes/snipe/thumb.php?src=http://www.snipe.net/wp-content/uploads/2008/12/n40212040147_6720.jpg&amp;h=90&amp;w=90&amp;zc=1&amp;q=95" alt="Planning a Facebook Application: Part Two" height="90" width="90" onmouseover="onover('Planning a Facebook Application: Part Two')" onmouseout="onout()" /></a></div>

			
               

        
        
        
		<div class="yarppimg"><a href="http://www.snipe.net/2009/12/twitter-business-contributors/" rel="bookmark">
		<img src="http://www.snipe.net/wp-content/themes/snipe/thumb.php?src=http://www.snipe.net/wp-content/uploads/2009/12/love-twitter.jpg&amp;h=90&amp;w=90&amp;zc=1&amp;q=95" alt="Twitter Gets Down to Business" height="90" width="90" onmouseover="onover('Twitter Gets Down to Business')" onmouseout="onout()" /></a></div>

	</div>

]]></content:encoded>
			<wfw:commentRss>http://www.snipe.net/2009/07/writing-your-first-twitter-application-with-oauth/feed/</wfw:commentRss>
		<slash:comments>201</slash:comments>
		</item>
		<item>
		<title>Changes to Facebook&#8217;s Newsfeed/Wall</title>
		<link>http://www.snipe.net/2009/04/changes-to-facebooks-newsfeed/</link>
		<comments>http://www.snipe.net/2009/04/changes-to-facebooks-newsfeed/#comments</comments>
		<pubDate>Thu, 30 Apr 2009 21:32:17 +0000</pubDate>
		<dc:creator>snipe</dc:creator>
				<category><![CDATA[Featured]]></category>
		<category><![CDATA[Web Development]]></category>
		<category><![CDATA[facebook]]></category>
		<category><![CDATA[facebook application development]]></category>
		<category><![CDATA[facebook applications]]></category>
		<category><![CDATA[php]]></category>

		<guid isPermaLink="false">http://www.snipe.net/?p=1784</guid>
		<description><![CDATA[With the most recent API changes, specifically the one that changed the way fan pages behave so that they look and behave more like Facebook user profiles, Facebook also made a significant change in how newsfeeds work in applications. Previously, you would send newsfeed items to a user&#8217;s profile wall and their main newsfeed using [...]]]></description>
			<content:encoded><![CDATA[<p>With the most recent API changes, specifically the one that changed the way fan pages behave so that they look and behave more like Facebook user profiles, Facebook also made a significant change in how newsfeeds work in applications.<br />
<span id="more-1784"></span><br />
Previously, you would send newsfeed items to a user&#8217;s profile wall and their main newsfeed using the same API call.  <a href="http://wiki.developers.facebook.com/index.php/Feed.publishUserAction">Feed.publishUserAction</a> pretty much took care of all of the feed related publishing.</p>
<p>Something like this would do the trick:</p>
<p>[source='php']$template_bundle_id = 123456789;<br />
$tokens = array();</p>
<p>try {<br />
$facebook->api_client->feed_publishUserAction($template_bundle_id, json_encode($tokens), $array_of_friends_id, &#8221;);<br />
} catch(Exception $e) {<br />
// error trapping goes here<br />
}[/source]</p>
<p>The code above would insert a one-line story into the user&#8217;s profile wall (as seen below), and into their friends&#8217; /home.php newsfeed.</p>
<p style="text-align: center;"><a href="http://www.snipe.net/wp-content/uploads/2009/04/fb_feed.jpg"><img class="aligncenter size-large wp-image-1786" title="fb_feed" src="http://www.snipe.net/wp-content/uploads/2009/04/fb_feed-560x322.jpg" alt="fb_feed" width="560" height="322" /></a></p>
<p>While the profile item is nice, the truly viral aspects come from the friends&#8217; newsfeed items. Most people don&#8217;t spend a lot of time on profile pages &#8211; they rely on their /home.php page for the overview of what their friends are doing by way of posted items, status updates and application messaging.</p>
<p>With the latest change in the Facebook API, suddenly feeds stopped appearing in the the newly redesigned friends&#8217; newsfeed, now referred to as the &#8220;stream&#8221;. They were still being pushed to the user&#8217;s profile, but as we already mentioned, the usefulness of putting feed items there is somewhat limited.</p>
<p><strong>With these new updates, publishUserAction no longer publishes anything to the users&#8217; friends&#8217; stream, and now only publishes one-line stories to the user&#8217;s own profile wall.</strong></p>
<h3>Enter Feed Forms and Facebook.showFeedDialog</h3>
<p>Using <a href="http://wiki.developers.facebook.com/index.php/Facebook.showFeedDialog" target="_blank">showFeedDialog</a>, the user is prompted whether or not they want to publish the action to their stream. While this does mean changing some application code, switching oer to the new feed system is actually very easy for the most part. (I cannot speak for how one would do it in a Flash-based application, as I haven&#8217;t had to tackle that yet.)</p>
<p>Assuming you&#8217;ve already created your feed template bundle in the <a href="http://developers.facebook.com/tools.php?feed">feed template console</a>, you&#8217;d do something like this:</p>
<p>[source='php']$feed_template = &#8220;{&#8216;filmname&#8217;:'&#8221;.$film_name.&#8221;&#8216;, &#8216;images&#8217;:[{'src':'".$film_cover."', 'href':'http://apps.facebook.com/snagfilms'}]}&#8221;;</p>
<p>echo &#8216;<script type="text/javascript">
Facebook.showFeedDialog(123456790, '.$feed_template.');
</script>&#8216;;[/source]</p>
<p>As long as you have a short-story version in your feed template, that&#8217;s pretty much all you have to do. <strong>If your previous feed templates only used one-line stories, you WILL have to create new feed template bundles that use short stories, as one-line stories are NEVER published to the stream.</strong> Otherwise, just stick that line of PHP/JavaScript into your form handler (or whatever script completes the action the user is initiating) in your application and you&#8217;re back in business. </p>
<p>To further complicate things, Facebook just announced the beta launch of their <a href="http://wiki.developers.facebook.com/index.php/Using_the_Open_Stream_API">Open Stream API</a> using <a href="http://wiki.developers.facebook.com/index.php/Stream.publish">Stream.publish</a>, which looks like it might offer a simpler-but-different method by which you can publish feeds. Fortunately for this article &#8211; and for the time being, my sanity &#8211; the Open Stream API is in beta, and only application developers can publish to their stream from their apps. As more information is available about Stream.publish, I&#8217;ll try to keep you updated.</p>

 <script type="text/javascript">
	<!--
		function onover(what){
	document.getElementById('blurbtext').innerHTML=''+what+'';
	}
	function onout(){
	document.getElementById('blurbtext').innerHTML='&nbsp;';
	}
	-->
	</script>



<h3 style="padding-bottom: 0px; margin-bottom: 0px;">Also check out: <br /><span id="blurbtext"><br /></span></h3>

<div id="relatedposts">




		
               

        
        
        
		<div class="yarppimg"><a href="http://www.snipe.net/2009/10/upcoming-changes-to-the-facebook-application-platform/" rel="bookmark">
		<img src="http://www.snipe.net/wp-content/themes/snipe/thumb.php?src=http://www.snipe.net/wp-content/uploads/2009/10/facebook_1.jpg&amp;h=90&amp;w=90&amp;zc=1&amp;q=95" alt="Big Changes to the Facebook Platform" height="90" width="90" onmouseover="onover('Big Changes to the Facebook Platform')" onmouseout="onout()" /></a></div>

			
               

        
        
        
		<div class="yarppimg"><a href="http://www.snipe.net/2008/09/planning-a-facebook-application/" rel="bookmark">
		<img src="http://www.snipe.net/wp-content/themes/snipe/thumb.php?src=http://www.snipe.net/wp-content/uploads/2008/12/n40212040147_6720.jpg&amp;h=90&amp;w=90&amp;zc=1&amp;q=95" alt="Planning Your Facebook Application" height="90" width="90" onmouseover="onover('Planning Your Facebook Application')" onmouseout="onout()" /></a></div>

			
               

        
        
        
		<div class="yarppimg"><a href="http://www.snipe.net/2008/12/planning-a-facebook-application-part-two/" rel="bookmark">
		<img src="http://www.snipe.net/wp-content/themes/snipe/thumb.php?src=http://www.snipe.net/wp-content/uploads/2008/12/n40212040147_6720.jpg&amp;h=90&amp;w=90&amp;zc=1&amp;q=95" alt="Planning a Facebook Application: Part Two" height="90" width="90" onmouseover="onover('Planning a Facebook Application: Part Two')" onmouseout="onout()" /></a></div>

	</div>

]]></content:encoded>
			<wfw:commentRss>http://www.snipe.net/2009/04/changes-to-facebooks-newsfeed/feed/</wfw:commentRss>
		<slash:comments>31</slash:comments>
		</item>
		<item>
		<title>Quick and Dirty PHP Caching</title>
		<link>http://www.snipe.net/2009/03/quick-and-dirty-php-caching/</link>
		<comments>http://www.snipe.net/2009/03/quick-and-dirty-php-caching/#comments</comments>
		<pubDate>Sun, 29 Mar 2009 19:26:52 +0000</pubDate>
		<dc:creator>snipe</dc:creator>
				<category><![CDATA[Featured]]></category>
		<category><![CDATA[Web Development]]></category>
		<category><![CDATA[caching]]></category>
		<category><![CDATA[php]]></category>

		<guid isPermaLink="false">http://www.snipe.net/?p=1698</guid>
		<description><![CDATA[Caching your database-driven website pages has a plethora of benefits, not the least of which being improved speed and reduced server loads. This article will explain how to set up a simple caching system, and will also address when and where caching might not be appropriate. For me, the impetus to switch to a caching [...]]]></description>
			<content:encoded><![CDATA[<p>Caching your database-driven website pages has a plethora of benefits, not the least of which being improved speed and reduced server loads. This article will explain how to set up a simple caching system, and will also address when and where caching might not be appropriate.</p>
<p><span id="more-1698"></span></p>
<p>For me, the impetus to switch to a caching method for one of my database driven sites was sparked by <a href="http://www.snipe.net/series/moving-to-mosso/" target="_blank">Mosso</a>, since they bill by cpu cycle, and I have one site that is, well, humongous (60k+ pages), and it happens to the highest traffic site on the account. While the database queries were all very efficient, and each page had, on average, no more than 6 queries, performance and cpu cycles would both be helped quite a lot by implementing a cache. This caching solution was a temporary fix, while we switched to a new CMS that was already using a robust caching system. It&#8217;s quick, it&#8217;s dirty, but it got the job done for the interim.</p>
<p>We&#8217;ll walk through how to execute a simple PHP cache, and then I&#8217;m going to explain how doing so without a little forethought will screw you right in the ear. Note that this is called a Quick and Dirty solution for a reason. There are more complex, more efficient methods available, but this covers some basics.</p>
<p>Using <a href="http://us3.php.net/manual/en/book.outcontrol.php" target="_blank">output buffering</a>, caching pages is incredibly easy. Simply put, output buffering allows you to control when output is sent from the script. This is particularly handy if you&#8217;re using cookies or sessions or some other process that sends headers to the browser before the page loads (as anyone who has gotten those pesky &#8220;headers already sent&#8221; errors can tell you.)</p>
<p>Please note that this article assumes your cache files will be created in a directory called &#8216;cache&#8217; &#8211; and that this cache directory must be writable by the webserver.</p>
<p>Please also note: the syntax highlighter was made of fail for this article and was double, sometimes triple converting HTML entities. I have fixed it a dozen times, and then every time I edit the post, I have to fix it all over again. So if you notice any funky characters that don&#8217;t look like they belong in the script snippets, they probably don&#8217;t. Let me know and I&#8217;ll fix them, yet *again*.</p>
<h2>The basic stuff</h2>
<p>In all its 6-lines of glory, this is actual, working caching code.</p>
<p>[source=php]// TOP of your script<br />
ob_start();   // start the output buffer<br />
$cachefile =&#8221;cache/cachefile.html&#8221;;<br />
// Your normal PHP script and HTML content here<br />
// BOTTOM of your script<br />
$fp = fopen($cachefile, &#8216;w&#8217;); // open the cache file for writing<br />
fwrite($fp, ob_get_contents()); // save the contents of output buffer to the file<br />
fclose($fp); // close the file<br />
ob_end_flush(); // Send the output to the browser[/source]</p>
<p>There are, of course, two major flaws with just using the script above. First, we&#8217;re always writing to cachefile.html file, which would only be useful to you if your website was only one page. And second, notice that the script writes to the cache, but never actually retrieves the cache file &#8211; it&#8217;s still running through the whole script every time. But, this is just the beginning. That&#8217;s all there is to the actual <em>caching</em> part &#8211; the rest of this article will deal with the when/where of caching, but the <em>how</em> is that right there.</p>
<p>Which brings us to the next step&#8230; adding the ability to check whether or not a cache file exists, and use that instead of running through the normal script. We&#8217;re going to keep using the one-page website model for now, but I&#8217;ll get into creating cache files for different pages later.</p>
<h2>Checking for a cache file</h2>
<p>Creating the cache file from database-driven content is easy, as we&#8217;ve seen &#8211; but it&#8217;s only useful if we actually check if a cache file exists and serve that instead of live database output. Using he modification below, we are checking to see if a cache file already exists and if it does, include it and exit instead of running through the normal PHP script.</p>
<p>[source=php]// TOP of your script<br />
ob_start();   // start the output buffer<br />
$cachefile = &#8216;cache/cachefile.html&#8217;;<br />
if (file_exists($cachefile)) {<br />
// the page has been cached from an earlier request<br />
include($cachefile); // include the cache file<br />
exit; // exit the script, so that the rest isn&#8217;t executed<br />
} [/source]</p>
<p>This is marginally more useful, since it actually prevents the script from executing if a cache file exists, however the way this is currently written, it will include that file for an indefinite time, never actually executing your full script again. Normally, in a cache situation, we want the ability to &#8220;expire&#8221; content after a certain time, so an updated version will be displayed and cached. You could automatically force a new page cache file to be generated by setting a cron job to automatically delete your cache files every hour/day/week/whatever &#8211; or you could handle this on the script level.</p>
<h2>Setting cache urls</h2>
<p>In our examples, we&#8217;ve been using cache/cachefile.html as the filename for the cache file that is generated. As I mentioned, this is great if your site is only one page, but otherwise every page this script is run on will create the same cache file, so you&#8217;ll end up serving the same cached file as content for every page on your site. Not awesome.</p>
<p>The easiest way to create individual cache files for each specific page is to do something like this:</p>
<p>[source=php]$cachefile = basename($_SERVER['SCRIPT_URI']);[/source]</p>
<p>This takes the unique url of the page requested and and uses that as the cached filename.</p>
<p><strong>But, there&#8217;s a gotcha.</strong> If your site uses pages that pass GET requests, such as a search page, etc &#8211; the SCRIPT_URI won&#8217;t see that as part of the url, so once someone does a search, all subsequent search requests will serve that same cached file unless you make the file name unique to each GET request.</p>
<p>In other words, if your search is located at yoursite.com/search.php, and when someone performs a search, the url looks something like yoursite.com/search.php?q=foo, PHP sees that url as search.php, regardless of the query string. So basically, it will break your search, big time.</p>
<p>NOTE: It may not be worth caching every GET request if your site doesn&#8217;t get a lot of traffic to files that use this. Or if disk space is a concern. Since there are a potentially unlimited number of GET strings that could be passed to your script (even bogus ones that don&#8217;t return valid results on your site), you may want to evaluate whether or not caching search pages is appropriate. In my case, it was &#8211; but it may not be for everyone. At the very least, if you opt to do this, make sure you&#8217;ve got some sanity checking in there so some asshole with a grudge can&#8217;t just sit there creating new, bogus query strings to eat up your disk space.</p>
<p>If you decide to cache query string data, you could do something like this:</p>
<p>[source=php]$cachefile = basename($_SERVER['SCRIPT_URI']);<br />
if ($_SERVER['QUERY_STRING']!=&#8221;) {<br />
$cachefile .= &#8216;_&#8217;.base64_encode($_SERVER['QUERY_STRING']);<br />
}[/source]</p>
<p>This basically just grabs the file name, checks to see if there is any GET data passed and if there it, it generates a url-safe base64-encoded sting that you can use as your cache file name.</p>
<h2>Setting an expiration</h2>
<p>You have three basic options for expiring your cache:</p>
<ol>
<li>Set up a cron job to automatically delete all of your cache files at specified intervals</li>
<li>Check the data source file for modification, and expire it if the source file is newer than the cache file</li>
<li>Check the timestamp of the cache file and delete+regenerate if it is older than x</li>
</ol>
<p><strong>Cron Job:</strong> Setting up a cron job to delete your entire cache at specific intervals is arguably the easiest solution, but not really the most efficient, especially with very large websites. Rather than just deleting the page that&#8217;s been determined to be expired, you&#8217;re deleting (and then subsequently regenerating) a large number of files in one shot.</p>
<p><strong>Data Source: </strong>Checking the data source file for modification is potentially the smartest way to handle caching, since it means the cache would never be expired if the data didn&#8217;t change. That certainly makes sense to do, since a page that hasn&#8217;t been updated doesn&#8217;t need to be regenerated, so you&#8217;re really getting the most bang for your caching buck.</p>
<p>The problem arises when you&#8217;re caching pages that are dynamically generated based on database records. The actual script that generates the data may not have been changed for quite some time, but the data records you&#8217;re fetching from the database may have been changed, so just checking the cache file date against the date the script was last modified will not give you what you need.</p>
<p>A workaround there would be that you could do a quick db query at the top of every page to find out when the record was last modified and compare that to the modification time on the cache file, but that means that every page, even your cached pages, will be performing a database hit on every page load. This may be perfectly acceptable to you, but it&#8217;s something to consider. Perhaps a better way of handling this would be to modify the content management system by which you publish content, so that the cache file is only deleted when you publish edits. This method would be the most thorough and efficient way, since your cache file would only be updated when you update something, and would be left to be served statically unless the data has changed. Although that&#8217;s outside the scope of this quick and dirty article, extending the code below to accommodate that wouldn&#8217;t take much work.</p>
<p><strong>Cache Timestamp</strong>: We&#8217;re going to address the third option, since it&#8217;s the most commonly used and would serve as the foundation for the second option anyway.</p>
<p>[source=php]// TOP of your script<br />
$cachefile = basename($_SERVER['SCRIPT_URI']);<br />
$cachetime = 120 * 60; // 2 hours<br />
// Serve from the cache if it is younger than $cachetime<br />
if (file_exists($cachefile) &#038;&#038; (time() &#8211; $cachetime < filemtime($cachefile))) {<br />
include($cachefile);<br />
echo "<!-- Cached ".date('jS F Y H:i', filemtime($cachefile))." -->&#8220;;<br />
exit;<br />
}<br />
ob_start(); // start the output buffer [/source]</p>
<p>This script gets the file name, sets a cache time, checks to see if the cache file exists, and if it does, it checks if the cache file is younger than the cachetime. If the cache is still valid, it includes the file and exists the script. If not, it will continue on to execute the script and create a new cache file. It also tacks on a comment at the very end of the cache file that tells you when the file was cached. This can be helpful in debugging, and helping you verify that the page you&#8217;re seeing is in fact a cached version, not a live version. (You can see this in action if you view the source of this page and look down at the very bottom of the source code.)</p>
<h2>The script, the whole script and nothing but the script</h2>
<p>Put all together, this is what our caching script looks like:</p>
<p>[source=php]// TOP of your script<br />
$cachefile = &#8216;cache/&#8217;.basename($_SERVER['SCRIPT_URI']);<br />
$cachetime = 120 * 60; // 2 hours<br />
// Serve from the cache if it is younger than $cachetime<br />
if (file_exists($cachefile) &#038;&#038; (time() &#8211; $cachetime < filemtime($cachefile))) {<br />
include($cachefile);<br />
echo "<!-- Cached ".date('jS F Y H:i', filemtime($cachefile))." -->&#8220;;<br />
exit;<br />
}<br />
ob_start(); // start the output buffer<br />
// Your normal PHP script and HTML content here<br />
// BOTTOM of your script<br />
$fp = fopen($cachefile, &#8216;w&#8217;); // open the cache file for writing<br />
fwrite($fp, ob_get_contents()); // save the contents of output buffer to the file<br />
fclose($fp); // close the file<br />
ob_end_flush(); // Send the output to the browser[/source]</p>
<h2>Gee&#8230; Oh&#8230; Cache challenges</h2>
<p>I know. Going to hell for that awful joke. Moving on&#8230;</p>
<p>Caching is a great way to speed things up on dynamic sites and save on server resources &#8211; however if your site has any kind of more advanced features, you need to be selective about where you apply it. The cache is not smart, so you have to be. Ideally, you&#8217;ll be building your caching system into the site as you develop the site and the content administration system &#8211; but if you end up having to add caching later, you really have to think everything through.</p>
<p>Examples of things that WILL break if you use caching unless you specifically work around them:</p>
<p><strong>User login: </strong>&#8220;Welcome, user&#8221; logged in functionality (the first user who logs in will create the cache, and everyone else logging in will see their name instead of their own!</p>
<p><strong>Voting:</strong> If you have any kind of voting functionality built into your pages, new votes will not be captured and old ratings will be displayed</p>
<p><strong>Anything requiring a POST request: </strong>Same as above  the first person submitting the form will get correct results, but anyone submitting it after them will get the first user&#8217;s cached results.</p>
<p><strong>Geo-IP lookup: </strong>If you&#8217;re displaying geographically relevant information to the user based on their IP address, the same rules apply. The first user hitting your site will create the cache file and everyone else accessing it will see their geographic results instead of their own.</p>
<p>And so on&#8230;</p>
<p>That said, all hope is not lost. Depending on the situation and what functionality I&#8217;m trying to preserve, I usually handle this one of two ways:</p>
<p><strong>Only serve cached files to users who are NOT logged in. </strong>This takes care of a lot of the issues right there &#8211; if a user has a profile preferences page, email preferences page, or whatever &#8211; all of these will be cached by the first user accessing them. The easy way around this is simply to serve live data to the user if they are logged in, cached pages if they are not. This will reduce the effectiveness of your caching system to some degree, but many users never both logging in, so you&#8217;re still getting a significant savings. (If 90% of your site&#8217;s content is only available to logged-in users, you may need to rethink your caching system though.)</p>
<p><strong>Use AJAX. </strong>This is one of the few situations where AJAX really can be 100% appropriate. Since AJAX requests are asynchronous and are not cached, this is a great solution for your voting script situations. Mind you, you should make sure your solution degrades gracefully for users who have javascript turned off.</p>
<p><strong>Only cache parts of your page instead of the whole thing.</strong> With a little more work, you can set up your caching system to only cache parts of your page, and not the entire page. This may reduce the effectiveness of the caching system, but may be necessary depending on your situation.</p>
<h2>One final gotcha</h2>
<p>You should consider a graceful way of handling database failures as well. Say you have your cache time set for 3 days &#8211; a long time by some standards, but not at all unreasonable if you have disk space to spare and your content doesn&#8217;t update that often. If your database throws an error when your cache file is being regenerated, that error will continue to be displayed for 3 days, even if the database error has been corrected. You should consider how to handle that gracefully, even if its a cheap and dirty method. For example, you could set up a <a href="http://www.snipe.net/2009/01/cheap-or-free-website-status-monitoring/" target="_blank">website monitoring service</a> that notifies you when your content has changed. If your page isn&#8217;t loading properly, you&#8217;ll be notified by text or email, and that will give you the opportunity to fix the error and manually blow out your cache so it can regenerate.</p>
<h2>A note for WordPress users</h2>
<p>If you&#8217;re using WordPress and are looking for a way to reduce server load and speed your blog up, you&#8217;re in luck. <a href="http://wordpress.org/extend/plugins/wp-super-cache/" target="_blank">WP-Super Cache</a> is an unparalleled caching solution for WordPress that is basically plug-and-play, no coding required.</p>
<h2>Caching Libraries</h2>
<p>Thanks to the fabulous comments to this article (and I genuinely do mean that), I am reminded to remind <em>you</em> that this method is exactly what it says it is -<em> <strong>quick and dirty</strong></em> &#8211; and it makes NO attempt to be the best solution to your caching needs. It is as much an exercise in considering where caching is appropriate (and inappropriate) as much as it is anything else.</p>
<p>For more sophisticated (and certainly more elegant) solutions, check out <strong><a href="http://pear.php.net/package/Cache_Lite" target="_blank">PEAR’s Cache_Lite</a> , <a href="http://xcache.lighttpd.net/" target="_blank">xCache</a> </strong>(lighthttpd)<strong>, <a href="http://www.eaccelerator.net/" target="_blank">eAccelerator</a> </strong>and <strong><a href="http://files.zend.com/help/Zend-Platform/zend_cache_api.htm" target="_blank">Zend_Cache</a></strong>, and read up on <strong><a href="http://php.net/apc" target="_blank">APC</a></strong> and <strong><a href="http://www.danga.com/memcached/" target="_blank">memcached</a></strong>.</p>

 <script type="text/javascript">
	<!--
		function onover(what){
	document.getElementById('blurbtext').innerHTML=''+what+'';
	}
	function onout(){
	document.getElementById('blurbtext').innerHTML='&nbsp;';
	}
	-->
	</script>



<h3 style="padding-bottom: 0px; margin-bottom: 0px;">Also check out: <br /><span id="blurbtext"><br /></span></h3>

<div id="relatedposts">




		
               

        
        
        
		<div class="yarppimg"><a href="http://www.snipe.net/2010/11/rockmelt/" rel="bookmark">
		<img src="http://www.snipe.net/wp-content/themes/snipe/thumb.php?src=http://www.snipe.net/wp-content/uploads/2010/11/RockMelt.jpg&amp;h=90&amp;w=90&amp;zc=1&amp;q=95" alt="A Few Quick Thoughts on RockMelt" height="90" width="90" onmouseover="onover('A Few Quick Thoughts on RockMelt')" onmouseout="onout()" /></a></div>

			
               

        
        
        
		<div class="yarppimg"><a href="http://www.snipe.net/2009/03/and-still-more-notes-on-mosso/" rel="bookmark">
		<img src="http://www.snipe.net/wp-content/themes/snipe/thumb.php?src=http://www.snipe.net/wp-content/uploads/2009/02/data_center.gif&amp;h=90&amp;w=90&amp;zc=1&amp;q=95" alt="And Still More Notes on Mosso" height="90" width="90" onmouseover="onover('And Still More Notes on Mosso')" onmouseout="onout()" /></a></div>

			
               

        
        
        
		<div class="yarppimg"><a href="http://www.snipe.net/2010/04/google-analytics-on-facebook-fan-pages/" rel="bookmark">
		<img src="http://www.snipe.net/wp-content/themes/snipe/thumb.php?src=http://www.snipe.net/wp-content/uploads/2010/04/1123617456_bef53fb54c.jpg&amp;h=90&amp;w=90&amp;zc=1&amp;q=95" alt="Using Google Analytics on Facebook Fan Pages" height="90" width="90" onmouseover="onover('Using Google Analytics on Facebook Fan Pages')" onmouseout="onout()" /></a></div>

	</div>

]]></content:encoded>
			<wfw:commentRss>http://www.snipe.net/2009/03/quick-and-dirty-php-caching/feed/</wfw:commentRss>
		<slash:comments>74</slash:comments>
		</item>
		<item>
		<title>Trying out Facebook Connect</title>
		<link>http://www.snipe.net/2009/01/trying-out-facebook-connect/</link>
		<comments>http://www.snipe.net/2009/01/trying-out-facebook-connect/#comments</comments>
		<pubDate>Sun, 25 Jan 2009 20:18:32 +0000</pubDate>
		<dc:creator>snipe</dc:creator>
				<category><![CDATA[Featured]]></category>
		<category><![CDATA[Web Development]]></category>
		<category><![CDATA[facebook]]></category>
		<category><![CDATA[facebook connect]]></category>
		<category><![CDATA[php]]></category>
		<category><![CDATA[wordpress]]></category>

		<guid isPermaLink="false">http://www.snipe.net/?p=1166</guid>
		<description><![CDATA[After much deliberation, I have decided to give Facebook Connect a shot on Snipe.Net. Those of you who read this site regularly may remember that I had quite a lot to say about using Facebook Connect last month, so it may seem odd that I&#8217;m making this decision. I&#8217;ll explain. But&#8230; but you said&#8230;. It [...]]]></description>
			<content:encoded><![CDATA[<p>After much deliberation, I have decided to give Facebook Connect a shot on Snipe.Net. Those of you who read this site regularly may remember that I had <a href="http://www.snipe.net/2008/12/facebook-connect-a-more-authentic-web-or-loss-of-privacy/" target="_blank">quite a lot to say about using Facebook Connect</a> last month, so it may seem odd that I&#8217;m making this decision. I&#8217;ll explain.</p>
<h2><span id="more-1166"></span>But&#8230; but you said&#8230;.</h2>
<p>It appears a few of my concerns from my previous article were addressed &#8211; at least in part. Unlike a month ago, it seems that Facebook has improved their security, so that if someone has their privacy locked down tightly, their name no longer appears on the site. When I tested with my own Facebook login, my picture was the default Facebook user icon and my name was listed as <em>Facebook User</em>. This is a big improvement in my eyes.</p>
<p>My main argument against using Facebook Connect on a site is using it as the <em>only</em> way to login, giving your users the choice of Facebook Connect, or not commenting. On Snipe.Net, we do not require a login of any kind, so this is less of an issue. If a user doesn&#8217;t want to use Facebook Connect but wants to comment, they are still free to do so. They can opt to use Facebook Connect if they want comment noted in their Facebook newsfeed. If they don&#8217;t, that&#8217;s fine too.</p>
<h2>Goals</h2>
<p>I am a firm believer in having specific goals for implementing new technology &#8211; not simply using it because it exists *cough*ajax*cough*. My goals here are simple &#8211; to encourage more Facebook users to visit the site. Generally speaking, regular readers of Snipe.Net tend to be of the somewhat geeky persuasion, with the exception of the random person who found the site by way of Google because they were having a specific problem that we&#8217;ve addressed here. Geeky people tend to have other geeky people as their friends &#8211; so this is an opportunity to share the joy and light that is Snipe.Net with more geeks.</p>
<p>It could be argued that most &#8220;real&#8221; geeks wouldn&#8217;t be caught dead on Facebook &#8211; but if that&#8217;s the case, no harm no foul. Nothing has been comprimised by adding it, even if nothing has been gained.</p>
<h2>Making it happen</h2>
<p>Making a website using Facebook Connect from scratch requires a little programming know-how. Making a WordPress blog Facebook Connect-enabled doesn&#8217;t, since there is a <strong><a href="http://wordpress.org/extend/plugins/wp-facebookconnect/" target="_blank">handy little plugin</a></strong> for it already. It appears the plugin is actually Facebook sanctioned, as the <a href="http://wiki.developers.facebook.com/index.php/WP-FBConnect" target="_blank">WordPress plugin documentation</a> is available right from the Facebook developers wiki.</p>
<p>All you have to do is insert:</p>
<p>[source='php']< ? php do_action('fbc_display_login_button')  ?>[/source]</p>
<p>into your comments.php file. Couldn&#8217;t be easier.</p>
<p>As a simple example, the comments.php snippet would look something like this, noting that the new line of code appears outside the else/if loop that checks if the user is logged in:</p>
<p>[source='php']&lt;? php if ( $user_ID ) : ?&gt;<br />
&#8230;<br />
&lt;? php else : ?&gt;<br />
&#8230;.<br />
&lt;? php endif; ?&gt;<br />
< ? php do_action('fbc_display_login_button')  ?> [/source]</p>
<p>The installation was a breeze &#8211; and although I&#8217;m still testing things out, all I had to do was add a line of code to the comments file in my WordPress theme. I opted to be a little more creative with it, and stack the &#8220;normal&#8221; WordPress comment form next to the Facebook Connect prompt, so as not to make the comment form area any longer or more unwieldy than it already is.</p>
<h2>D&#8217;oh! Something&#8217;s borked!</h2>
<p>One gotcha &#8211; and I don&#8217;t know if this is a bug on my end, or a plugin conflict, or what yet &#8211; but after activating the Facebook Connect plugin, my edit post functionality in the admin seems to be borked. When I try to edit a specific post, the page stops loading after the:</p>
<p>[source='html']
<div id="quicktags">
<script type="text/javascript">
<!--
edToolbar()
// -->
</script>
</div>
<p>[/source]</p>
<p>Still looking into this issue, and once I figure out what the cause is, I&#8217;ll update this post. As it stands now,  I have to deactivate the plugin in order to edit posts, and then re-activate it. A pain in the ass, and if I don&#8217;t find a solution soon, my Facebook Connect experiment is going to go away real quick. I&#8217;ll start by disabling some of my admin plugins and see if that helps. More to come.</p>
<p><strong>Update: </strong>I disabled the <a href="http://deanjrobinson.com/projects/fluency-admin/" target="_blank">Fluency Admin</a> plugin and everything seems to be working fine. Pity, I like that admin skin. But the improved admin in WordPress 2.7 is certainly usable enough. Problem solved.</p>

 <script type="text/javascript">
	<!--
		function onover(what){
	document.getElementById('blurbtext').innerHTML=''+what+'';
	}
	function onout(){
	document.getElementById('blurbtext').innerHTML='&nbsp;';
	}
	-->
	</script>



<h3 style="padding-bottom: 0px; margin-bottom: 0px;">Also check out: <br /><span id="blurbtext"><br /></span></h3>

<div id="relatedposts">




		
               

        
        
        
		<div class="yarppimg"><a href="http://www.snipe.net/2008/12/facebook-connect-a-more-authentic-web-or-loss-of-privacy/" rel="bookmark">
		<img src="http://www.snipe.net/wp-content/themes/snipe/thumb.php?src=http://www.snipe.net/wp-content/uploads/2008/12/facebook-shirt.jpg&amp;h=90&amp;w=90&amp;zc=1&amp;q=95" alt="Facebook Connect &#8211; a More Authentic Web, Or Loss of Privacy?" height="90" width="90" onmouseover="onover('Facebook Connect &#8211; a More Authentic Web, Or Loss of Privacy?')" onmouseout="onout()" /></a></div>

			
               

        
        
        
		<div class="yarppimg"><a href="http://www.snipe.net/2009/04/facebook-application-tabs/" rel="bookmark">
		<img src="http://www.snipe.net/wp-content/themes/snipe/thumb.php?src=http://www.snipe.net/wp-content/uploads/2009/04/69tx0t.png&amp;h=90&amp;w=90&amp;zc=1&amp;q=95" alt="%$#^%$* Facebook Application Tabs" height="90" width="90" onmouseover="onover('%$#^%$* Facebook Application Tabs')" onmouseout="onout()" /></a></div>

			
               

        
        
        
		<div class="yarppimg"><a href="http://www.snipe.net/2008/09/planning-a-facebook-application/" rel="bookmark">
		<img src="http://www.snipe.net/wp-content/themes/snipe/thumb.php?src=http://www.snipe.net/wp-content/uploads/2008/12/n40212040147_6720.jpg&amp;h=90&amp;w=90&amp;zc=1&amp;q=95" alt="Planning Your Facebook Application" height="90" width="90" onmouseover="onover('Planning Your Facebook Application')" onmouseout="onout()" /></a></div>

	</div>

]]></content:encoded>
			<wfw:commentRss>http://www.snipe.net/2009/01/trying-out-facebook-connect/feed/</wfw:commentRss>
		<slash:comments>35</slash:comments>
		</item>
		<item>
		<title>Creating A WordPress Theme</title>
		<link>http://www.snipe.net/2009/01/creating-a-wordpress-theme/</link>
		<comments>http://www.snipe.net/2009/01/creating-a-wordpress-theme/#comments</comments>
		<pubDate>Fri, 09 Jan 2009 06:35:31 +0000</pubDate>
		<dc:creator>snipe</dc:creator>
				<category><![CDATA[Featured]]></category>
		<category><![CDATA[Web Development]]></category>
		<category><![CDATA[css]]></category>
		<category><![CDATA[php]]></category>
		<category><![CDATA[wordpress]]></category>

		<guid isPermaLink="false">http://www.snipe.net/?p=847</guid>
		<description><![CDATA[If you&#8217;ve already got some design chops and a WordPress blog, but you find the idea of turning it into a WordPress template a bit daunting, you&#8217;re not alone. Creating your own WordPress theme is actually easier than you might imagine, and although some PHP-fu is certainly helpful, you don&#8217;t need to be a PHP [...]]]></description>
			<content:encoded><![CDATA[<p>If you&#8217;ve already got some design chops and a WordPress blog, but you find the idea of turning it into a WordPress template a bit daunting, you&#8217;re not alone. Creating your own WordPress theme is actually easier than you might imagine, and although some PHP-fu is certainly helpful, you don&#8217;t need to be a PHP rockstar to pull off an amazing template design. <span id="more-847"></span></p>
<p>Creating your own WordPress theme will allow you to break out of free (or commercial) templates that mean your blog invariably looks just like hundreds (if not thousands) of other blogs out there using the same theme. Plus, once you&#8217;ve created a few and feel pretty comfortable, you can potentially take on paid work customizing WordPress templates, create commercial templates to sell to people less brave than you, or offer free templates on your website as a way to draw traffic to your blog.</p>
<h2>Getting Started</h2>
<p>First things first, if you have something designed already, I strongly urge you to code it out into (X)HTML before even looking at a WordPress theme tutorial. Trying to wrangle style sheets while trying to grok the theme structure might be a bit much, so you&#8217;ll be ahead of the game if you&#8217;ve already got your design and (X)HTML coding done. (If you&#8217;re unsure about how to code a table-free layout, using only CSS, check out our article, <strong><a href="http://www.snipe.net/2008/12/getting-started-all-css-website-layout/" target="_blank">Making the Leap to All-CSS Layout</a></strong>.)</p>
<p>One thing to keep in mind as you&#8217;re slicing and dicing your design and beginning your layout coding, there are some commonly used CSS element names in most WordPress themes that you may want to use in your code. Chance are, you&#8217;re not going to be creating every single template file from scratch, but rather, reusing a sample or tutorial template. Keeping the element names consistent will make this much easier in the long run. The template classes often used are:</p>
<ol>
<li>#wrapper (holds the entire layout except the footer)</li>
<li>#header (header part, including top page navigation)</li>
<li>#content (container that holds your main page content and sidebar)</li>
<li>#left-col (for the posting area, comment section and respond section)</li>
<li>#right-col (your sidebar)</li>
<li>#footer (footer)</li>
</ol>
<h2>Quick Note on CSS</h2>
<p>Notice that we&#8217;re using element ids instead of classes in the list above. This is because classes (such as li.foo or .foo) are meant to be reusable. CSS id elements (such as #foo) are only used once in a page, and since these primary elements are never re-used on the page, we use ids instead of classes. Using ids instead of classes will make inheritance much easier and will speed up your development time.</p>
<p>Just as a reminder to CSS-newbies, if you have an element defined with an id (as opposed to a class), its very easy to control large groups of child class elements. For example, something like this:</p>
<p>[source lang='html']
<div id="nav">
<ul>
<li>Nav Item 1</li>
<li>Nav Item 2</li>
<li>Nav Item 3</li>
</ul>
</div>
<p>[/source]</p>
<p>To apply a style to all of the list item elements inside of the div with the id of &#8220;nav&#8221;, you simply use this:<br />
[source lang='css']#nav li {<br />
color: white;<br />
}[/source]</p>
<p>This would turn all of the text in your list items elements white. You can further define specifics by combining ids and classes, like:</p>
<p>[source lang='css']#nav li.widget {<br />
color: green;<br />
}[/source]</p>
<p>That will cause the text in all of your list items with the class of &#8220;widget&#8221; within the &#8220;nav&#8221; div to turn green. Easy, right? I bring this up here (and my apologizes to anyone reading this who already understands the relationship between id and class) is because your WordPress HTML/CSS will be much cleaner and easier to work with if you take this approach.</p>
<h2>Moving On&#8230;</h2>
<p>While I could spend the time writing my own tutorial from scratch here, a few other people have already written ones that kick the crap out of anything I could come up with, so I&#8217;ll leave the actual nuts and bolts to them. A few tutorials really stand out from the rest. Some of these tutorials are pretty complicated and involved, while others work with only the basics to avoid confusing the reader with too much information.</p>
<p><strong><a href="http://nettuts.com/site-builds/how-to-create-a-wordpress-theme-from-scratch/" target="_blank">How to Create a WordPress Theme from Scratch</a></strong>, brought to you by <a href="http://nettuts.com/" target="_blank">NetTuts</a>, does exactly this, taking a very simple approach that may be particularly helpful with people still perfecting their CSS-fu. At the end of the tutorial, you end up with a plain, but functional, place to start that includes all of the basic functionality your blog will need, without overloading it with design elements that might be confusing.</p>
<p><strong><a href="http://themetation.com/2008/07/14/how-to-create-wordpress-themes-from-scratch-part-1/" target="_blank">How to Create a WordPress Theme from Scratch</a></strong>, brought to you by <a href="http://themetation.com" target="_blank">ThemeTation</a>, is an incredibly comprehensive tutorial that starts with actually designing, slicing and coding the PSD file. It might be a little much for someone who already knows how to slice and dice their PSDs into submission, but <a href="http://themetation.com/2008/07/17/how-to-create-wordpress-themes-from-scratch-part-3a/" target="_blank">part 3a</a> starts at actual implementation into WordPress. While this tutorial is a bit long, it gives you a start-to-finish walkthrough that may be very helpful to some.</p>
<p><strong><a href="http://www.wpdesigner.com/2007/02/19/so-you-want-to-create-wordpress-themes-huh/" target="_blank">So You Want to Create WordPress Themes, Huh?</a></strong>, brought to you by <a href="http://www.wpdesigner.com" target="_blank">WPDesigner</a>, is a bit of a middle ground of the first two tutorials listed. It&#8217;s very comprehensive, but it assumes that you&#8217;ve already got the layout slicing mostly covered, so the real focus is on WordPress theme structure and functionality.</p>
<p>There is even a <strong><a href="http://css-tricks.com/designing-for-wordpress-complete-series-downloads/" target="_blank">three-part video screencast tutorial</a></strong> available on the <a href="http://css-tricks.com/" target="_blank">CSS-Tricks website</a>. Pack a lunch, as the complete series is <em>over two hours long</em>, but Chris does a great job addressing theme creation from start to finish. They also provide the demo theme created in the video as a download, so you can play along.</p>
<h2>A Word on Widgets</h2>
<p>Plugins are arguably the best part of WordPress. Chances are, if you want your blog to have some special feature or function, someone has already created a plugin that does it. Not all plugins are widget-ready, but the ones that are usually use the same CSS containers, so that they will fit seamessly into your page design. (Not all widgets do this, which can be a pain in the ass, but you should plan for the standard and fix the ones that don&#8217;t comply.</p>
<p>The standard WordPress sidebar widget CSS looks something like this:</p>
<p>[source lang='html']
<div id="sidebar">
<ul>
<li class="widget">
<h2>Widget Name</h2>
<ul>
<li>Widget content 1</li>
<li>Widget content 2</li>
<li>Widget content 2</li>
</ul>
</li>
</ul>
</div>
<p>[/source]</p>
<p>Because this is a semi-standard format, you might want to consider coding your HTML in this way, so you have a better chance of widgets fitting into your site&#8217;s style right out of the box. It won&#8217;t work every time, but it often does, and I wish I had realized that when I first got started.</p>
<h2>Next Steps</h2>
<p>As usual, I tend to recommend that you actually follow the steps in these tutorials, one by one as you go. I&#8217;m a hands-on learner, so nothing makes information stick in my brain better than actually getting into the muck of it.</p>
<p>Personally, when I learned to make WordPress themes, I started with the simplest tutorials listed above, and then opened the default theme that comes with WordPress, copied it, installed my new copy under a new name, and used that as the place to start. Once I felt pretty confident there, I poked around in some of the more complicated themes, to see how they did what they do. Start simple &#8211; don&#8217;t try to conquer the world of WordPress your first time. The more comfortable you get with the structure and functions, the more great ideas you&#8217;ll have on what you can do with your blog.</p>
<p>When you&#8217;re ready to get more advanced, check out the <strong><a href="http://codex.wordpress.org/Main_Page" target="_blank">WordPress Codex</a></strong>, that explains what each function within WordPress does, usually with detailed examples and documentation. If you start to get fancy with your WordPress queries, specifically with regard to specifying posts from only one (or more) categories, or all posts from one (or more) categories except the one you specify, the <a href="http://codex.wordpress.org/Template_Tags/query_posts" target="_blank">Template Tags &#8211; Query page</a> in the codex will be your new best friend. The forums are also a great place to get answers to a specific question.</p>

 <script type="text/javascript">
	<!--
		function onover(what){
	document.getElementById('blurbtext').innerHTML=''+what+'';
	}
	function onout(){
	document.getElementById('blurbtext').innerHTML='&nbsp;';
	}
	-->
	</script>



<h3 style="padding-bottom: 0px; margin-bottom: 0px;">Also check out: <br /><span id="blurbtext"><br /></span></h3>

<div id="relatedposts">




		
               

        
        
        
		<div class="yarppimg"><a href="http://www.snipe.net/2009/01/essential-wordpress-plugins/" rel="bookmark">
		<img src="http://www.snipe.net/wp-content/themes/snipe/thumb.php?src=http://www.snipe.net/wp-content/uploads/2009/01/blog_logo.jpg&amp;h=90&amp;w=90&amp;zc=1&amp;q=95" alt="Essential WordPress Plugins" height="90" width="90" onmouseover="onover('Essential WordPress Plugins')" onmouseout="onout()" /></a></div>

			
               

        
        
        
		<div class="yarppimg"><a href="http://www.snipe.net/2010/11/wordpress-security-book/" rel="bookmark">
		<img src="http://www.snipe.net/wp-content/themes/snipe/thumb.php?src=http://www.snipe.net/wp-content/uploads/2010/11/secure-wordpress.jpg&amp;h=90&amp;w=90&amp;zc=1&amp;q=95" alt="Upcoming WordPress Security Book" height="90" width="90" onmouseover="onover('Upcoming WordPress Security Book')" onmouseout="onout()" /></a></div>

			
               

        
        
        
		<div class="yarppimg"><a href="http://www.snipe.net/2010/06/upgrading-to-wordpress-3/" rel="bookmark">
		<img src="http://www.snipe.net/wp-content/themes/snipe/thumb.php?src=http://www.snipe.net/wp-content/uploads/2010/06/wordpress-mug.jpg&amp;h=90&amp;w=90&amp;zc=1&amp;q=95" alt="Upgrading to WordPress 3.0 and Adding Multi-Site" height="90" width="90" onmouseover="onover('Upgrading to WordPress 3.0 and Adding Multi-Site')" onmouseout="onout()" /></a></div>

	</div>

]]></content:encoded>
			<wfw:commentRss>http://www.snipe.net/2009/01/creating-a-wordpress-theme/feed/</wfw:commentRss>
		<slash:comments>18</slash:comments>
		</item>
	</channel>
</rss>

<!-- Dynamic page generated in 0.572 seconds. -->
<!-- Cached page generated by WP-Super-Cache on 2012-02-03 02:25:42 -->

