<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
	<channel>
		<title>Ben Edmunds</title>
		<description>Ben Edmunds Blog</description>
		<link>http://benedmunds.com</link>
		<atom:link href="http://benedmunds.com/feed.xml" rel="self" type="application/rss+xml" />
		
			<item>
				<title>AI Skills Are the New Platform Interface</title>
				<description>
&lt;p&gt;An evolving idea I’m working through is that developer portals like Backstage and Port are becoming obsolete.  They solved a real problem.  Engineers needed one place to find services, templates, and docs.  But a portal is just a website.  It’s passive.  It shows you things and gives you forms.  The developer still has to leave their editor, open a browser, find the right page, and click through a workflow.  That’s a lot of ceremony for someone who just wants to check who owns a service.&lt;/p&gt;

&lt;p&gt;AI skills skip all of that.  A skill connected to your service catalog via MCP can answer “what depends on the payments API?” without anyone opening a tab.  A skill that knows your Terraform modules can scaffold infrastructure, apply your org’s naming conventions and compliance guardrails, and hand back real code.  For new services, we still use cookiecutter templates to keep things deterministic.  But the skill knows which template to use and how to run it.&lt;/p&gt;

&lt;p&gt;Your engineers already live in their CLI.  Meet them there.&lt;/p&gt;
</description>
				<pubDate>Thu, 02 Apr 2026 00:00:00 +0000</pubDate>
				<link>http://benedmunds.com/management/2026/04/02/ai-skills-are-the-new-platform-interface</link>
				<guid isPermaLink="true">http://benedmunds.com/management/2026/04/02/ai-skills-are-the-new-platform-interface</guid>
			</item>
		
			<item>
				<title>The Platform Hierarchy of Needs</title>
				<description>
&lt;p&gt;Every platform team I’ve talked to wants to build a portal. A developer portal with a service catalog, self-service provisioning, and change management workflows. It’s the slick stuff. It’s also the last thing you should build.&lt;/p&gt;

&lt;p&gt;Platforms evolve in layers. Each layer builds on the one below it. Skip a layer and you end up with a portal that provisions services into infrastructure nobody can observe, deployed through pipelines nobody trusts. You’re stacking bricks on sand.&lt;/p&gt;

&lt;p&gt;I think about this as a platform hierarchy of needs. Just like Maslow’s hierarchy, you can’t meaningfully work on the higher levels until the lower ones are solid. Here’s what it looks like:&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/images/platform-hierarchy-of-needs.svg&quot; alt=&quot;Platform Hierarchy of Needs&quot; /&gt;&lt;/p&gt;

&lt;p&gt;At the base you have the fundamentals. Your workloads run in the cloud. Secrets are managed, not hardcoded. Environments are isolated. You have basic APM so you can see when things are broken. Incident management exists as a process, not just someone pinging a Slack channel. Deployments are automated, even if they’re simple. This is the floor. Without this, nothing above it matters.&lt;/p&gt;

&lt;p&gt;The next layer up is where things start getting real. Infrastructure as code so you’re not clicking around in consoles. Observability beyond just “is it up?” to actual structured logs, metrics, and traces. Teams own their own incidents instead of throwing everything over the wall to an SRE team. Zero-downtime deployments so shipping code doesn’t mean taking a hit.&lt;/p&gt;

&lt;p&gt;Then you mature those foundations. IaC goes from “we have some Terraform” to full coverage with zero clickops. Monitoring becomes proactive instead of reactive. You move from automated deployments to true continuous delivery. And you start showing teams what their infrastructure costs. Not charging them yet, just making the numbers visible. Cost showback changes behavior all by itself.&lt;/p&gt;

&lt;p&gt;Once that’s solid, you can start getting sophisticated. Auto-scaling that actually works. Service discovery so services find each other without hardcoded endpoints. Canary and blue-green deployments for safer rollouts. Cost chargeback so teams have real skin in the game on spending.&lt;/p&gt;

&lt;p&gt;Higher still, you get traffic shaping, ephemeral environments for testing, and advanced deployment strategies. These are genuinely powerful capabilities. But they’re useless if your teams can’t even see what’s running in production or if your IaC only covers half your infrastructure.&lt;/p&gt;

&lt;p&gt;Near the top, platform abstractions and shared libraries let you encode all those lower layers into reusable building blocks. A team spins up a new service and gets observability, deployment pipelines, auto-scaling, and cost tracking for free. This is where the platform really starts compounding.&lt;/p&gt;

&lt;p&gt;And finally, at the peak: the portal and change management. Now you have something worth putting a UI in front of. The portal works because every layer beneath it is solid. Change management works because you have the observability, the deployment safety, and the cost visibility to actually understand the impact of changes.&lt;/p&gt;

&lt;p&gt;The failure mode is always the same. A team reads a blog post about Backstage, gets excited, and starts building a developer portal when they still have services with no observability and deployments that require SSH access. It’s not that the portal is a bad idea. It’s that it’s a bad idea right now.&lt;/p&gt;

&lt;p&gt;Each layer in this hierarchy enables the next one. You can’t do meaningful cost chargeback if you don’t have cost showback first. You can’t do canary deployments if you don’t have zero-downtime deployments figured out. You can’t build useful platform abstractions if the underlying capabilities are half-baked.&lt;/p&gt;

&lt;p&gt;The good news is you don’t need to finish each layer perfectly before moving up. You need it solid enough. IaC covering 90% of your infrastructure? Good enough to start thinking about proactive monitoring. Observability in place for your critical services? Start experimenting with canary deployments. It’s not a strict gate, it’s a foundation that needs to bear weight.&lt;/p&gt;

&lt;p&gt;Build the base. Stack the bricks. Resist the urge to jump to the top of the pyramid. The portal will be there when you’re ready for it.&lt;/p&gt;
</description>
				<pubDate>Sun, 01 Mar 2026 00:00:00 +0000</pubDate>
				<link>http://benedmunds.com/management/2026/03/01/the-platform-hierarchy-of-needs</link>
				<guid isPermaLink="true">http://benedmunds.com/management/2026/03/01/the-platform-hierarchy-of-needs</guid>
			</item>
		
			<item>
				<title>Platform Engineering Isn&apos;t a Portal</title>
				<description>
&lt;p&gt;Every company eventually builds an internal developer platform. The mistake most teams make is building the wrong one for their size.&lt;/p&gt;

&lt;p&gt;At a 50-person company you don’t need a portal. You don’t need a service catalog. You need to stop making every team solve the same damn problems over and over again. Rate limiting, auth, deployment pipelines. These things should be solved once and pushed into the platform so product teams never think about them.&lt;/p&gt;

&lt;p&gt;Early stage platform engineering is about opinionated abstractions. You pick the right defaults, bake them in, and let teams ship features instead of configuring load balancers. The whole point is that a developer starting a new service shouldn’t have to care how auth works or how deploys get rolled out. They just write code and it works. That’s the platform doing its job.&lt;/p&gt;

&lt;p&gt;This only works if you’re willing to be opinionated. A platform that gives you twelve options for deployment is not a platform. It’s a burden. At this stage, fewer choices means faster teams. You’re trading flexibility for velocity, and that’s the right trade when you have more problems than people.&lt;/p&gt;

&lt;p&gt;Then you grow. You hit a few hundred engineers, maybe more. Teams start bumping into the edges of those nice abstractions. Someone needs a custom deployment strategy for a ML pipeline. Another team needs fine-grained control over rate limiting because their traffic patterns are weird. The opinionated defaults that got you here start feeling like constraints.&lt;/p&gt;

&lt;p&gt;This is where the platform evolves. You still keep the abstractions. They’re still the happy path and most teams should use them. But now you layer on tooling that lets teams pierce those abstractions when they have a real reason to. Developer portals like Backstage start making sense because you actually have enough services and teams to need a catalog. Code generation tooling helps enforce patterns across a bigger surface area. More automation fills the gaps that humans used to cover when the company was small.&lt;/p&gt;

&lt;p&gt;The later stage platform is everything the early one was plus off-ramps. The defaults still exist. Most teams still use them. But the teams with unique needs can dig in, customize, and own their own complexity without blowing up everyone else’s experience.&lt;/p&gt;

&lt;p&gt;The common failure mode is building the later stage platform too early. I’ve watched small companies spend months setting up Backstage when they have fifteen services and three teams. That’s not platform engineering. That’s premature optimization. Start with strong opinions. Solve the boring problems well. You’ll know when it’s time to add the portal and the off-ramps because teams will be actively fighting your abstractions. Until then, keep it simple and keep shipping.&lt;/p&gt;
</description>
				<pubDate>Mon, 16 Feb 2026 00:00:00 +0000</pubDate>
				<link>http://benedmunds.com/management/2026/02/16/platform-engineering-isnt-a-portal</link>
				<guid isPermaLink="true">http://benedmunds.com/management/2026/02/16/platform-engineering-isnt-a-portal</guid>
			</item>
		
			<item>
				<title>Testing Microservices Without Cloning the World</title>
				<description>
&lt;p&gt;Shared staging environments are a lie we all agree to believe. Developers need to deploy broken code to test it. Other developers need that same environment to not be broken. You can’t have both, and yet every company tries.&lt;/p&gt;

&lt;p&gt;This is one of those problems that seems simple until you actually have microservices. With a monolith, you spin up a review app and you’re done. With dozens of services talking over HTTP, gRPC, and message queues, testing one service in isolation tells you almost nothing. Your feature touches three services and a background worker. A single-service review app is useless.&lt;/p&gt;

&lt;p&gt;The obvious fix is cloning the whole environment. Just copy everything for each feature branch. Except that’s absurdly expensive and slow when “everything” means your entire infrastructure. Nobody’s doing that at scale.&lt;/p&gt;

&lt;p&gt;Mocking is the other trap. It feels productive because your tests pass, but your mocks drift from reality over time. You end up with green CI and broken production. False confidence is worse than no confidence because at least with no confidence you test manually before shipping.&lt;/p&gt;

&lt;h2 id=&quot;the-real-problem-is-partial-isolation&quot;&gt;The Real Problem Is Partial Isolation&lt;/h2&gt;

&lt;p&gt;What you actually need is a way to route traffic to your changed services while everything else falls back to stable staging. You want isolation where it matters and shared infrastructure everywhere else.&lt;/p&gt;

&lt;p&gt;At SeatGeek we built Ephie to solve exactly this. The core idea is DNS-based routing. Services in your ephie environment resolve DNS within their own namespace first. If the service exists there, traffic stays local. If it doesn’t, DNS falls back to stable staging. Simple concept, and it actually works.&lt;/p&gt;

&lt;p&gt;But HTTP routing only gets you halfway. When services communicate through RabbitMQ, you can’t just redirect DNS. You need isolated message brokers too. And if you spin up workers against a shared database without thinking about it, those workers start competing with staging workers for the same jobs. So Ephie handles that by scaling worker replicas to zero when resources aren’t isolated, and optionally spinning up dedicated RabbitMQ clusters and Postgres databases per environment.&lt;/p&gt;

&lt;h2 id=&quot;what-developers-actually-see&quot;&gt;What Developers Actually See&lt;/h2&gt;

&lt;p&gt;Developers don’t care about DNS routing or namespace resolution. They care about “can I test my thing.” Ephie gives them an interactive CLI where they pick which services to test, choose a branch or MR for each, and optionally toggle on isolated databases or message brokers. The Postgres databases restore from weekly snapshots and spin up in under a minute. Slack notifications ping when your environment is ready. Datadog dashboards show you what’s happening inside it.&lt;/p&gt;

&lt;p&gt;Average startup time is just over three minutes. At peak we had 75 monthly active users (engineers) running 70 concurrent environments. Teams that used to wait days for a test cycle on shared staging cut that time dramatically. The inventory team was one of the loudest advocates because their workflows touched so many services that shared staging was basically unusable for them.&lt;/p&gt;

&lt;h2 id=&quot;the-part-that-mattered-most&quot;&gt;The Part That Mattered Most&lt;/h2&gt;

&lt;p&gt;The strongest signal that Ephie worked wasn’t the usage numbers. It was that teams actively campaigned for continued investment in it. When engineers go out of their way to tell leadership “keep funding this tool,” that’s about as clear a signal as you’ll get in platform engineering.&lt;/p&gt;

&lt;p&gt;Check out the full technical details on the SeatGeek blog: &lt;a href=&quot;https://chairnerd.seatgeek.com/ephie/&quot;&gt;Ephie: Ephemeral Environments at SeatGeek&lt;/a&gt;. That post covers the Kubernetes architecture, DNS resolution chain, CloudNativePG setup, and all the implementation specifics.&lt;/p&gt;
</description>
				<pubDate>Mon, 29 Sep 2025 00:00:00 +0000</pubDate>
				<link>http://benedmunds.com/management/2025/09/29/ephemeral-environments-for-microservices</link>
				<guid isPermaLink="true">http://benedmunds.com/management/2025/09/29/ephemeral-environments-for-microservices</guid>
			</item>
		
			<item>
				<title>Rearchitecting CI at SeatGeek</title>
				<description>
&lt;p&gt;Our CI runners were slowly ruining everyone’s day. Shared, stateful hosts where one team’s build could poison the environment for the next team. Classic noisy neighbor problem, except at the infrastructure layer where it’s way harder to figure out what went wrong.&lt;/p&gt;

&lt;p&gt;We had about 80 hosts on weekdays, 10 on weekends. Fixed scaling. Peak hours meant developers sat in queue. Off-peak meant machines sat idle burning money. We were paying for capacity we weren’t using and still didn’t have enough when it actually mattered.&lt;/p&gt;

&lt;p&gt;Container builds made it worse. Tightly coupled to EC2 hosts with local Docker daemons. Settings persisted between builds, so one team’s config could quietly break the next team’s image build. Multi-arch images required emulation that absolutely destroyed build times. The whole thing was brittle and nobody trusted it.&lt;/p&gt;

&lt;h2 id=&quot;600-repos-cant-flip-a-switch&quot;&gt;600 Repos Can’t Flip a Switch&lt;/h2&gt;

&lt;p&gt;We had over 600 repositories on this infrastructure. You don’t just migrate that over a weekend.&lt;/p&gt;

&lt;p&gt;We ran a four-phase rollout. Started with our own platform team repos so we ate our own dogfood first. Expanded to other platform-owned repos. Updated the shared CI jobs. Then automated the long tail with multi-gitter across hundreds of repos. Each phase surfaced problems we could fix before the blast radius got bigger. That phasing is the only reason we pulled this off without pissing everyone off.&lt;/p&gt;

&lt;h2 id=&quot;autoscaling-ci-is-harder-than-you-think&quot;&gt;Autoscaling CI Is Harder Than You Think&lt;/h2&gt;

&lt;p&gt;This is the part nobody warns you about. Autoscaling CI infrastructure sounds straightforward until you actually try it.&lt;/p&gt;

&lt;p&gt;You need the right metric. We used saturation: the ratio of pending and running jobs to available slots. Most default metrics don’t capture the developer experience of staring at a queue. You need graceful shutdowns because Buildkit will just kill your build mid-way on SIGTERM if you let it. And you need capacity reservation so that scaling up doesn’t mean waiting five minutes for a node to come online. We over-provisioned with low-priority pods that pre-pulled common images, then got evicted when real work showed up.&lt;/p&gt;

&lt;p&gt;None of these are individually hard. Together they’re a real engineering problem.&lt;/p&gt;

&lt;h2 id=&quot;what-we-built&quot;&gt;What We Built&lt;/h2&gt;

&lt;p&gt;Kubernetes with ephemeral pods. Every CI job gets its own isolated pod that’s destroyed when the job finishes. No state leaking between builds. No noisy neighbors. Clean slate every time.&lt;/p&gt;

&lt;p&gt;For container builds, we deployed Buildkit as Kubernetes deployments connected via remote driver. Completely decoupled from the CI hosts. No more shared Docker daemons.&lt;/p&gt;

&lt;h2 id=&quot;the-numbers&quot;&gt;The Numbers&lt;/h2&gt;

&lt;p&gt;Average queue time dropped from 16 seconds to 2. The p98 went from over 3 minutes to under 4 seconds. Cost per job down 40%. Concurrent job capacity doubled. And zero state pollution between builds.&lt;/p&gt;

&lt;h2 id=&quot;go-read-the-technical-posts&quot;&gt;Go Read the Technical Posts&lt;/h2&gt;

&lt;p&gt;We wrote a three-part series on the SeatGeek blog with the full technical details:&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;https://chairnerd.seatgeek.com/ci-runner-rearchitecture/&quot;&gt;Part 1: Rearchitecture&lt;/a&gt; covers the architecture decisions, the Kubernetes executor setup, and the migration strategy across all those repos.&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;https://chairnerd.seatgeek.com/building-containers-on-kubernetes-with-buildkit/&quot;&gt;Part 2: Building Containers with Buildkit&lt;/a&gt; covers how we replaced local Docker daemons with remote Buildkit deployments and all the fun edge cases that came with it.&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;https://chairnerd.seatgeek.com/ci-runner-optimizations/&quot;&gt;Part 3: Optimizations&lt;/a&gt; covers autoscaling, caching, NVMe storage, and the performance work that got us to those final numbers.&lt;/p&gt;

&lt;p&gt;If you’re running shared CI infrastructure and feeling the pain, start with Part 1. The problems will sound familiar.&lt;/p&gt;
</description>
				<pubDate>Tue, 21 Jan 2025 00:00:00 +0000</pubDate>
				<link>http://benedmunds.com/management/2025/01/21/rearchitecting-ci-at-seatgeek</link>
				<guid isPermaLink="true">http://benedmunds.com/management/2025/01/21/rearchitecting-ci-at-seatgeek</guid>
			</item>
		
			<item>
				<title>Onboarding New Developers to a Legacy Codebase</title>
				<description>
&lt;p&gt;I’ve ran into an issue recently that hopefully can help you.  I’ve been freelancing for a non-profit that has several products that have been in development for years.  One of these codebases in particular is pretty huge and verbose, with many different developers touching it over several years.&lt;/p&gt;

&lt;p&gt;The biggest issue we’ve all faced with onboarding to this project has been converting what the business stakeholders are asking for, into scoped requirements and code that handles all of the edges and complexity presented by this large (mostly undocumented) codebase.&lt;/p&gt;

&lt;p&gt;We’ve implemented a process, that I’ve used successfully in the past when I was onboarding freelancers for my projects, and it’s going pretty well.  What I’m doing is first developing a rough, minimal, implementation of the feature that’s requested and then submitting that for review to technical and business stakeholders to review and then discuss.  This is often an intermediate pull request as soon as enough code to cover the basics of the implementation is ready.&lt;/p&gt;

&lt;p&gt;This gives us all an example to review together to be sure we’re on the same page. Then once we work out the correct scope, based on this example, I’ll develop the full feature.&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;http://benedmunds.com/posts.html#contact&quot; target=&quot;_blank&quot;&gt;Reach out&lt;/a&gt; if you’d like to discuss this more, I’d love to hear your thoughts.&lt;/p&gt;
</description>
				<pubDate>Sun, 15 Apr 2018 00:00:00 +0000</pubDate>
				<link>http://benedmunds.com/management/2018/04/15/onboarding-developers-to-legacy-codebase</link>
				<guid isPermaLink="true">http://benedmunds.com/management/2018/04/15/onboarding-developers-to-legacy-codebase</guid>
			</item>
		
			<item>
				<title>Evaluating Contractors</title>
				<description>
&lt;p&gt;A question was recently posed to a CTO mailing list I’m a part of as to evaluating contractors.   The poster was looking at frontend web development contractors and trying to determine the best way to evaluate them.  In case you find yourself in a similar situation, here is my (slightly edited) response:&lt;/p&gt;

&lt;hr /&gt;

&lt;p&gt;OP,&lt;/p&gt;

&lt;p&gt;I’ve done several types of evaluations.  I’ve found that the two below seem to work best for me.&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;
    &lt;p&gt;I greatly prefer using real world issues.  I usually setup a small agreement (4-8 hour contract) with appropriate NDAs.  It ensures the contractor receives value for their time and gives me a good feel for how their work will be.  I’ll then have the contractor work a real issue/ticket we have open on the system they’ll be working with.  Just make sure to include time for them to get setup with their local development environment along with appropriate instructions.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;If that’s not possible, I’d recommend having them do a sample project thats similar to your core stack.  Although exact frameworks and libraries wouldn’t be a concern for me.  I’ll usually have someone create something simple, a guitar tab site is a fun favorite of mine, and dictate one or two tools.  Then I’ll let them decide the rest.  I find that seeing how someone architects a project with a lot of decisions left up to them tells you much more than having them follow an exact spec.&lt;/p&gt;
  &lt;/li&gt;
&lt;/ol&gt;

&lt;hr /&gt;

&lt;p&gt;Hit me up on &lt;a href=&quot;http://twitter.com/benedmunds&quot; target=&quot;_blank&quot;&gt;Twitter&lt;/a&gt;, I’d love to hear your thoughts.&lt;/p&gt;
</description>
				<pubDate>Wed, 16 Aug 2017 00:00:00 +0000</pubDate>
				<link>http://benedmunds.com/management/2017/08/16/evaluating-contractors</link>
				<guid isPermaLink="true">http://benedmunds.com/management/2017/08/16/evaluating-contractors</guid>
			</item>
		
			<item>
				<title>CodeIgniter 4 Overview - It&apos;s really not dead!</title>
				<description>
&lt;p&gt;I’ve been getting excited about and have started talking about CodeIgniter 4 a lot more recently.  Several people have asked “that isn’t dead yet”, “why”, or similar questions so I’m going to give a high level overview of the what and why of CodeIgniter 4.&lt;/p&gt;

&lt;p&gt;I’ll be speaking just of my personal opinions and will do my best not to misrepresent my fellow CodeIgniter Council members who have by far done the majority of the hard work with the development of version 4.&lt;/p&gt;

&lt;h3 id=&quot;lets-start-with-some-context-around-codeigniter&quot;&gt;Let’s start with some context around CodeIgniter&lt;/h3&gt;

&lt;p&gt;The general ethos around CodeIgniter, both as a community and as a framework, has always been to “get shit done”.  People are drawn to CodeIgniter for a variety of reasons. IMHO the main draws are it’s relatively short learning curve, stable API, lack of opinion about how you code, and the way the community celebrates shipping over perfection.&lt;/p&gt;

&lt;p&gt;This served the community well for good a while but over time the apprehension towards breaking backwards compatibility and general neglect by previous maintainers caused it’s community to slowly dissipate.  It was hard to get excited about starting a project with CodeIgniter when it hadn’t been updated to support any of the enhancements to PHP from the past decade and didn’t even play well with others.&lt;/p&gt;

&lt;p&gt;Around the same time as CodeIgniter was fizzling, Laravel came on the scene (I’m personally a big fan of Laravel by the way).  A lot of the CodeIgniter community moved to Laravel 4 once it was released.  It had a very simple architecture and followed a similar design philosophy to what we were used to.&lt;/p&gt;

&lt;p&gt;This resulted in CodeIgniter stagnating as far as most people were concerned.&lt;/p&gt;

&lt;h3 id=&quot;where-we-are-now&quot;&gt;Where we are now&lt;/h3&gt;

&lt;p&gt;A couple years ago CodeIgniter was acquired by The British Columbia Institute of Technology (BCIT) and fully open sourced.  This gave the community the opportunity to take control of the development of the framework and started pushing it forward.&lt;/p&gt;

&lt;p&gt;With a community driven team in place, version 3 was soon finished and released.  Version 3 was an incremental release so development was quickly mapped out for a truly new version of CodeIgniter.  This version would have the latest PHP features but still allow you to develop a simple app end to end.  Version 4 was born.&lt;/p&gt;

&lt;p&gt;Development on version 4 has been slow but very well considered.  Release of a public stable version is getting increasingly close, likely to be later this year or early next year (not official).&lt;/p&gt;

&lt;h3 id=&quot;why&quot;&gt;Why&lt;/h3&gt;

&lt;p&gt;Now to the real point of this post and what you’re probably here for.  Why.&lt;/p&gt;

&lt;p&gt;In the current PHP ecosystem, where most frameworks resemble Java more than the PHP of a few years ago I think there’s a real niche in the market for a framework that is quick, simple, and easy to use but still gives you all the power of newer PHP features.&lt;/p&gt;

&lt;p&gt;Laravel has moved to version 5, which leaves simple MVC behind for powerful, and complicated, command bus style architecture.&lt;/p&gt;

&lt;p&gt;Symfony has continued to evolve and become a bastion of modern PHP and everything that entails.  Both good and bad.&lt;/p&gt;

&lt;p&gt;Kohana is dead.  Yii, all but dead.  Etc.&lt;/p&gt;

&lt;p&gt;On the plus side.  Micro-frameworks have become a ton more popular, Slim and Silex are great tools that I absolutely love.  I use Slim almost every day.&lt;/p&gt;

&lt;p&gt;The problem with micro-frameworks is that they force you to practically design your own framework from smaller pieces.  This can be great for an experienced developer or team.  This is absolutely horrible for a new developer or trying to onboard new developers to a large project or simply for getting a project off the ground.  I can’t tell you how many times I’ve had an idea for a new app but by the time I picked out all the tools to use and setup the project architecture I was tired of the project and abandoned it.&lt;/p&gt;

&lt;p&gt;That’s why I’m really excited about this next version of CodeIgniter.  It gives you the simple MVC architecture you’re used to.  Basic routing.  Real classes without the wild loading things old CI used to do.  PSR-4 autoloading.  Tests.  A full stack, end to end framework, that you can download and immediately see work in your browser.  You can edit two files to serve up a static site.  Three files to add a new model/view/controller that serve an app.&lt;/p&gt;

&lt;p&gt;I have nothing against the other frameworks mentioned.  I’m a big fan of them for the right projects and will continue using them.  I’m also really excited for CodeIgniter 4.  It gives a new developer a great place to start.  It gives me a way to get a new app shipped without worrying about what the newest routing library is or how I would architecture at the scale of Facebook.  It gives an experienced team an amazing starting place to create an app that’ll be used by tons of users and that they’ll enjoy working with.  It’ll get out of your way and let you code.&lt;/p&gt;

&lt;p&gt;You can check out the current process on Github at &lt;a href=&quot;https://github.com/bcit-ci/CodeIgniter4&quot; target=&quot;_blank&quot;&gt;https://github.com/bcit-ci/CodeIgniter4&lt;/a&gt;.  It’d be awesome if you could contribute.&lt;/p&gt;

&lt;p&gt;Hit me up on &lt;a href=&quot;http://twitter.com/benedmunds&quot; target=&quot;_blank&quot;&gt;Twitter&lt;/a&gt;, I’d love to hear your thoughts.&lt;/p&gt;
</description>
				<pubDate>Tue, 08 Aug 2017 00:00:00 +0000</pubDate>
				<link>http://benedmunds.com/php/2017/08/08/codeigniter-4-overview</link>
				<guid isPermaLink="true">http://benedmunds.com/php/2017/08/08/codeigniter-4-overview</guid>
			</item>
		
			<item>
				<title>CodeIgniter Lives On</title>
				<description>
&lt;p&gt;I’m sure most of you know that at one time I was heavily involved in the CodeIgniter framework but have not been in quite some time.  CodeIgniter stagnated and other frameworks moved in to take it’s place.  Namely Slim and Laravel.  EllisLab, the company behind CodeIgniter, had lost interest in maintaining the project a long time before they finally annouced that they were &lt;a href=&quot;https://ellislab.com/blog/entry/ellislab-seeking-new-owner-for-codeigniter&quot;&gt;looking for a new owner for the framework in July 2013&lt;/a&gt;.  Luckily for us all, it was recently annouced that the &lt;a href=&quot;http://www.bcit.ca/cas/computing/&quot;&gt;British Columbia Institute of Technology&lt;/a&gt; has taken over as the new owner.&lt;/p&gt;

&lt;p&gt;With this new owner comes new leadership and a new vision for the future of CodeIgniter.  CI will continue to focus on being a simple, lightweight, yet relevant framework for modern PHP developers going forward.  It will be community focused and driven by open source.  I have joined on to advise on the future direction of the framework as a member of the &lt;a href=&quot;http://www.codeigniter.com/help/about&quot;&gt;CodeIgniter Counsel&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;I personally still use CodeIgniter in many legacy applications day to day and am very excited that it will continue to be a valid option going forward.  Together we can shape CI to be the framework we all wish it was.&lt;/p&gt;

&lt;p&gt;I also want to clarify.  This does not mean that I’ll stop using Slim, Laravel, Express, etc as needed.  I’m a firm believer in using the best tool for the job and will definitely be using CodeIgniter when it’s the right fit.  I can’t stress enough how important it is to take a step back when you’re planning a new project and choice the best framework/components/whatever for your needs.  Now go make cool shit!&lt;/p&gt;
</description>
				<pubDate>Tue, 04 Nov 2014 00:00:00 +0000</pubDate>
				<link>http://benedmunds.com/php/2014/11/04/codeigniter-lives-on</link>
				<guid isPermaLink="true">http://benedmunds.com/php/2014/11/04/codeigniter-lives-on</guid>
			</item>
		
			<item>
				<title>Fixing Homebrew PHP / Apache after Yosemite</title>
				<description>
&lt;p&gt;Today I upgraded to Yosemite.  Played with all the new cool shit.  Then tried to get some work done, broken.  Everything.  Broken.&lt;/p&gt;

&lt;p&gt;To explain a bit, Apache wasn’t loading so http://localhost wasn’t loading, let’s walk through the steps I took to fix this in case you’re seeing the same issue.&lt;/p&gt;

&lt;h3 id=&quot;php&quot;&gt;PHP&lt;/h3&gt;
&lt;p&gt;First we’ll need to reinstall PHP.  Start by running brew update and brew doctor, fix what they recommend:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;$ brew update
$ brew doctor
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Now for the reinstall, use whatever PHP version and flags you originally installed with.  For this example we’ll be doing PHP 5.3 with MySQL and Postgres&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;$ brew reinstall php53 --with-mysql --with-pgsql --with-apache
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;At the end of the install process brew will tell you a few commands to run and give you the path to the PHP module.  So let’s set PHP 5.3 to load at startup and load it right damn now&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;$ ln -sfv /usr/local/opt/php53/*.plist ~/Library/LaunchAgents
$ launchctl load ~/Library/LaunchAgents/homebrew.mxcl.php53.plist
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;In the output we can see that the LoadModule line for the libphp5.so is&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;LoadModule php5_module    /usr/local/opt/php53/libexec/apache2/libphp5.so
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Go ahead and make a note of that LoadModule line.&lt;/p&gt;

&lt;h3 id=&quot;apache&quot;&gt;Apache&lt;/h3&gt;
&lt;p&gt;If you’re using OSX Apache your httpd.conf has been backed up and a new one is now in place, this will show you all of the files:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;$ ls /private/etc/apache2
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;You should see a httpd.conf and a httpd.conf.pre-update or something similar.  The pre-update is your old config, you can find your old paths and any special configs/settings here.  I’m assuming you already know the basics of setting up an Apache server.&lt;/p&gt;

&lt;p&gt;Now we’re going to update the new httpd.conf with our particular settings, most of which you can grab from the .pre-update file.&lt;/p&gt;

&lt;p&gt;Open /private/etc/apache2/httpd.conf in your editor of choice.  Update the ServerRoot, DocumentRoot, and any Directory definitions as needed (1), you should be able to copy these from your httpd.conf.pre-update file.&lt;/p&gt;

&lt;p&gt;Comment out any existing “LoadModule …. libphp5.so” lines.&lt;/p&gt;

&lt;p&gt;At the bottom of the file add the LoadModule line from earlier (2)&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;LoadModule php5_module /usr/local/lib/libphp5.so
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Restart apache&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;$ sudo apachectl -k restart
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Hopefully everything will be good to go now.  Watch the output from the apache restart for errors that will help you track down any additional issues.&lt;/p&gt;

&lt;hr /&gt;
&lt;p&gt;(1) - My previous SystemRoot didn’t work, I had to use&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;SystemRoot &quot;/usr&quot;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;hr /&gt;
&lt;p&gt;(2) - I also had to add&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;AddType application/x-httpd-php .php
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;&lt;br /&gt;&lt;br /&gt;&lt;/p&gt;
</description>
				<pubDate>Thu, 16 Oct 2014 00:00:00 +0000</pubDate>
				<link>http://benedmunds.com/php/2014/10/16/fixing-homebrew-php-apache-after-yosemite</link>
				<guid isPermaLink="true">http://benedmunds.com/php/2014/10/16/fixing-homebrew-php-apache-after-yosemite</guid>
			</item>
		
			<item>
				<title>Book Review - Integrating Frontend Components with Web Applications</title>
				<description>
&lt;p&gt;I recently had the pleasure of receiving an early copy of Integrating Frontend Components with Web Applications by Maks Surguy.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://s3.amazonaws.com/titlepages.leanpub.com/frontend/large?1396807871&quot; width=&quot;200&quot; style=&quot;margin-left:0;&quot; /&gt;&lt;/p&gt;

&lt;h3 id=&quot;whats-it-cover&quot;&gt;What’s it cover&lt;/h3&gt;
&lt;p&gt;This book has excellent content explained in a thorough, yet really engaging manner.  It covers a wide array of common frontend components including&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Integrating Twitter Bootstrap&lt;/li&gt;
  &lt;li&gt;Tagging&lt;/li&gt;
  &lt;li&gt;Notifications and Alerts&lt;/li&gt;
  &lt;li&gt;Spinners&lt;/li&gt;
  &lt;li&gt;Auto-Completing Search&lt;/li&gt;
  &lt;li&gt;AJAX Login and Registration&lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;AJAX file Uploads&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;Avatar Cropping&lt;/li&gt;
  &lt;li&gt;Date Pickers&lt;/li&gt;
&lt;/ul&gt;

&lt;h3 id=&quot;thoughts&quot;&gt;Thoughts&lt;/h3&gt;
&lt;p&gt;I really enjoyed reading this book.  I have been doing a large amount for frontend work for years now and I even learned several things from this book.  I especially liked that Maks made no assumptions as to the existing knowledge of the reader.  Junior all the way through Senior developers will find something for them in this material.&lt;/p&gt;

&lt;p&gt;The diagrams and visuals throughout really distinguish this book IMHO.  I would be surprised if there are any concepts covered that someone isn’t able to easily follow and understand.  It’s hard to even express how clear and concise things are conveyed here, &lt;a href=&quot;https://leanpub.com/frontend&quot;&gt;check out the sample chapter on Leanpub&lt;/a&gt; to see what I mean.&lt;/p&gt;

&lt;p&gt;BTW - I’ve never seen &lt;a href=&quot;http://parsleyjs.org/&quot;&gt;Parsley&lt;/a&gt; before and it looks like a kick ass validation library.  I’ll definitely be using this in future projects.&lt;/p&gt;

&lt;h3 id=&quot;criticisms&quot;&gt;Criticisms&lt;/h3&gt;
&lt;p&gt;My only criticism is the reliance on Laravel and jQuery for many of the examples.  I completely understand the constraints an author is under though, you have to keep the examples succinct while still getting the point across, so overall I think Maks found a great balance between generalities and specifics.&lt;/p&gt;

&lt;h3 id=&quot;recommend-or-hate&quot;&gt;Recommend or Hate?&lt;/h3&gt;
&lt;p&gt;I totally &lt;em&gt;recommend&lt;/em&gt; this book without any reservations.  This is money well spent.  You’ll learn a ton.&lt;/p&gt;

&lt;p&gt;I’ll be personally recommending this to anyone that is starting to learn frontend development, or hell, even just someone that wants a guidebook on how to handle the most commonly asked for frontend components.&lt;/p&gt;

&lt;h3 id=&quot;want-it&quot;&gt;Want it?&lt;/h3&gt;
&lt;p&gt;You can purchase the book through Leanpub: &lt;a href=&quot;https://leanpub.com/frontend&quot;&gt;Buy it here&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;The price is discounted to $19.99 through July 23rd, after that it goes it goes up to $29.99 so grab it now to save a good bit.&lt;/p&gt;

&lt;p&gt;&lt;br /&gt;&lt;br /&gt;&lt;/p&gt;
</description>
				<pubDate>Wed, 16 Jul 2014 00:00:00 +0000</pubDate>
				<link>http://benedmunds.com/javascript/2014/07/16/integrating-frontend-components-book-review</link>
				<guid isPermaLink="true">http://benedmunds.com/javascript/2014/07/16/integrating-frontend-components-book-review</guid>
			</item>
		
			<item>
				<title>Advanced CSRF Usage in PHP</title>
				<description>
&lt;p&gt;This expands on my post, &lt;a href=&quot;/php/2014/04/29/csrf-in-php/&quot; target=&quot;_blank&quot;&gt;Securing against Cross Site Request Forgery (CSRF) exploits in PHP&lt;/a&gt;.  In the previous post we discussed the basics of how to protect against CSRF exploits.  I recommend reading that if you haven’t yet.  Now let’s cover a more advanced use case.&lt;/p&gt;

&lt;h3 id=&quot;multiple-csrf-tokens&quot;&gt;Multiple CSRF Tokens&lt;/h3&gt;
&lt;p&gt;The previous solution only covered basic, one time use protection but what if you need to allow users to use multiple tabs or protect AJAX calls in addition to regular ol’ forms. You don’t want a user’s form token to expire simply because an AJAX call fired off in the background.&lt;/p&gt;

&lt;p&gt;The solution is to support multiple CSRF tokens at once.&lt;/p&gt;

&lt;p&gt;Here was our old code to generate a token&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-javascript&quot; data-lang=&quot;javascript&quot;&gt;&lt;table class=&quot;rouge-table&quot;&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td class=&quot;gutter gl&quot;&gt;&lt;pre class=&quot;lineno&quot;&gt;1
2
3
4
5
6
7
8
9
10
11
12
&lt;/pre&gt;&lt;/td&gt;&lt;td class=&quot;code&quot;&gt;&lt;pre&gt;	&lt;span class=&quot;c1&quot;&gt;//assuming the rest of the form class here&lt;/span&gt;

	&lt;span class=&quot;kd&quot;&gt;static&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;generateCsrf&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;

	  &lt;span class=&quot;nx&quot;&gt;$token&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;mcrypt_create_iv&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;16&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;MCRYPT_DEV_URANDOM&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;

	  &lt;span class=&quot;nl&quot;&gt;Session&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;flash&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;csrfToken&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;$token&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;


	  &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;$token&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
	&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
	
&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;&lt;br clear=&quot;both&quot; /&gt;&lt;/p&gt;

&lt;p&gt;and here is our new function&lt;/p&gt;

&lt;p&gt;&lt;br clear=&quot;both&quot; /&gt;&lt;br clear=&quot;both&quot; /&gt;&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-javascript&quot; data-lang=&quot;javascript&quot;&gt;&lt;table class=&quot;rouge-table&quot;&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td class=&quot;gutter gl&quot;&gt;&lt;pre class=&quot;lineno&quot;&gt;1
2
3
4
5
6
7
8
9
10
11
&lt;/pre&gt;&lt;/td&gt;&lt;td class=&quot;code&quot;&gt;&lt;pre&gt;&lt;span class=&quot;c1&quot;&gt;//assuming the rest of the form class here&lt;/span&gt;

	&lt;span class=&quot;kd&quot;&gt;static&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;generateCsrf&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;

	  &lt;span class=&quot;nx&quot;&gt;$token&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;mcrypt_create_iv&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;16&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;MCRYPT_DEV_URANDOM&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;

	  &lt;span class=&quot;nx&quot;&gt;$_SESSION&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;csrfTokens&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;][&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;$token&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;time&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;();&lt;/span&gt;

	  &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;$token&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
	&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
	
&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;&lt;br clear=&quot;both&quot; /&gt;&lt;/p&gt;

&lt;p&gt;What this does is instead of storing the token as the value we are storing an array of tokens and then their corresponding creation timestamps.  The previous example used the Laravel Session class but in this example I’m using standard PHP session handling since I don’t want this to be confusing.&lt;/p&gt;

&lt;p&gt;&lt;br clear=&quot;both&quot; /&gt;&lt;br clear=&quot;both&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Now the validation of the CSRF tokens looks like this&lt;/p&gt;

&lt;p&gt;&lt;br clear=&quot;both&quot; /&gt;&lt;br clear=&quot;both&quot; /&gt;&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-javascript&quot; data-lang=&quot;javascript&quot;&gt;&lt;table class=&quot;rouge-table&quot;&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td class=&quot;gutter gl&quot;&gt;&lt;pre class=&quot;lineno&quot;&gt;1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
&lt;/pre&gt;&lt;/td&gt;&lt;td class=&quot;code&quot;&gt;&lt;pre&gt;&lt;span class=&quot;nx&quot;&gt;Route&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;post&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;/signup&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;function&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(){&lt;/span&gt;

	  &lt;span class=&quot;c1&quot;&gt;//this would probably be abstracted away into&lt;/span&gt;
	  &lt;span class=&quot;c1&quot;&gt;//a route filter or your form validation&lt;/span&gt;

	  &lt;span class=&quot;c1&quot;&gt;//here we are setting our expiration timestamp&lt;/span&gt;
	  &lt;span class=&quot;c1&quot;&gt;//to 1 day ago&lt;/span&gt;
	  &lt;span class=&quot;nx&quot;&gt;$expiration&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;time&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;86400&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;//86400 is the number of seconds in 24 hours&lt;/span&gt;

	  &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;
	  	  &lt;span class=&quot;nx&quot;&gt;isset&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;$_SESSION&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;csrfTokens&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;][&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;$_POST&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;token&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]])&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;amp;&amp;amp;&lt;/span&gt;
	  	  &lt;span class=&quot;nx&quot;&gt;$_SESSION&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;csrfTokens&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;][&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;$_POST&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;token&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;gt;=&lt;/span&gt;  &lt;span class=&quot;nx&quot;&gt;$expiration&lt;/span&gt;
	  &lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;

		&lt;span class=&quot;c1&quot;&gt;//process the form&lt;/span&gt;

	  &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;


	  &lt;span class=&quot;c1&quot;&gt;//like earlier, you should add a&lt;/span&gt;
	  &lt;span class=&quot;c1&quot;&gt;//legit error message here&lt;/span&gt;
	  &lt;span class=&quot;nx&quot;&gt;die&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;Invalid Form Data&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;

	&lt;span class=&quot;p&quot;&gt;});&lt;/span&gt;
	
&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;This new function not only checks that the token exists but also checks that it hasn’t expired.&lt;/p&gt;

&lt;p&gt;&lt;br clear=&quot;both&quot; /&gt;&lt;br clear=&quot;both&quot; /&gt;&lt;br clear=&quot;both&quot; /&gt;&lt;/p&gt;

&lt;h3&gt;Garbage Collection&lt;/h3&gt;

&lt;p&gt;You really should use a Session class to wrap these calls to the $_SESSION data and then write a garage collection routine to clear expired tokens.  Here is an example&lt;/p&gt;

&lt;p&gt;&lt;br clear=&quot;both&quot; /&gt;&lt;br clear=&quot;both&quot; /&gt;&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-javascript&quot; data-lang=&quot;javascript&quot;&gt;&lt;table class=&quot;rouge-table&quot;&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td class=&quot;gutter gl&quot;&gt;&lt;pre class=&quot;lineno&quot;&gt;1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
&lt;/pre&gt;&lt;/td&gt;&lt;td class=&quot;code&quot;&gt;&lt;pre&gt;&lt;span class=&quot;kd&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;Session&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
		&lt;span class=&quot;kd&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;validateCSRFToken&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;$token&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;

			&lt;span class=&quot;nx&quot;&gt;$this&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;garbageCollectCsrfTokens&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;();&lt;/span&gt;

			&lt;span class=&quot;c1&quot;&gt;//if it is a validate token clear it&lt;/span&gt;
			&lt;span class=&quot;c1&quot;&gt;//and then return true&lt;/span&gt;
			&lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;isset&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;$_SESSION&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;csrfTokens&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;][&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;$_POST&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;token&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]])&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;===&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;TRUE&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
				&lt;span class=&quot;nx&quot;&gt;unset&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;$_SESSION&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;csrfTokens&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;][&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;$_POST&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;token&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]]);&lt;/span&gt;
				&lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;TRUE&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
			&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

			&lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;FALSE&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;

		&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

		&lt;span class=&quot;kd&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;garbageCollectCsrfTokens&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;

			&lt;span class=&quot;c1&quot;&gt;//here we are setting our expiration timestamp&lt;/span&gt;
			&lt;span class=&quot;c1&quot;&gt;//to 1 day ago&lt;/span&gt;
			&lt;span class=&quot;c1&quot;&gt;//this has been hardcoded here for simplicity&lt;/span&gt;
			&lt;span class=&quot;nx&quot;&gt;$expiration&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;time&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;86400&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;//86400 is the # of seconds in 24 hours&lt;/span&gt;

			&lt;span class=&quot;nx&quot;&gt;foreach&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;$_SESSION&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;csrfTokens&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;as&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;$k&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;$time&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;

				&lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;$time&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;$expiration&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
					&lt;span class=&quot;c1&quot;&gt;//unset since it&apos;s expired&lt;/span&gt;
					&lt;span class=&quot;nx&quot;&gt;unset&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;$_SESSION&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;csrfTokens&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;][&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;$k&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]);&lt;/span&gt;
				&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

			&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

		&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
	&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
	
&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;&lt;br clear=&quot;both&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Everytime the token is evaluated a garabage collection routine will be ran against all the tokens.  The route logic to check the tokens has now been simplified to this&lt;/p&gt;

&lt;p&gt;&lt;br clear=&quot;both&quot; /&gt;&lt;br clear=&quot;both&quot; /&gt;&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-javascript&quot; data-lang=&quot;javascript&quot;&gt;&lt;table class=&quot;rouge-table&quot;&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td class=&quot;gutter gl&quot;&gt;&lt;pre class=&quot;lineno&quot;&gt;1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
&lt;/pre&gt;&lt;/td&gt;&lt;td class=&quot;code&quot;&gt;&lt;pre&gt;&lt;span class=&quot;nx&quot;&gt;Route&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;post&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;/signup&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;function&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;Session&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;$session&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;){&lt;/span&gt;

	  &lt;span class=&quot;c1&quot;&gt;//this would probably be abstracted away into&lt;/span&gt;
	  &lt;span class=&quot;c1&quot;&gt;//a route filter or your form validation&lt;/span&gt;

	  &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;$session&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;validateCSRFToken&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;$_POST&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;token&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;])&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;===&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;TRUE&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;

		&lt;span class=&quot;c1&quot;&gt;//process the form&lt;/span&gt;

	  &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;


	  &lt;span class=&quot;c1&quot;&gt;//like earlier, you should add a&lt;/span&gt;
	  &lt;span class=&quot;c1&quot;&gt;//legit error message here&lt;/span&gt;
	  &lt;span class=&quot;nx&quot;&gt;die&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;Invalid Form Data&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;

	&lt;span class=&quot;p&quot;&gt;});&lt;/span&gt;
	
&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;&lt;br clear=&quot;both&quot; /&gt;&lt;br clear=&quot;both&quot; /&gt;&lt;/p&gt;

&lt;p&gt;You will now be able to use multiple CSRF tokens at once in the same user session.  Plus have the added protection of expiring tokens.&lt;/p&gt;

&lt;p&gt;&lt;br clear=&quot;both&quot; /&gt;&lt;br clear=&quot;both&quot; /&gt;&lt;br clear=&quot;both&quot; /&gt;&lt;/p&gt;

&lt;h3 class=&quot;centered&quot;&gt;Want to Learn More about PHP Security?&lt;/h3&gt;
&lt;div class=&quot;book_image_container post&quot;&gt;
    &lt;a href=&quot;https://leanpub.com/buildingsecurephpapps&quot; target=&quot;_blank&quot;&gt;&lt;img src=&quot;https://images.springer.com/sgw/books/medium/9781484221198.jpg&quot; class=&quot;book_image&quot; style=&quot;margin-top:0.2em;&quot; /&gt;&lt;/a&gt;
&lt;/div&gt;

&lt;div style=&quot;text-align:center; width:70%; margin:0 auto;&quot;&gt;
	This builds upon topics discussed in my book, &lt;a href=&quot;http://securingphpapps.com&quot; target=&quot;_blank&quot;&gt;Building Secure PHP Apps&lt;/a&gt;.  If you want to learn a ton more, some might even call it a metric fuck-ton, about writing secure PHP code then stop what you&apos;re doing and &lt;br /&gt;
	&lt;a href=&quot;http://securingphpapps.com&quot; target=&quot;_blank&quot; class=&quot;small_book_buy_btn&quot;&gt;Buy the Book&lt;/a&gt;
&lt;/div&gt;

&lt;p&gt;&lt;br clear=&quot;both&quot; /&gt;&lt;/p&gt;
</description>
				<pubDate>Sun, 11 May 2014 00:00:00 +0000</pubDate>
				<link>http://benedmunds.com/php/2014/05/11/advanced-csrf-usage-in-php</link>
				<guid isPermaLink="true">http://benedmunds.com/php/2014/05/11/advanced-csrf-usage-in-php</guid>
			</item>
		
			<item>
				<title>Securing against Cross Site Request Forgery (CSRF) exploits in PHP</title>
				<description>
&lt;p&gt;Cross Site Request Forgery (CSRF) is basically the opposite of an XSS exploit.  Where XSS takes advantage of the user by means of a trusted web site, CSRF takes advantage of the web site by means of a trusted user.&lt;/p&gt;

&lt;p&gt;An example of this is an attacker sending out fake emails with a link to delete a blog post, an email, whatever.  The target user then clicks this and is taken to a delete page.  Since the user is an administrator of this site, and they have a valid session, your web application goes ahead and deletes the record as requested.  The user had no idea that’s what the link was taking them to and now their account has been deleted without their consent.  Not cool.&lt;/p&gt;

&lt;p&gt;This doesn’t have to be a text link either, it is often attached to an image or a button.  This might sound like a small risk since most critical web site functions are behind forms that require POSTed data but this can just as easily be expanded upon to use a button or JavaScript to submit hidden forms.&lt;/p&gt;

&lt;p&gt;&lt;br clear=&quot;both&quot; /&gt;&lt;/p&gt;

&lt;h3 id=&quot;how-to-protect-against-it&quot;&gt;How to protect against it&lt;/h3&gt;
&lt;p&gt;The first step is to ensure that no data altering actions are preformed by GET requests.  Anything that performs an action on data requires a PUT, POST or DELETE request.  A basic example of this is any insert, update or delete preformed on your database should be behind a POST form request.  If the user clicks a delete button they should then be taken to a form where they submit this to verify the action.  If data altering actions need to be preformed over GET, maybe for a RESTful API, then simply require a unique token in the query string, exactly how we will discuss it being in the hidden form data in the following examples.&lt;/p&gt;

&lt;p&gt;Now that you are submitting forms for your data manipulations we will need to add CSRF tokens to our forms.  Our CSRF token will be a standard Nonce (Number used Once).  To do this we will generate a random token, store it in the user’s session, then add it as a hidden field to our form.  Once this form is POSTed we can check the POSTed CSRF token against the one in the session.&lt;/p&gt;

&lt;p&gt;First we’ll create a function to generate the token.  This will usually be placed in a universally callable place, maybe as a route filter, voter, or a helper library.&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-javascript&quot; data-lang=&quot;javascript&quot;&gt;&lt;table class=&quot;rouge-table&quot;&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td class=&quot;gutter gl&quot;&gt;&lt;pre class=&quot;lineno&quot;&gt;1
2
3
4
5
6
7
8
9
10
11
12
&lt;/pre&gt;&lt;/td&gt;&lt;td class=&quot;code&quot;&gt;&lt;pre&gt;	&lt;span class=&quot;c1&quot;&gt;//assuming the rest of the form class here&lt;/span&gt;

	&lt;span class=&quot;kd&quot;&gt;static&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;generateCsrf&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;

	  &lt;span class=&quot;nx&quot;&gt;$token&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;mcrypt_create_iv&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;16&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;MCRYPT_DEV_URANDOM&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;

	  &lt;span class=&quot;nl&quot;&gt;Session&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;flash&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;csrfToken&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;$token&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;


	  &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;$token&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
	&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
	
&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;Note that we are using session flashdata here.  This is supported concept in most session wrapping classes.  Flashdata will be stored to the session but can only be accessed on one request and then it is destroyed.  This keeps our token from being validate for more than this one request.&lt;/p&gt;

&lt;p&gt;Next we’ll call this from our route and pass the token to the view that is generating the form&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-javascript&quot; data-lang=&quot;javascript&quot;&gt;&lt;table class=&quot;rouge-table&quot;&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td class=&quot;gutter gl&quot;&gt;&lt;pre class=&quot;lineno&quot;&gt;1
2
3
4
5
6
7
8
9
&lt;/pre&gt;&lt;/td&gt;&lt;td class=&quot;code&quot;&gt;&lt;pre&gt;	&lt;span class=&quot;nx&quot;&gt;Route&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;kd&quot;&gt;get&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;/signup&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;function&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(){&lt;/span&gt;

	  &lt;span class=&quot;nx&quot;&gt;$data&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;token&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;Form&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;generateCsrf&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;();&lt;/span&gt;


	  &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;View&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;render&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;signup.form&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;$data&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;

	&lt;span class=&quot;p&quot;&gt;});&lt;/span&gt;
	
&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;And now for our view, “signup/form.php”&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-javascript&quot; data-lang=&quot;javascript&quot;&gt;&lt;table class=&quot;rouge-table&quot;&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td class=&quot;gutter gl&quot;&gt;&lt;pre class=&quot;lineno&quot;&gt;1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
&lt;/pre&gt;&lt;/td&gt;&lt;td class=&quot;code&quot;&gt;&lt;pre&gt;	&lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;form&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;method&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;POST&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;action&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;/signup&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt;

	  &lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;label&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt;
		&lt;span class=&quot;nx&quot;&gt;First&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;Name&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;
		&lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;input&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;type&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;text&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;first_name&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;/&amp;gt;&lt;/span&gt;
	  &lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;sr&quot;&gt;/label&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;&amp;gt;
&lt;/span&gt;
	  &lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;label&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt;
		&lt;span class=&quot;nx&quot;&gt;Last&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;Name&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;
		&lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;input&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;type&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;text&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;last_name&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;/&amp;gt;&lt;/span&gt;
	  &lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;sr&quot;&gt;/label&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;&amp;gt;
&lt;/span&gt;
	  &lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;label&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt;
		&lt;span class=&quot;nx&quot;&gt;Email&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;
		&lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;input&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;type&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;text&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;email&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;/&amp;gt;&lt;/span&gt;
	  &lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;sr&quot;&gt;/label&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;&amp;gt;
&lt;/span&gt;

	  &lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;input&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;type&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;hidden&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;token&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;value&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&amp;lt;?=$token?&amp;gt;&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;/&amp;gt;&lt;/span&gt;

	  &lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;input&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;type&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;submit&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;submit&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;value&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;Signup&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;/&amp;gt;&lt;/span&gt;

	&lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;sr&quot;&gt;/form&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;&amp;gt;
&lt;/span&gt;	
&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;When this form is POSTed we can now verify that the token is valid&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-javascript&quot; data-lang=&quot;javascript&quot;&gt;&lt;table class=&quot;rouge-table&quot;&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td class=&quot;gutter gl&quot;&gt;&lt;pre class=&quot;lineno&quot;&gt;1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
&lt;/pre&gt;&lt;/td&gt;&lt;td class=&quot;code&quot;&gt;&lt;pre&gt;	&lt;span class=&quot;nx&quot;&gt;Route&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;post&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;/signup&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;function&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(){&lt;/span&gt;

	  &lt;span class=&quot;c1&quot;&gt;//this would probably be abstracted away into&lt;/span&gt;
	  &lt;span class=&quot;c1&quot;&gt;//a route filter or your form validation&lt;/span&gt;
	  &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;$_POST&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;token&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;===&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;Session&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;kd&quot;&gt;get&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;csrfToken&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;

		&lt;span class=&quot;c1&quot;&gt;//process the form&lt;/span&gt;

	  &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;


	  &lt;span class=&quot;c1&quot;&gt;//like earlier, you should add a&lt;/span&gt;
	  &lt;span class=&quot;c1&quot;&gt;//legit error message here&lt;/span&gt;
	  &lt;span class=&quot;nx&quot;&gt;die&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;Invalid Form Data&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;

	&lt;span class=&quot;p&quot;&gt;});&lt;/span&gt;
	
&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;Now that this token checking is in place even if an attacker tricks a user into submitting a fake form they won’t have a matching CSRF token in their session data for your website so the request will fail.&lt;/p&gt;

&lt;p&gt;&lt;br clear=&quot;both&quot; /&gt;&lt;br clear=&quot;both&quot; /&gt;&lt;br clear=&quot;both&quot; /&gt;&lt;/p&gt;

&lt;h3 class=&quot;centered&quot;&gt;Want to Learn More about PHP Security?&lt;/h3&gt;
&lt;div class=&quot;book_image_container post&quot;&gt;
    &lt;a href=&quot;https://leanpub.com/buildingsecurephpapps&quot; target=&quot;_blank&quot;&gt;&lt;img src=&quot;https://images.springer.com/sgw/books/medium/9781484221198.jpg&quot; class=&quot;book_image&quot; style=&quot;margin-top:0.2em;&quot; /&gt;&lt;/a&gt;
&lt;/div&gt;
&lt;div style=&quot;text-align:center; width:70%; margin:0 auto;&quot;&gt;
	This is an excerpt from my book, &lt;a href=&quot;http://securingphpapps.com&quot; target=&quot;_blank&quot;&gt;Securing PHP Apps&lt;/a&gt;.  If you want to learn a ton more, some might even call it a metric fuck-ton, about writing secure PHP code then stop what you&apos;re doing and &lt;br /&gt;
	&lt;a href=&quot;http://securingphpapps.com&quot; target=&quot;_blank&quot; class=&quot;small_book_buy_btn&quot;&gt;Buy the Book&lt;/a&gt;
&lt;/div&gt;

&lt;p&gt;&lt;br clear=&quot;both&quot; /&gt;&lt;/p&gt;
</description>
				<pubDate>Tue, 29 Apr 2014 00:00:00 +0000</pubDate>
				<link>http://benedmunds.com/php/2014/04/29/csrf-in-php</link>
				<guid isPermaLink="true">http://benedmunds.com/php/2014/04/29/csrf-in-php</guid>
			</item>
		
			<item>
				<title>Building Secure PHP Apps - Early Release</title>
				<description>
&lt;p&gt;Hey, sorry for taking like six months since my last blog post.  I missed you, promise.  BTW, have I mentioned how awesome you are?&lt;/p&gt;

&lt;p&gt;I’m breaking my silence / severe writing laziness to annouce that I’m opening my ebook, Building Secure PHP Apps, for early access.  It’s for sale on Leanpub right now.  Currently at about 40% complete and writing around one chapter every one to two weeks so it will be done soon.&lt;/p&gt;

&lt;p&gt;If you’ve ever wished you knew more about security, HTTPS, password encryption, etc then this should be a good guide for you.  Also if you’ve ever used my &lt;em&gt;Ion Auth&lt;/em&gt; library for CodeIgniter I suggest you check this out so you can implement good security practices in future PHP apps.&lt;/p&gt;

&lt;p&gt;Over the years I’ve learned a lot about security and am really passionate about it.  I want to help people keep their site and their users safe without having to learn it the hard way.&lt;/p&gt;

&lt;p&gt;Anyway, if you’re interested you can learn more and buy it here:&lt;/p&gt;

&lt;p&gt;     &lt;a href=&quot;http://securingphpapps.com&quot; target=&quot;_blank&quot; style=&quot;&quot; class=&quot;book_buy_btn&quot;&gt;Securing PHP Apps&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;br /&gt;
&lt;br /&gt;&lt;/p&gt;
</description>
				<pubDate>Thu, 06 Feb 2014 00:00:00 +0000</pubDate>
				<link>http://benedmunds.com/php/2014/02/06/building-secure-php-apps-ebook-early-release</link>
				<guid isPermaLink="true">http://benedmunds.com/php/2014/02/06/building-secure-php-apps-ebook-early-release</guid>
			</item>
		
			<item>
				<title>My New Motto</title>
				<description>
&lt;p&gt;The product is the current product, the culture is the next hundred products.&lt;br /&gt;&lt;/p&gt;
&lt;ul&gt;
  &lt;li&gt;Phil Libin
&lt;br /&gt;
&lt;br /&gt;&lt;/li&gt;
&lt;/ul&gt;
</description>
				<pubDate>Wed, 19 Jun 2013 00:00:00 +0000</pubDate>
				<link>http://benedmunds.com/2013/06/19/best-startup-quote-ever</link>
				<guid isPermaLink="true">http://benedmunds.com/2013/06/19/best-startup-quote-ever</guid>
			</item>
		
			<item>
				<title>Life Hack - Pomodoro</title>
				<description>
&lt;p&gt;I’m always up for a good life hack to improve my productivity so I wanted to share the most recent one I’ve discovered.&lt;/p&gt;

&lt;p&gt;The &lt;a href=&quot;http://en.wikipedia.org/wiki/Pomodoro_Technique&quot; target=&quot;_blank&quot;&gt;Pomodora technique&lt;/a&gt; is a method for time managment and focus.  Most of you have probably heard of it.  The gist of it is that you work hard and focus for 25 minutes and then reward yourself with a 5 minute break.&lt;/p&gt;

&lt;p&gt;At first this might seem like a lot of wasted time with all these breaks but it really is amazing how much these breaks help you concentrate for that 25 minutes of work.  Also, the 5 minute break doesn’t neccesarily have to be wasting time; I try to force myself to only check and respond to emails during the break time, this allows me to focus on coding for 25 minutes, take 5 minutes to handle email and give my brain a break, then jump back into code.&lt;/p&gt;

&lt;p&gt;One tool that has been incredibly valuable to enforce this is &lt;a href=&quot;https://github.com/steveklabnik/pomodoro&quot; target=&quot;_blank&quot;&gt;Pomodoro by Steve Klabnik&lt;/a&gt;.  It’s a simple Ruby script that will redirect time sucking websites except for the 5 minute break periods.  I really recommend you try this out to get the full effect of Pomodoro.&lt;/p&gt;
</description>
				<pubDate>Thu, 01 Nov 2012 00:00:00 +0000</pubDate>
				<link>http://benedmunds.com/2012/11/01/pomodoro</link>
				<guid isPermaLink="true">http://benedmunds.com/2012/11/01/pomodoro</guid>
			</item>
		
			<item>
				<title>Fix PHPUnit using Zend Server CE on OSX</title>
				<description>
&lt;p&gt;Just a simple explanation for anyone else running into this issue getting PHPUnit working with Zend Server CE on OSX Mountain Lion.&lt;/p&gt;

&lt;p&gt;The error:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;PHP Warning:  PHP Startup: Unable to load dynamic library &apos;/usr/local/zend/lib/php_extensions/mcrypt.so&apos; - dlopen(/usr/local/zend/lib/php_extensions/mcrypt.so, 9): Library not loaded: /usr/lib/libltdl.3.dylib
Referenced from: /usr/local/zend/lib/php_extensions/mcrypt.so
Reason: image not found in Unknown on line 0
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;The fix:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;ln -s /usr/local/zend/lib/libltdl.3.dylib /usr/lib/libltdl.3.dylib
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Enjoy!&lt;/p&gt;

&lt;p&gt;&lt;br /&gt;
&lt;br /&gt;&lt;/p&gt;
</description>
				<pubDate>Sun, 19 Aug 2012 00:00:00 +0000</pubDate>
				<link>http://benedmunds.com/php/2012/08/19/fix-phpunit-zend-server-ce-osx</link>
				<guid isPermaLink="true">http://benedmunds.com/php/2012/08/19/fix-phpunit-zend-server-ce-osx</guid>
			</item>
		
			<item>
				<title>Appcelerator JS SDK for Node.js</title>
				<description>
&lt;p&gt;Announcing the release of the Appcelerator ACS JS SDK module for Node.js.  Made by yours truly as the first open source release by &lt;a href=&quot;http://dbltaplabs.com&quot; target=&quot;_blank&quot;&gt;DblTap Labs&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Check out the source on &lt;a href=&quot;http://github.com/DblTapLabs/Node-Appcelerator&quot; target=&quot;_blank&quot;&gt;GitHub&lt;/a&gt; or use it in a project by installing it with npm:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;$ npm install appcelerator
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;&lt;br /&gt;
&lt;br /&gt;&lt;/p&gt;
</description>
				<pubDate>Wed, 25 Jul 2012 00:00:00 +0000</pubDate>
				<link>http://benedmunds.com/node/2012/07/25/appcelerator-sdk-for-node</link>
				<guid isPermaLink="true">http://benedmunds.com/node/2012/07/25/appcelerator-sdk-for-node</guid>
			</item>
		
			<item>
				<title>Ion Auth now supports MongoDB</title>
				<description>
&lt;p&gt;Thanks to the awesome work done by &lt;a href=&quot;http://github.com/sepehr/&quot; target=&quot;_blank&quot;&gt;sepehr&lt;/a&gt;, &lt;a href=&quot;http://github.com/benedmunds/CodeIgniter-Ion-Auth&quot; target=&quot;_blank&quot;&gt;Ion Auth&lt;/a&gt; now supports MongoDB.  Go check it out on &lt;a href=&quot;http://github.com/benedmunds/CodeIgniter-Ion-Auth&quot; target=&quot;_blank&quot;&gt;Github&lt;/a&gt; and let me know any feedback you have.&lt;/p&gt;
</description>
				<pubDate>Mon, 04 Jun 2012 00:00:00 +0000</pubDate>
				<link>http://benedmunds.com/2012/06/04/ion-auth-now-supports-mongodb</link>
				<guid isPermaLink="true">http://benedmunds.com/2012/06/04/ion-auth-now-supports-mongodb</guid>
			</item>
		
			<item>
				<title>Boxcar.io API library for CodeIgniter and bundle for Laravel</title>
				<description>
&lt;p&gt;Announcing the release of the Boxcar.io Provider API PHP SDK for CodeIgniter and Laravel.  This is a simple port of the standard PHP SDK.  Check them out here:&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;http://github.com/benedmunds/CodeIgniter-Boxcar&quot; target=&quot;_blank&quot;&gt;CodeIgniter Library&lt;/a&gt;
&lt;br /&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;http://github.com/benedmunds/Laravel-Boxcar&quot; target=&quot;_blank&quot;&gt;Laravel Bundle&lt;/a&gt;
&lt;br /&gt;&lt;/p&gt;

&lt;p&gt;&lt;br /&gt;
&lt;br /&gt;&lt;/p&gt;
</description>
				<pubDate>Tue, 29 May 2012 00:00:00 +0000</pubDate>
				<link>http://benedmunds.com/php/2012/05/29/boxcario-api-library-for-codeigniter-and-bundle-for-laravel</link>
				<guid isPermaLink="true">http://benedmunds.com/php/2012/05/29/boxcario-api-library-for-codeigniter-and-bundle-for-laravel</guid>
			</item>
		
			<item>
				<title>Last.FM for PyroCMS Released by AppStucco</title>
				<description>
&lt;p&gt;Annoucing the release of the Last.FM module and widget for PyroCMS by &lt;a href=&quot;http://appstucco.com&quot; target=&quot;_blank&quot;&gt;AppStucco&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Go
&lt;a href=&quot;http://appstucco.com/resources/blog/item/3-pyrocms-lastfm-module-released&quot; target=&quot;_blank&quot;&gt;read about it&lt;/a&gt;
on the AppStucco blog, watch the
&lt;a href=&quot;http://appstucco.com/resources/blog/item/3-pyrocms-lastfm-module-released#itemVideoAnchor&quot; target=&quot;_blank&quot;&gt;screencast&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;&lt;/p&gt;
</description>
				<pubDate>Wed, 16 May 2012 00:00:00 +0000</pubDate>
				<link>http://benedmunds.com/php/2012/05/16/appstucco---lastfm-for-pyro-released</link>
				<guid isPermaLink="true">http://benedmunds.com/php/2012/05/16/appstucco---lastfm-for-pyro-released</guid>
			</item>
		
			<item>
				<title>Composer bundle for Laravel</title>
				<description>
&lt;p&gt;Announcing the release of my &lt;a href=&quot;http://github.com/benedmunds/Laravel-Composer&quot; target=&quot;_blank&quot;&gt;Composer bundle for Laravel&lt;/a&gt;.  This bundle will autoload composer packages in your Laravel application.&lt;/p&gt;

&lt;p&gt;Composer packages are a unified way to distribute PHP packages that work with any framework that supports PSR-0 namespacing.  You shouldn’t have to rewrite all of your favorite PHP libraries for each framework you use, that’s where Composer packages come to the rescue.  Find the latest packages at &lt;a href=&quot;http://packagist.org&quot; target=&quot;_blank&quot;&gt;Packagist&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;You can get the bundle here: &lt;a href=&quot;http://github.com/benedmunds/Laravel-Composer&quot; target=&quot;_blank&quot;&gt;Laravel Composer Bundle&lt;/a&gt;
&lt;br /&gt;
&lt;br /&gt;&lt;/p&gt;
</description>
				<pubDate>Tue, 08 May 2012 00:00:00 +0000</pubDate>
				<link>http://benedmunds.com/php/2012/05/08/composer-bundle-for-laravel</link>
				<guid isPermaLink="true">http://benedmunds.com/php/2012/05/08/composer-bundle-for-laravel</guid>
			</item>
		
			<item>
				<title>A Magical CodeIgniter Super Object</title>
				<description>
&lt;p&gt;Recently &lt;a href=&quot;https://github.com/Militis&quot; target=&quot;_blank&quot;&gt;Militis&lt;/a&gt; reminded me of a “trick” to automatically load items from the CodeIgniter super-object.  Of course, you should determine for yourself if this functionality is needed and is worth the performance loss.  We’re now using this in &lt;a href=&quot;http://github.com/benedmunds/CodeIgniter-Ion-Auth&quot; target=&quot;_blank&quot;&gt;Ion Auth&lt;/a&gt; if you want to see it in action.&lt;/p&gt;

&lt;p&gt;Just add the following method to your library class&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;public function __get($var)
{
	return get_instance()-&amp;gt;$var;
}
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;And then you can access and CI items through the $this object like so&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;$this-&amp;gt;load-&amp;gt;library(&apos;email&apos;);
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

</description>
				<pubDate>Mon, 07 May 2012 00:00:00 +0000</pubDate>
				<link>http://benedmunds.com/php/2012/05/07/a-magical-ci-super-object</link>
				<guid isPermaLink="true">http://benedmunds.com/php/2012/05/07/a-magical-ci-super-object</guid>
			</item>
		
			<item>
				<title>AppStucco Launch</title>
				<description>
&lt;p&gt;Last night and today have been extremely exciting as &lt;a href=&quot;http://twitter.com/#!/dan_lopez&quot; target=&quot;_blank&quot;&gt;Dan Lopez&lt;/a&gt; and I have offically launched &lt;a href=&quot;http://appstucco.com&quot; target=&quot;_blank&quot;&gt;AppStucco&lt;/a&gt;!&lt;/p&gt;

&lt;p&gt;We are hitting the ground running with an open source &lt;a href=&quot;http://github.com/appstucco/LDAP-for-PyroCMS&quot; target=&quot;_blank&quot;&gt;LDAP module for PyroCMS&lt;/a&gt; and you can expect to see a few more &lt;a href=&quot;http://pyrocms.com/&quot; target=&quot;_blank&quot;&gt;PyroCMS&lt;/a&gt; modules popping up in the next few weeks.&lt;/p&gt;

&lt;p&gt;Check us out at &lt;a href=&quot;http://appstucco.com&quot; target=&quot;_blank&quot;&gt;AppStucco.com&lt;/a&gt; or read more about the launch on &lt;a href=&quot;http://www.cmscritic.com/appstucco-releases-ldap-for-pyrocms/&quot; target=&quot;_blank&quot;&gt;CMS Critic&lt;/a&gt;.&lt;/p&gt;
</description>
				<pubDate>Tue, 01 May 2012 00:00:00 +0000</pubDate>
				<link>http://benedmunds.com/2012/05/01/launching-appstucco</link>
				<guid isPermaLink="true">http://benedmunds.com/2012/05/01/launching-appstucco</guid>
			</item>
		
			<item>
				<title>Appcelerator PHP SDK for CodeIgniter, Laravel, and vanilla PHP</title>
				<description>
&lt;p&gt;Announcing the release of the Appcelerator ACS PHP SDK for CodeIgniter, Laravel, and plain ol’ PHP.  Made in collaboration with &lt;a href=&quot;http://twitter.com/#!/shealan&quot; target=&quot;_blank&quot;&gt;Shealan Foreshaw&lt;/a&gt; and sponsored by &lt;a href=&quot;http://twitter.com/#!/swipeandtap&quot; target=&quot;_blank&quot;&gt;Swipe &amp;amp; Tap&lt;/a&gt;.  Check it out here:&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;http://github.com/benedmunds/CodeIgniter-Appcelerator&quot; target=&quot;_blank&quot;&gt;CodeIgniter Library&lt;/a&gt;
&lt;br /&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;http://github.com/benedmunds/Laravel-Appcelerator&quot; target=&quot;_blank&quot;&gt;Laravel Bundle&lt;/a&gt;
&lt;br /&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;http://github.com/benedmunds/PHP-Appcelerator&quot; target=&quot;_blank&quot;&gt;PHP SDK&lt;/a&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;&lt;/p&gt;
</description>
				<pubDate>Mon, 30 Apr 2012 00:00:00 +0000</pubDate>
				<link>http://benedmunds.com/php/2012/04/30/appcelerator-php-sdk-for-codeigniter-laravel-and-vanilla-php</link>
				<guid isPermaLink="true">http://benedmunds.com/php/2012/04/30/appcelerator-php-sdk-for-codeigniter-laravel-and-vanilla-php</guid>
			</item>
		
			<item>
				<title>Writing a Nagios plugin with Javascript using Node.js</title>
				<description>
&lt;p&gt;This is pretty much an exact copy of my &lt;a href=&quot;http://benedmunds.com/2012/04/25/writing-a-nagios-plugin-with-php/&quot; target=&quot;_blank&quot;&gt;Writing a Nagios plugin with PHP&lt;/a&gt; post modified for Javascript.  So, here is a quick example of writing a Javascript plugin for Nagios using Node.js.&lt;/p&gt;

&lt;p&gt;Create your JS file named “check_js_test.js” with the following contents&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;process.stdout.write(&apos;This check passed&apos;);
process.exit(0);
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;This will output the “This check passed” string to Nagio with a status code of zero. Of course you will want to customize this to determine your OK and Error states.  The available status codes are&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;0  = OK	or UP
1 = WARNING UP or DOWN/UNREACHABLE
2 = CRITICAL or DOWN/UNREACHABLE
3 = UNKNOWN or DOWN/UNREACHABLE
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Now edit your commands.cfg and add a new command for the PHP plugin we will create&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;define command{
    command_name    check-js-test
    command_line    node /your/path/check_js_test.js
}
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Add a service to execute this command in your host config&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;define service{
    use                             local-service ; Name of service template to use
    host_name                       localhost
    service_description             PHP_ERROR
    check_command                   check-js-test
    check_interval                  5 ; check every 5 minutes (if you havent changed your time units)
    register                        1
    active_checks_enabled           1
    retry_interval                  1 ; retry every minute when in an error state
    max_check_attempts              4 ; test 4 times before deciding the hard state
    contact_groups                  admins ; contact the admin with errors
}
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Restart Nagios and monitor your shit.&lt;/p&gt;
</description>
				<pubDate>Thu, 26 Apr 2012 00:00:00 +0000</pubDate>
				<link>http://benedmunds.com/node/2012/04/26/writing-a-nagios-plugin-with-nodejs</link>
				<guid isPermaLink="true">http://benedmunds.com/node/2012/04/26/writing-a-nagios-plugin-with-nodejs</guid>
			</item>
		
			<item>
				<title>Writing a Nagios plugin with PHP</title>
				<description>
&lt;p&gt;For those of you who don’t know, &lt;a href=&quot;http://www.nagios.org/&quot; target=&quot;_blank&quot;&gt;Nagios&lt;/a&gt; is a simple and powerful monitioring tool.  Nagios can call external commands at set intervals to check for errors and then escalate or alert on the errors.  Here is a quick example of writing a PHP plugin for Nagios.&lt;/p&gt;

&lt;p&gt;Create your PHP file named “check_php_test.php” with the following contents&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;\&amp;lt;?php
	fwrite(STDOUT, &apos;This check passed&apos;);
	exit(0);
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;This will output the “This check passed” string to Nagio with a status code of zero. Of course you will want to customize this to determine your OK and Error states.  The available status codes are&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;0  = OK	or UP
1 = WARNING UP or DOWN/UNREACHABLE
2 = CRITICAL or DOWN/UNREACHABLE
3 = UNKNOWN or DOWN/UNREACHABLE
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Now edit your commands.cfg and add a new command for the PHP plugin we will create&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;define command{
    command_name    check-php-test
    command_line    php /your/path/check_php_test.php
}
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Add a service to execute this command in your host config&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;define service{
    use                             local-service ; Name of service template to use
    host_name                       localhost
    service_description             PHP_ERROR
    check_command                   check-php-test
    check_interval                  5 ; check every 5 minutes (if you havent changed your time units)
    register                        1
    active_checks_enabled           1
    retry_interval                  1 ; retry every minute when in an error state
    max_check_attempts              4 ; test 4 times before deciding the hard state
    contact_groups                  admins ; contact the admin with errors
}
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Restart Nagios and monitor your shit.&lt;/p&gt;
</description>
				<pubDate>Wed, 25 Apr 2012 00:00:00 +0000</pubDate>
				<link>http://benedmunds.com/php/2012/04/25/writing-a-nagios-plugin-with-php</link>
				<guid isPermaLink="true">http://benedmunds.com/php/2012/04/25/writing-a-nagios-plugin-with-php</guid>
			</item>
		
			<item>
				<title>Simple Node.js Express MVR Template</title>
				<description>
&lt;p&gt;In this post we’ll walk through how to setup a simple MVR Node.js project using Express, Mongoose (MongoDB), Jade (templating) and everyauth (authentication).  First off, what the fuck is MVR, think MVC but with routes instead controllers.&lt;/p&gt;

&lt;h3 id=&quot;what-were-going-to-be-using&quot;&gt;What we’re going to be using&lt;/h3&gt;
&lt;ul&gt;
  &lt;li&gt; &lt;a target=&quot;_blank&quot; href=&quot;http://expressjs.com/&quot;&gt;Express&lt;/a&gt; for our framework&lt;/li&gt;
  &lt;li&gt; &lt;a target=&quot;_blank&quot; href=&quot;http://mongoosejs.com/&quot;&gt;Mongoose&lt;/a&gt; for MongoDB&lt;/li&gt;
  &lt;li&gt; &lt;a target=&quot;_blank&quot; href=&quot;http://jade-lang.com/&quot;&gt;Jade&lt;/a&gt; for templating&lt;/li&gt;
  &lt;li&gt; &lt;a target=&quot;_blank&quot; href=&quot;http://everyauth.com/&quot;&gt;everyauth&lt;/a&gt; for authentication&lt;/li&gt;
  &lt;li&gt; &lt;a target=&quot;_blank&quot; href=&quot;http://twitter.github.com/bootstrap/&quot;&gt;Twitter Bootstrap&lt;/a&gt; for styling&lt;/li&gt;
&lt;/ul&gt;

&lt;h3 id=&quot;setup&quot;&gt;Setup&lt;/h3&gt;
&lt;p&gt;You’re going to need Node.JS, NPM, and MongoDB installed.  If you haven’t done that yet see &lt;a target=&quot;_blank&quot; href=&quot;https://github.com/joyent/node/wiki/Installation&quot;&gt;Building and Installing Node.js&lt;/a&gt; and &lt;a target=&quot;_blank&quot; href=&quot;http://www.mongodb.org/display/DOCS/Quickstart&quot;&gt;MongoDB Quickstart&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Open up the command line to create the project&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;$ npm install -g express-generator
$ express examplemvr
$ cd examplemvr
$ rm -rf ./routes
$ rm public/stylesheets/style.css
$ mkdir models
$ npm install
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Now open the mongo console and insert some test data&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;$ mongo nodemvr
$ db.examples.insert({name:&apos;Test Doc&apos;});
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h3 id=&quot;dependencies&quot;&gt;Dependencies&lt;/h3&gt;
&lt;p&gt;Open the examplemvr project in your favorite text editor and edit package.json to match the following&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;package.json
--------------

{
    &quot;name&quot;: &quot;application-name&quot;
  , &quot;version&quot;: &quot;0.0.1&quot;
  , &quot;private&quot;: true
  , &quot;dependencies&quot;: {
      &quot;express&quot;: &quot;2.5.8&quot;
    , &quot;jade&quot;: &quot;&amp;gt;= 0.0.1&quot;
    , &quot;mongodb&quot;: &quot;&amp;gt;= 0.9.6-7&quot;
    , &quot;mongoose&quot;: &quot;&amp;gt;= 2.5.10&quot;
    , &quot;everyauth&quot;: &quot;&amp;gt;=0.2.32&quot;
  },
  &quot;engines&quot;: {
    &quot;node&quot;: &quot;&amp;gt;= 0.6.14&quot;,
    &quot;npm&quot;:  &quot;1.0.x&quot;
  }
}
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;This tells NPM what modules we need and the versions we require.  Now open up the command line again to update your modules with NPM&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;$ npm install
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;This will tell NPM to read the package.json and install any dependencies that are needed.&lt;/p&gt;

&lt;h3 id=&quot;application-core&quot;&gt;Application Core&lt;/h3&gt;
&lt;p&gt;Now open app.js and edit it to match the following&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;/app.js
--------------

var express = require(&apos;express&apos;);
var app = module.exports = express.createServer();
app.everyauth = require(&apos;everyauth&apos;);
app.everyauth.helpExpress(app);
app.mongoose = require(&apos;mongoose&apos;);

var config = require(&apos;./config.js&apos;)(app, express);

var models = {};
models.examples = require(&apos;./models/example&apos;)(app.mongoose).model;

require(&apos;./routes&apos;)(app, models);

app.listen(process.env.PORT || 3000);
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h3 id=&quot;-review&quot;&gt;# Review&lt;/h3&gt;
&lt;p&gt;Let’s review this a few lines at a time.&lt;/p&gt;

&lt;p&gt;Require express and assign the server to the “app” object.&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;var express = require(&apos;express&apos;);
var app = module.exports = express.createServer();
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Require everyauth and load the helpers&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;app.everyauth = require(&apos;everyauth&apos;);
app.everyauth.helpExpress(app);
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Require mongoose&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;app.mongoose = require(&apos;mongoose&apos;);
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Require the config file and pass it some variables to use, we’ll go through this later&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;var config = require(&apos;./config.js&apos;)(app, express);
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Create the object to hold our models and then require them (is this example we only have 1 model)&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;var models = {};
models.examples = require(&apos;./models/example&apos;)(app.mongoose).model;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Require the routes&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;require(&apos;./routes&apos;)(app, models);
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Set the server to listen on a port (process.env.PORT is for production deployment, ie heroku)&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;app.listen(process.env.PORT || 3000);
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h3 id=&quot;setup-the-config&quot;&gt;Setup the config&lt;/h3&gt;
&lt;p&gt;Create a new file under the root of the project named “config.js” and edit it to match the following&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;/config.js
--------------

module.exports = function(app, express, mongoose){

  var config = this;

  app.requireAuth = true;

  //configure everyauth
  app.everyauth.twitter
     .consumerKey(&apos;yourKey&apos;)
     .consumerSecret(&apos;yourSecret&apos;)
     .findOrCreateUser( function (session, accessToken, accessTokenSecret, user) {
       return 1;
  }).redirectPath(&apos;/&apos;);

  //generic config
  app.configure(function(){
    app.set(&apos;views&apos;, __dirname + &apos;/views&apos;);
    app.set(&apos;view engine&apos;, &apos;jade&apos;);
    app.use(express.bodyParser());
    app.use(express.cookieParser());
    app.use(express.session({ secret: &apos;topsecret&apos; }));
    app.use(app.everyauth.middleware());
    app.use(express.methodOverride());
    app.use(app.router);
    app.use(express.static(__dirname + &apos;/public&apos;));
  });

  //env specific config
  app.configure(&apos;development&apos;, function(){
    app.use(express.errorHandler({ dumpExceptions: true, showStack: true }));

    app.mongoose.connect(&apos;mongodb://localhost/nodemvr&apos;);
  });

  app.configure(&apos;production&apos;, function(){
    app.use(express.errorHandler());

    app.mongoose.connect(&apos;mongodb://flame.mongohq.com:27087/nodemvr&apos;);
  });

  return config;

};
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;I’ll let you spend some time to figure out what each little bit of this does but the gist of it is that it sets up your twitter information for authentication and then various config settings which should be pretty self explanitory.&lt;/p&gt;

&lt;p&gt;NOTE - you will need to setup an application on &lt;a href=&quot;http://dev.twitter.com&quot; target=&quot;_blank&quot;&gt;dev.twitter.com&lt;/a&gt; to obtain a key and secret if you want to use authentication.  If not, just set app.requireAuth = false.&lt;/p&gt;

&lt;h3 id=&quot;models&quot;&gt;Models&lt;/h3&gt;

&lt;p&gt;Now let’s create out example model.  We’re going to be using Mongoose for MongoDB.&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;/models/example.js
--------------

module.exports = function(mongoose) {
  var collection = &apos;examples&apos;;
  var Schema = mongoose.Schema;
  var ObjectId = Schema.ObjectId;

  var schema = new Schema({
    author: ObjectId,
    name: String,
    date: Date
  });

  this.model = mongoose.model(collection, schema);

  return this;
};
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Set your collection and build out you’re schema.&lt;/p&gt;

&lt;h3 id=&quot;views&quot;&gt;Views&lt;/h3&gt;

&lt;p&gt;Edit the index.jade and layout.jade to match the following&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;/views/layout.jade
--------------

!!!
html
    head
        title= title
        link(rel=&apos;stylesheet&apos;, href=&apos;/stylesheets/bootstrap.min.css&apos;)

    body
        div.topbar.navbar.navbar-fixed-top
            div.fill
                div.container
                    a(href=&apos;/&apos;).brand #{title}


    div.container!= body
        footer
            p
                | Node.js MVC template by
                a(href=&apos;http://benedmunds.com&apos;)(target=&apos;_blank&apos;) Ben Edmunds


/views/index.jade
--------------

div.hero-unit
    h1 Heading

div.content
    div.row
        div.span12
            h2 Sub-Heading
            ul.unstyled.indent
                each example in examples
                    li
                        a(href=&quot;example/#{example._id}&quot;)  #{example.name}
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;We’ll be using twitter’s bootstrap for our styling so go grab the img, and js from &lt;a href=&quot;https://github.com/twitter/bootstrap/&quot; target=&quot;_blank&quot;&gt;Github&lt;/a&gt; and we’ll use a customized version of the spacelab theme for bootstrap which you can get from &lt;a href=&quot;https://gist.github.com/2424724&quot; target=&quot;_blank&quot;&gt;Gist&lt;/a&gt;.  Place them under their respective folder in the public directory.  Your new directory structure should look like the following&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;public/
    - images/
        glyphicons-halflings-white.png
        glyphicons-halflings.png
    - javascripts/
    	bootstrap.min.js
    - stylesheets/
    	bootstrap.min.css
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h3 id=&quot;routes&quot;&gt;Routes&lt;/h3&gt;
&lt;p&gt;Now for the final step we’re going to create the routes to glue this all together, in the root of your project create a file named “routes.js” and insert the following&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;/routes.js
--------------

module.exports = function(app, models){

  app.get(&apos;/&apos;, function(req, res){

    if (app.requireAuth === true &amp;amp;&amp;amp; req.loggedIn === false)
      res.redirect(&apos;/auth/twitter&apos;);

    //get all the rides
    models.examples.find({}, function(err, docs){

      //render the index page
      res.render(&apos;index.jade&apos;, {
          locals: {
            title: &apos;Example&apos;,
            search_placeholder: &apos;Search&apos;,
            examples: docs
          }
      });

    });
  });

};
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h3 id=&quot;-review-1&quot;&gt;# Review&lt;/h3&gt;
&lt;p&gt;We’ll walk through this one in more detail.&lt;/p&gt;

&lt;p&gt;Create a route to respond to /&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;module.exports = function(app, models){

  app.get(&apos;/&apos;, function(req, res){
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;If requireAuth is true in our config then require authentication&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt; if (app.requireAuth === true &amp;amp;&amp;amp; req.loggedIn === false)
      res.redirect(&apos;/auth/twitter&apos;);
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Get the example data from the model&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;models.examples.find({}, function(err, docs){
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Render the index.jade template with our data&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;res.render(&apos;index.jade&apos;, {
  locals: {
    title: &apos;Example&apos;,
    search_placeholder: &apos;Search&apos;,
    examples: docs
  }
});
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h3 id=&quot;done&quot;&gt;Done!&lt;/h3&gt;
&lt;p&gt;Open the command line and start your app&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;$ node app.js
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h3 id=&quot;get-the-code&quot;&gt;Get the code&lt;/h3&gt;
&lt;p&gt;You can get the code for this project on &lt;a href=&quot;http://github.com/benedmunds/Node-Express-MVR-Example&quot; target=&quot;_blank&quot;&gt;Github&lt;/a&gt;.  I’m fairly new to node and this is a work in progress so if you see anywhere this can be improved feel free to send a pull request.&lt;/p&gt;

&lt;h3 id=&quot;translations&quot;&gt;Translations&lt;/h3&gt;
&lt;p&gt;This page has been translated into &lt;a href=&quot;http://www.webhostinghub.com/support/es/misc/Plantilla-simple-de-Node.js&quot; target=&quot;_blank&quot;&gt;Spanish&lt;/a&gt; language by Maria Ramos  from &lt;a href=&quot;http://www.webhostinghub.com/support/edu&quot; target=&quot;_blank&quot;&gt;Webhostinghub.com/support/edu&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Have fun!&lt;/p&gt;

&lt;p&gt;&lt;br clear=&quot;both&quot; /&gt;&lt;br clear=&quot;both&quot; /&gt;&lt;br clear=&quot;both&quot; /&gt;&lt;/p&gt;

&lt;h3 class=&quot;centered&quot;&gt;Want to Learn More about Node?&lt;/h3&gt;
&lt;div class=&quot;book_image_container post&quot;&gt;
    &lt;a href=&quot;http://securingnodeapps.com&quot; target=&quot;_blank&quot;&gt;&lt;img src=&quot;https://s3.amazonaws.com/titlepages.leanpub.com/securingnodeapps/hero?1481404445&quot; class=&quot;book_image&quot; style=&quot;margin-top:0.2em;&quot; /&gt;&lt;/a&gt;
&lt;/div&gt;
&lt;div style=&quot;margin:0 auto; text-align:center; width:70%;&quot;&gt;
	I&apos;m writing a book on Node JS, &lt;a href=&quot;https://leanpub.com/buildingsecurenodeapps&quot; target=&quot;_blank&quot;&gt;Building Secure Node Apps&lt;/a&gt;.  If you want to learn a ton more, some might even call it a metric fuck-ton, about writing secure Node JS code then stop what you&apos;re doing and &lt;br /&gt;
	&lt;a href=&quot;http://securingnodeapps.com&quot; target=&quot;_blank&quot; class=&quot;small_book_buy_btn&quot;&gt;Buy the Book&lt;/a&gt;
&lt;/div&gt;

&lt;p&gt;&lt;br clear=&quot;both&quot; /&gt;&lt;br clear=&quot;both&quot; /&gt;&lt;br clear=&quot;both&quot; /&gt;&lt;/p&gt;
</description>
				<pubDate>Thu, 19 Apr 2012 00:00:00 +0000</pubDate>
				<link>http://benedmunds.com/node/2012/04/19/simple-nodejs-express-mvr-template</link>
				<guid isPermaLink="true">http://benedmunds.com/node/2012/04/19/simple-nodejs-express-mvr-template</guid>
			</item>
		
			<item>
				<title>Tumblr bundle for Laravel</title>
				<description>
&lt;p&gt;Announcing the release of my &lt;a href=&quot;http://bundles.laravel.com/bundle/tumblr&quot; target=&quot;_blank&quot;&gt;Tumblr bundle&lt;/a&gt; for Laravel.   Check it out on &lt;a href=&quot;http://github.com/benedmunds/Laravel-Tumblr&quot; target=&quot;_blank&quot;&gt;Github&lt;/a&gt;.&lt;/p&gt;
</description>
				<pubDate>Wed, 18 Apr 2012 00:00:00 +0000</pubDate>
				<link>http://benedmunds.com/php/2012/04/18/tumblr-bundle-for-laravel</link>
				<guid isPermaLink="true">http://benedmunds.com/php/2012/04/18/tumblr-bundle-for-laravel</guid>
			</item>
		
			<item>
				<title>Logging Client Side Javascript Errors</title>
				<description>
&lt;p&gt;This seems to be something a lot of people don’t know how to do so here’s a quick intro.  You might have a great error logging setup on the backend of your site but most people have no idea what’s going on with the frontend.  As an example, wouldn’t it be great to be able to see what browser version that one user who always gets JS errors was actually using, or even track the user’s id so you can reference their profile data to get in contact with them.&lt;/p&gt;

&lt;p&gt;That’s where logging client side javascript errors comes in handy.  You’ll need to add logging code on the frontend and a simple API on the backend.  And as a disclaimer, this code is not 100% vetted, it’s just a quick example to get you started.&lt;/p&gt;

&lt;h3 id=&quot;frontend&quot;&gt;Frontend&lt;/h3&gt;
&lt;p&gt;Example logging of javascript errors using jQuery&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;try {
  window.onerror = function(err, url, line) {
    //api url
    var apiUrl = &apos;your/api/url&apos;;

    //suppress browser error messages
    var suppressErrors = true;

    $.ajax({
      url: apiUrl,
      type: &apos;POST&apos;,
      data: {
        errorMsg: err,
        errorLine: line,
        queryString: document.location.search,
        url: document.location.pathname,
        referrer: document.referrer,
        userAgent: navigator.userAgent
      }
    });

    return suppressErrors;
  };
} catch(e) { }
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;&lt;br /&gt;
&lt;br /&gt;&lt;/p&gt;

&lt;h3 id=&quot;backend&quot;&gt;Backend&lt;/h3&gt;
&lt;p&gt;Example route to log the error in Laravel&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;Route::post(&apos;your/api/url&apos;, function()
{
	Log::error(&apos;Javascript error:&apos; . json_encode(Input::get()));
});
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;&lt;br /&gt;
&lt;br /&gt;&lt;/p&gt;

&lt;h3 id=&quot;log-file&quot;&gt;Log File&lt;/h3&gt;
&lt;p&gt;This gives you the following information in your log file&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;2012-04-17 23:40:44 ERROR - Javascript error:{&quot;errorMsg&quot;:&quot;Uncaught ReferenceError: notDefined is not defined&quot;,&quot;errorLine&quot;:&quot;119&quot;,&quot;queryString&quot;:&quot;&quot;,&quot;url&quot;:&quot;\/Personal\/laravel\/public\/&quot;,&quot;referrer&quot;:&quot;http:\/\/localhost\/Personal\/laravel\/&quot;}
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;&lt;br /&gt;
&lt;br /&gt;&lt;/p&gt;
</description>
				<pubDate>Tue, 17 Apr 2012 00:00:00 +0000</pubDate>
				<link>http://benedmunds.com/javascript/2012/04/17/logging-client-side-javascript-errors</link>
				<guid isPermaLink="true">http://benedmunds.com/javascript/2012/04/17/logging-client-side-javascript-errors</guid>
			</item>
		
			<item>
				<title>Connecting to MongoHQ with Node.js MongoDB Native</title>
				<description>
&lt;p&gt;I’m using MongoHQ for a Node.js app I’m deploying on Heroku and couldn’t find it plainly documented anywhere how to connect to MongoHQ using node-mongodb-native, so enjoy:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;/**
 * NOTE: whitespace added for readability
 *
 * EXAMPLE OPTIONS:
 * var options = {
 *     host: &apos;flame.mongohq.com&apos;,
 *     port: 27087,
 *     db: &apos;your_db&apos;,
 *     username: &apos;your_username&apos;,
 *     password: &apos;your_password&apos;
 * };
 *
 **/
DataProvider = function(options) {

    //store this for later use
    var _parent = this;

    //connect to the db
    this.db = new Db(
        options.db,
        new Server(
            options.host,
    	    options.port,
    	    {auto_reconnect: true},
    	    {}
        )
    );

    //open the db connection and then authenticate
    this.db.open(function(err) {
        _parent.db.authenticate(
        	options.username,
        	options.password,
        	function(err) {
                if (err) {
                   console.log(err);
                }
            }
        );
    });

});
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
</description>
				<pubDate>Thu, 12 Apr 2012 00:00:00 +0000</pubDate>
				<link>http://benedmunds.com/node/2012/04/12/connecting-to-mongohq-with-nodejs-mongo-native</link>
				<guid isPermaLink="true">http://benedmunds.com/node/2012/04/12/connecting-to-mongohq-with-nodejs-mongo-native</guid>
			</item>
		
			<item>
				<title>Leading a Dev Team - Focus</title>
				<description>
&lt;h3 id=&quot;the-zone&quot;&gt;The Zone&lt;/h3&gt;
&lt;p&gt;One of the hardest things for developers is to stay focused and in the “zone”.  There is, of course, debate since this can’t be scientifically proven but most people agree that it only takes a second to be snapped out of the zone but can take 15-30 minutes to get back in depending on the complexity of the task.
&lt;br /&gt;&lt;/p&gt;

&lt;h3 id=&quot;human-ram&quot;&gt;Human RAM&lt;/h3&gt;
&lt;p&gt;When developing there are hundreds of tiny details that you have to keep in short term memory for quick access; all of the variables and classes related to what your working on, how those classes interact with other objects, functions, the language API itself, etc. so keeping all of this at the forefront of your mind and not losing it is a very delicate task.  It is your job to make it as easy as possible for your developers to maintain the concentration they need.
&lt;br /&gt;&lt;/p&gt;

&lt;h3 id=&quot;implementation&quot;&gt;Implementation&lt;/h3&gt;
&lt;p&gt;I highly recommend remote working since this allows the developer to work in whatever environment is most productive for him/her.  Also, keep the emails, phone calls, etc. to a minimum unless it is a true emergency.  I personally love Campfire, developers can keep it open and interact as needed but are instructed that anything in Campfire is not an emergency so it can wait.  If there is an emergency you’ll get an IM or call but on the average day you can focus when you need to and check in on Campfire to follow up when you’re between tasks or need a break.
&lt;br /&gt;
&lt;br /&gt;&lt;/p&gt;
</description>
				<pubDate>Wed, 11 Apr 2012 00:00:00 +0000</pubDate>
				<link>http://benedmunds.com/2012/04/11/leading-a-dev-team---focus</link>
				<guid isPermaLink="true">http://benedmunds.com/2012/04/11/leading-a-dev-team---focus</guid>
			</item>
		
			<item>
				<title>Twilio bundle for Laravel</title>
				<description>
&lt;p&gt;Announcing the release of my &lt;a href=&quot;http://bundles.laravel.com/bundle/twilio&quot; target=&quot;_blank&quot;&gt;Twilio bundle&lt;/a&gt; for Laravel.   Check it out on &lt;a href=&quot;http://github.com/benedmunds/Laravel-Twilio&quot; target=&quot;_blank&quot;&gt;Github&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;See the &lt;a href=&quot;http://readthedocs.org/docs/twilio-php/en/latest/&quot; target=&quot;_blank&quot;&gt;Twilio docs&lt;/a&gt; for API details and usage examples.&lt;/p&gt;
</description>
				<pubDate>Tue, 10 Apr 2012 00:00:00 +0000</pubDate>
				<link>http://benedmunds.com/php/2012/04/10/release-twilio-bundle-for-laravel</link>
				<guid isPermaLink="true">http://benedmunds.com/php/2012/04/10/release-twilio-bundle-for-laravel</guid>
			</item>
		
			<item>
				<title>Leading a Dev Team  - Burnout</title>
				<description>
&lt;p&gt;An important part of leading a development team is detecting and preventing burnout before it sets in.  Software development is this strange mix of creating art and worshipping logic.  Programming requires you to creatively solve problems yet in the most rational way possible.
&lt;br /&gt;&lt;/p&gt;

&lt;h3 id=&quot;causes&quot;&gt;Causes&lt;/h3&gt;
&lt;p&gt;After working through a rough project, demanding managers, working a ton of hours, or due to some personal issue developers are very susceptible to burn out.  Burn out is usually where your brain pretty much turns off the ability to solve problems creatively.  You might be able to churn out HTML all day but good luck architecting a new API or solving a difficult bug.  Marissa Mayer also has the &lt;a href=&quot;http://www.thedailymuse.com/career/i-dont-believe-in-burnout-career-lessons-from-marissa-mayer/&quot; target=&quot;_blank&quot;&gt;unique and valid perspective&lt;/a&gt; that burnout is caused by resentment.
&lt;br /&gt;&lt;/p&gt;

&lt;h3 id=&quot;solutions&quot;&gt;Solutions&lt;/h3&gt;
&lt;p&gt;The best way I’ve found to prevent burn out is to create a fun environment with as little stress as possible, give the developer more personal time, and if burnout starts to set in give them an easy project where they see progress often.  Another thing to always guard against is creating resentment, so make sure that you aren’t demanding too much and be as flexible as possible.  It’s amazing what a three day weekend can do to someone’s outlook.  It’s also extremely refreshing  for someone to create something and solve a problem without adding to their mental stress.
&lt;br /&gt;
&lt;br /&gt;&lt;/p&gt;
</description>
				<pubDate>Fri, 06 Apr 2012 00:00:00 +0000</pubDate>
				<link>http://benedmunds.com/2012/04/06/leading-a-dev-team----burnout</link>
				<guid isPermaLink="true">http://benedmunds.com/2012/04/06/leading-a-dev-team----burnout</guid>
			</item>
		
			<item>
				<title>Leading a Dev Team - Trust</title>
				<description>
&lt;p&gt;I’m going to do a small series to document some of the things I’ve learned while being a developer all these years and while managing/leading development teams.  This is the first post in the series (so get ready bitches).&lt;/p&gt;

&lt;p&gt;You have to trust your dev team completely.  Only hire people who you can really trust.  If you’re spending your time worrying about whether or not someone is doing their job or working their hours or whatever else then that’s energy wasted that should be spent elsewhere.  There will of course be issues with certain team members, but deal with those issues quickly and trust them again as soon as possible.&lt;/p&gt;

&lt;p&gt;Output is MUCH more important than hours.  Your developers need the freedom to not be bound by a clock or a desk or a phone.  Sometimes the best way to figure out a problem is to go take a walk.  What might be solved by a 10 minute break can easily turn into a completely wasted day if your employees feel like they can’t break away.&lt;/p&gt;

&lt;p&gt;Trust also leads to freedom, you’re developers should be able to make their own decisions on the technologies they use (within reason) and how they implement those technologies (where possible).  Remember, you hired them for a reason, so let them grow and show you what they can do.&lt;/p&gt;
</description>
				<pubDate>Tue, 03 Apr 2012 00:00:00 +0000</pubDate>
				<link>http://benedmunds.com/2012/04/03/leading-a-dev-team---trust</link>
				<guid isPermaLink="true">http://benedmunds.com/2012/04/03/leading-a-dev-team---trust</guid>
			</item>
		
			<item>
				<title>One Line HG Pull/Update for Deployment</title>
				<description>
&lt;p&gt;The following is a quick one-liner for pulling and updating a mercurial repo with a specified directory, this is especially useful for deployment scripts:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;$ hg pull -vu --cwd /full/path/to/dir/to/update  
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
</description>
				<pubDate>Mon, 02 Apr 2012 00:00:00 +0000</pubDate>
				<link>http://benedmunds.com/2012/04/02/one-line-hg-pullupdate-for-deployment</link>
				<guid isPermaLink="true">http://benedmunds.com/2012/04/02/one-line-hg-pullupdate-for-deployment</guid>
			</item>
		
			<item>
				<title>Jekyll - Publish Posts by Date/Time</title>
				<description>
&lt;p&gt;I had to read through the Jekyll source to figure this out since I didn’t see this feature documented anywhere (I’m sure it is though) so I’m going to document how to filter the display of posts in Jekyll by a published date.&lt;/p&gt;

&lt;p&gt;For example, you write a post now but don’t want it to display until a certain time tomorrow.&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;
    &lt;p&gt;In _config.yml add/modify the following:&lt;/p&gt;

    &lt;p&gt;&lt;code&gt;future: false  &amp;nbsp;&amp;nbsp;# This will tell jekyll to not display future posts&lt;/code&gt;
&lt;br /&gt;
&lt;br /&gt;&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;In the post header add a date attribute with the date and time you want the post to publish:&lt;/p&gt;

    &lt;p&gt;&lt;code&gt;date: 2012-03-28 18:31:00&lt;/code&gt;
&lt;br /&gt;
&lt;br /&gt;&lt;/p&gt;
  &lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;br /&gt;&lt;/p&gt;

</description>
				<pubDate>Tue, 27 Mar 2012 15:30:00 +0000</pubDate>
				<link>http://benedmunds.com/ruby/2012/03/27/jekyll---publish-posts-by-datetime</link>
				<guid isPermaLink="true">http://benedmunds.com/ruby/2012/03/27/jekyll---publish-posts-by-datetime</guid>
			</item>
		
			<item>
				<title>How I Work</title>
				<description>
&lt;p&gt;I’m always interested in the way other people work so I figured I would share my environment and what makes me most productive.&lt;/p&gt;

&lt;h3 id=&quot;hardware&quot;&gt;Hardware&lt;/h3&gt;
&lt;p&gt;13” Macbook Pro.  When I’m sitting at my desk I use a 23” external Samsung monitor, Apple wireless keyboard, Magic Trackpad.&lt;/p&gt;

&lt;h3 id=&quot;software&quot;&gt;Software&lt;/h3&gt;
&lt;p&gt;OSX Snow Leopard.  Firefox for web browsing.  Sublime Text 2 for development.  Git and HG on the command line for version control.  CLI and PGAdmin3 for Postgres.  CLI and Navicat for MySQL.  Sparrow for email.  Gtalk for IM.  iTunes and Spotify for music.&lt;/p&gt;

&lt;h3 id=&quot;work-day&quot;&gt;Work Day&lt;/h3&gt;
&lt;p&gt;I usually get up around 8:15am EST.  Make some coffee (dunkin donuts), feed my dogs, and let them out.  Then start working around 8:30am.  I usually work until about 5pm with a 30 minute lunch break but depending on what’s going on I might take a longer lunch and then work later.&lt;/p&gt;

&lt;p&gt;I tend to move around a lot during the day.  I find that a change of scenery really helps keep me thinking straight.  I start the morning in the kitchen most days and then move to my office a couple of hours later for a scrum call.  Sometime after lunch (if the weather is nice) I’ll move outside or some random place in the house (living room, bedroom, kitchen, office).  Whenever I start to get stir crazy I’ll get out of the house and work from one of the coffee shops downtown.&lt;/p&gt;

&lt;h3 id=&quot;desk&quot;&gt;Desk&lt;/h3&gt;
&lt;p&gt;&lt;img src=&quot;/assets/desk.jpg&quot; /&gt;&lt;/p&gt;
</description>
				<pubDate>Sun, 25 Mar 2012 00:00:00 +0000</pubDate>
				<link>http://benedmunds.com/2012/03/25/how-i-work</link>
				<guid isPermaLink="true">http://benedmunds.com/2012/03/25/how-i-work</guid>
			</item>
		
	</channel>
</rss>