Unlimited Plugins, WordPress themes, videos & courses! Unlimited asset downloads! From $16.50/m
  1. Code
  2. Yii

Building Your Startup: Invite People via URL

Read Time:13 minsLanguages:
This post is part of a series called Building Your Startup With PHP.
Building Your Startup: Ajax for Meeting Times and Places
Building Your Startup: Increasing Security
Final product imageFinal product imageFinal product image
What You'll Be Creating

This tutorial is part of the Building Your Startup With PHP series on Envato Tuts+. In this series, I'm guiding you through launching a startup from concept to reality using my Meeting Planner app as a real-life example. Every step along the way, I'll release the Meeting Planner code as open-source examples you can learn from. I'll also address startup-related business issues as they arise.

Schedule Your Group Meeting via Shortcut URL

Welcome! I'm recently back from my favorite place in the world, which I mentioned at the end of the last episode. After completing multiple participant meetings, I took a break in nature.

Building Your Startup Secure Shareable Invitation URL - My Favorite Place In the WoodsBuilding Your Startup Secure Shareable Invitation URL - My Favorite Place In the WoodsBuilding Your Startup Secure Shareable Invitation URL - My Favorite Place In the Woods

Today, I'll be adding the ability to invite meeting participants by sharing a secure URL associated with your meeting. This will be especially helpful for scheduling group meetings. For example, if you want to invite 30 people, it's sometimes easier to drop an email to everyone with an invitation URL.

If you haven't yet, please try to schedule your own group meeting today! Invite a few friends to meet you for kombucha, kava, or coffee. Share your thoughts and feedback of everyone's experience in the comments below. I do participate in the discussions, but you can also reach me @reifman on Twitter. I'm always open to new feature ideas for Meeting Planner as well as suggestions for future series episodes.

As a reminder, all the code for Meeting Planner is provided open source and written in the Yii2 Framework for PHP. If you'd like to learn more about Yii2, check out my parallel series Programming With Yii2

Before I dive into this feature, I want to give some examples of some of the common day bugs (or oversights) that I've encountered building the service. (If you just want to read about secure shareable URLs, please feel free to skip this section.)

The Startup Bug Interlude

As more and more people begin trying Meeting Planner, bugs come rolling in. And, often during development, I notice them myself. Here are a few recent ones, just to give you an idea of startup life. 

It can be hard to focus on business development and marketing, coding new features, and identifying and fixing bugs. The one-person startup grows in difficulty as your site's features grow.

As I wrote about earlier, I am currently using Asana for feature planning—but also to track bugs.

The If Assignment Bug

I'm sure if I had more expertise as a developer, worked with colleagues, or had more time to not code Meeting Planner, I'd know exactly which Atom Editor extension hunts for these. If you know, please post it in the comments.

Apparently, in an important feature to check if a viewer was actually a meeting attendee, I was using assignment to check. In other words, I wasn't asking if the owner was the viewer—I was temporarily making this the case.

You remember, two equals is a comparison, one equals is an assignment. Just like periods are for concatenations and plus signs are for addition, except in JavaScript, where they're for endlessly difficult to find bugs (which is also why Ajax is hell in PHP).

Database Queries That Fail Over Time

As my own usage of Meeting Planner increased, there were more and more meetings in my tabbed views. And then I noticed that sometimes duplicates would show up. This was hard to detect earlier when there was less data.

My tab-specific meeting queries (i.e. planning a meeting, confirmed meetings, past meetings, etc.) were not isolating unique entries:

Adding ->distinct() to the query fixed it.

Yii2 Pagination on Grid Views on Tabbed 

Another bug I encountered with more data was that Yii2 pagination links always took me back to the first tab.

Building Your Startup Secure Shareable Invitation URL - Pagination of MeetingsBuilding Your Startup Secure Shareable Invitation URL - Pagination of MeetingsBuilding Your Startup Secure Shareable Invitation URL - Pagination of Meetings

I added a query parameter for the current tab which MeetingController.php actionIndex now looks for:

Also, I instructed the pagination params to merge the current tab setting. When users click on a different page link, the current tab is now included.

Finally, I also made the /frontend/views/meeting/index.php aware of this, setting the active tab from the query parameter:

Those are just a few good examples of the everyday kind of bugs that I run into building a startup the scope of Meeting Planner.

Now, let's dive into building invitations via shortcut URLs as promised.

Building Secure Shareable Shortcut URLs

Thinking About Security for URLs

To make it more difficult for a random blast of URL guesses to break into someone's meeting invitation, I needed to have a fairly unique key combined with an unguessable code.

I decided to use the person's username as a key. Each user would have a large number of nearly unguessable meeting codes.

So, for example, a meeting URL might be https://meetingplanner.io/presidenthillary/X1Y2Z3A7C9.

For the code, I decided to use eight case-sensitive alphanumeric characters. In other words, each character would be a-z, A-Z, or 0-9, essentially 62 possibilities for each character.

The total number of possibilities for each user is 218,340,105,584,896—more than 218 trillion. Oh, and you'd have to know your target's username to get started! It would be much easier to hack a participant's email account.

Adding the Security Code for Every Meeting

To add a security code to all the existing meetings, I created a migration, m160902_174350_extend_meeting_for_identifier.php:

You'll notice that in this migration, I actually use code to create random strings for every existing meeting, i.e. Yii::$app->security->generateRandomString(8);.

It's not often that I'll write code into a migration to update existing areas of the database. In this case, it works smoothly. Other times, I've used the /frontend/models/Fix.php model.

Also, in Meeting::beforeSave(), I added automated code to generate an identifier for all future meetings:

Extending Yii Routing

While it would have been easiest to include a controller prefix such as /m/username/identity-code, I wanted links to be simple, with no additional prefix. This required extending the Yii Routing

If I'd kept this within its own model for the prefix and the username, I might have been able to use what I wrote about in Yii2 Sluggable Behaviors and Building Your Startup: Geolocation and Google Places.

Instead, I added  '<username>/<identity:[A-Za-z0-9_-]{8}>' => 'meeting/identity', which maps any username with an identity string to the MeetingController actionIdentity() method.

With this, I did run into a few problems. I had to reorder the rules and put in static routes for any eight character actions that might have appeared to look like a username (instead of a controller) and a method (instead of an identity key).

For example, https://meetingplanner.io/site/features mapped to a user named site having a secure meeting ID of 'features' instead of Meeting Planner's cool new feature table.

But, once I oriented myself to the issues, everything worked fine.

The Meeting Controller Identity Method

Next, I built actionIdentity() within MeetingController:

First, it verifies that the username and identity correspond to an existing user and an existing meeting. If not, we send them to authfailure.

If the user is already logged in, we automatically add them as a participant to this page and redirect them to the Meeting's view page.

If they are not, we send them to a Participant controller Join action to address sign-in or sign-up.

Participant Requesting to Join a Meeting

For example, let's say I receive the following email invitation from a friend:

https://meetingplanner.io/tomeMcFarline/JzRq1a42. I'll be shown this page:

Building Your Startup Secure Shareable Invitation URL - Participant Join Page from Invite URLBuilding Your Startup Secure Shareable Invitation URL - Participant Join Page from Invite URLBuilding Your Startup Secure Shareable Invitation URL - Participant Join Page from Invite URL

If the user wishes to sign up for Meeting Planner via a social network, we'll be able to validate their email address.

So I set the Yii return URL (a page that the user is redirected to after a successful sign-up or login) which will return them to the Meeting view page after authentication.

For the most part, the social authentication, login and/or sign-up is managed by the code I described in Building Your Startup: Simplifying Onramp With OAuth.

If the participant is new, they'll provide their first and last name and email address. We'll add them to the meeting as an unverified participant, similar to what we do when a user invites someone by adding a new email address to the meeting.

You're wondering right now, hey Jeff, what's with the ... today? This is simple, right? We're just adding a new user to a meeting.

While coding this, I realized I was creating a huge privacy hole.

A Fun Security Hole Example

Let's say Tom McFarlin has nothing to do one day and decides to mess with me (and God). He'll create a new meeting and, knowing that the Dalai Lama is a regular Meeting Planner user (because of all his spiritual meetings), McFarlin will add him to his meeting using the email dalailama@gmail.com.

Then, he'll grab his fancy secure shortcut URL. Following me?

Next, McFarlin will open a different browser and open his secure shortcut URL and pretend he's the Dalai Lama who just received a different invitation via email from Tom, i.e. he'll try to join his own meeting as if he was the Dalai Lama. i.e. Dalai, Lama, dalailama@gmail.com.

Initially, I presumed that there was no likelihood that someone would ever guess the secure URL, so if that happened to happen, I'd just let a person log in this way. 

But, this would give the dangerous McFarlin access to the Dalai Lama's account (partly because I haven't yet built the limited access mode for users coming in through URLs to only be able to see a single meeting until they log in).

Yep, my initial code worked this way. And then I got a call down from the heavens and pointed this out. 

What if McFarlin invited Sally and Sally forwarded the secure URL to Bill Gates? By manually adding Bill Gates to the meeting first, McFarlin could access all of Gates's meetings with this trick.

The new code requires a participant using the secure URL who has already been coincidentally added to the meeting to log in manually. Here's the ... code:

I'll patch this again once I create the single meeting restricted access mode.

I might not have thought about this if I hadn't known how devious McFarlin is. Phew. One more queen saved from poisoning.

Building Your Startup Secure Shareable Invitation URL - The Devious Editorial God Tom McFarlin Or NotBuilding Your Startup Secure Shareable Invitation URL - The Devious Editorial God Tom McFarlin Or NotBuilding Your Startup Secure Shareable Invitation URL - The Devious Editorial God Tom McFarlin Or Not

Probably taking my long weekend in nature got me more in touch with the heavens too.

What's in the Pipeline?

Building Your Startup Secure Shareable Invitation URL - Surfing Pipeline imageBuilding Your Startup Secure Shareable Invitation URL - Surfing Pipeline imageBuilding Your Startup Secure Shareable Invitation URL - Surfing Pipeline image
Public domain via Google & Hawaii Picture of the Day

I hope you've enjoyed this episode on creating secure URLs to invite people to meetings. I imagine it's highly reusable for other scenarios in your own services. 

You can also probably tell I'm either enjoying the potential Meeting Planner seems to have at this point—or I've just been working too long.

Ultimately, building secure URL invitations also opens up the possibility of offering users a public scheduling page. For example, I can share my public Meeting Planner URL with friends and, say, just schedule me at https://meetingplanner.io/username.

In the future, I could even extend Meeting Planner to offer subscription features for professionals to take appointments at their public Meeting Planner page. However, I have other more exciting ideas. This territory is well staked out by other business-oriented companies.

Riding the Wave Home

If you haven't yet, go schedule your first meeting with Meeting Planner now! Try sharing your meeting's shortcut URL, and keep it secret from our editorial god Tom McFarlin.

You can also reach out to me @reifman. I'm always open to new feature ideas and topic suggestions for future tutorials. Or try out our helpdesk and open a bug report or feature request ticket. 

A tutorial on crowdfunding is also in the works, so please follow our WeFunder Meeting Planner page.

Stay tuned for all of this and more upcoming tutorials by checking out the Building Your Startup With PHP series

Related Links

Looking for something to help kick start your next project?
Envato Market has a range of items for sale to help get you started.