テキストや画像、動画などの投稿、プライベートチャットを楽しめるSNSウェブアプリケーション。
アプリ名に「ten」という単語を使ったのは、人々が交わる(クロス)というイメージを表現するためです。そのイメージに合うのが、「t」から始まり、漢字で「十」という意味を持つ「ten」という単語でした。
画面下部にある+マークの青いボタンをクリック。
入力フォームに内容を入力し「投稿」ボタンを押すと、投稿できます。
また、画面左下にあるイメージアイコンをクリックし、画像や動画などのメディアを選択すると、テキストと一緒にメディアも投稿できます。
予約投稿の機能を利用すると、指定した日時に投稿できます。
投稿フォームで予約投稿したい内容を入力後、画面下側にあるカレンダーマークをクリック。
「日付を入力」をクリックし、投稿したい日付と日時を選択し、「決定」ボタンをクリックします。
投稿フォームで予約投稿したい内容を入力し、「投稿」ボタンをクリックすると、予約投稿の完了です。
また、投稿フォームの右上にある「予約投稿一覧」をクリックすると、予約済みの投稿を確認できます。
自分の投稿の右側の「・・・」マークをクリックし、削除を選択。
アラートの画面で削除を選択すると投稿を削除できます。
ホーム画面ではトレンドの投稿とフォーロー中のユーザーの投稿を閲覧できます。
画面上部にあるタブでタイムラインの切り替えが可能です。
トレンドのタイムラインは今日投稿された中で最も新しい投稿を閲覧できます。
検索ページではユーザーの検索ができます。
検索欄に文字を入力すると、その文字がアカウント名もしくはユーザー名に含まれるユーザーが画面に表示されます。
検索欄に何も文字を入力していない場合は、フォロワーが多い順に上から100人のユーザーが表示されます。
フォローしたいユーザーのプロフィール画面にある「フォローする」ボタンを押すとユーザーをフォローできます。
各ユーザーのプロフィール画面は、ユーザーの検索画面や投稿のアカウント名から飛ぶことができます。
投稿の下部にあるグッドボタンのアイコンをクリックすると、投稿に対して「いいね」ができます。 投稿をクリックして投稿の詳細画面のページに行くと、投稿に対して返信をしたり、他の人の返信を閲覧できます。
ダイレクトメッセージを送りたいユーザーのプロフィール画面に行き、「メッセージ」ボタンを押すと、ダイレクトメッセージのやり取りができるページに行けます。 ここでは2人だけのやり取りを楽しめます。
通知ページでは通知の一覧を確認できます。
通知アイコン部分には未確認の通知の数が表示されます。
自分の投稿に対して返信あるいはいいねされた場合、自分がフォローされた場合、ダイレクトメッセージを受信した場合に通知が届きます。
各通知をクリックすると、返信・いいねされた自分の投稿、フォローしてくれたユーザー、ダイレクトメッセージなどのページに行くことができます。
このSNSウェブアプリケーションは、テキストや画像などの投稿、相互フォロー、プライベートチャットなど、さまざまな機能を楽しめます。
また、パソコンやタブレット、スマートフォンなど、どの端末でも使いやすいように、レスポンシブ対応のUIを採用しています。
- アカウント作成
- Eメール認証
- ログイン
- プロフィール画像、年齢、場所、自己紹介などのプロフィール作成
- アカウントの削除
- パスワードのリセット
- テキストの投稿
- 画像の投稿
- 動画の投稿
- 投稿の削除
- 日付・時間指定による予約投稿
- ダイレクトメッセージ
- フォロー中、トレンド別のタイムライン表示
- ユーザー名、アカウント名でのユーザー検索
- 投稿に対するいいね機能
- 投稿への返信
- 自分の投稿への返信
- 自分の投稿へのいいね
- フォロー
- ダイレクトメッセージの受信
このSNSウェブアプリケーションの制作は、これまでの学習やプロジェクト作成を通じて得た知識とスキルを活かし、より大規模なプロジェクトに取り組むことを目指して始めました。独自のマイクロフレームワークを使用し、ゼロからアプリケーションを構築することで、将来的にどのようなバックエンドフレームワークを学習する際にも役立つスキルセットを身につけることを意図しています。
MVC(Model-View-Controller)アーキテクチャを採用し、データベースの管理にはマイグレーションベースを採用しました。また、データベースへのアクセスにはDAO(Data Access Object)を利用しています。
特にセキュリティへの取り組みには重点を置き、以下のセキュリティ対策を実装しました。
- セッションベースのユーザー認証
- ユーザー入力のバリデーション
- プリペアドステートメントの使用
- テキストの暗号化
- CSRF(Cross-Site Request Forgery)対策
- 署名付きURLの発行
- Eメールの検証
これらの実装についての詳細は、後述する「こだわった点」で解説します。
項目 | 内容 |
---|---|
使用言語 | HTML, CSS, Javascript |
CSSフレームワーク | Tailwind |
Tailwindライブラリ | flowbite, daisyUI |
日付選択ライブラリ | Flatpickr |
リアルタイム通信 | WebSocket |
パッケージ管理 | npm |
モジュールバンドラー | webpack |
項目 | 内容 |
---|---|
使用言語 | PHP |
データベース | MySQL |
ジョブ管理ツール | cron |
単体テスト | PHPUnit |
メール送信 | PHPMailer |
リアルタイム通信 | Ratchet |
プロセス制御システム | Supervisor |
画像編集 | ImageMagick |
動画編集 | ffmpeg |
日付操作 | Carbon |
ダミーデータ | Faker |
ダミー画像 | Pixabay API |
パッケージ管理 | Composer |
オートローダー | Composer |
Webサーバー | NGINX |
サーバー | Amazon EC2 |
SSL/TLS証明書更新 | Certbot |
2024年1月18日から約2か月半かけて開発しました。
実装開発サイクルに入る前に、図を作成して要件を把握し、要件モデリングを行いました。 これにより全体像が把握でき、スムーズに実装を進めることができました。
必要な機能を洗い出すためにユースケース図を作成しました。 ゲストユーザーが使用できる機能、ログインユーザーが使用できる機能、システムの担当が必要な機能などを表しています。 ユースケース図のコードは、user_usecase.puで確認できます。
アジャイル開発を採用し、実装を進めながらソフトウェア設計を反復して、ER図を構築していきました。 ER図のコードは、er.puで確認できます。
機能のフローを把握するためにシーケンス図を作成しました。 例えば以下はゲストユーザーがトレンドのタイムラインを表示する際の流れを表したシーケンス図です。 作成したすべてのシーケンス図はsequencesで確認できます。
安全なアプリケーションを開発するために、大きく以下の3つのセキュリティ対策を実装しました。
- 署名付きURLによる検証
- ミドルウェアによるアクセス制限
- ユーザー入力の検証
ユーザーが入力したEメールが有効かどうかを確認するEメール認証機能を導入しました。 これにより不正なアカウントの作成を防止します。
サーバーはアカウント作成ページで入力された情報を受け取ると、署名付きURLを作成し、入力されたEメール宛に送信します。 ユーザーが受信した署名付きURLを開くと、Eメールが有効であるとみなされアカウントが作成されます。
URLの署名には、サーバーサイドのシークレットキーとHMAC SHA256メッセージハッシュアルゴリズムを使用しました。 署名付きURLにはユーザーID、ハッシュ化されたEメール、有効期限を含めました。
サーバーが署名URLへのリクエストを受け取ると、現在のURLをシークレットキーでハッシュし、URLに埋め込まれた署名と比較して署名の有効性を検証します。 署名が有効であることが確認されると、ユーザーのアカウント作成が成功し、ログインが可能になります。
このフローを以下の図に示します。
パスワードリセット機能も同様の署名付きURLを使用して実装しています。 さらに、パスワードリセットの場合は、リクエストしたユーザーのIDとトークンを管理するためのパスワードリセットテーブルを使用しています。
各ページへのアクセスはミドルウェアによって制限されています。ほとんどのページは、ログイン状態かつEメール認証済みのユーザーのみが閲覧可能です。
例えば未ログインの状態で、ログインが必要なページ(https://ten.yuki-gakiya.com/messagesなど)に、アクセスすると下記の画像のように、アラートが表示されログインページにリダイレクトされます。
これはAuthenticatedMiddlewareによって実行されます。
このように、ミドルウェアはユーザーのログイン状態やEメール認証の有無などを判断し、特定のページや機能へのアクセスを許可します。
ユーザー認証にはセッションベースの方法を採用しています。ログインページで正しいEメールとパスワードが入力されると、セッションデータにユーザーIDが付与され、アクセスが許可されます。セッションが有効な限り、ユーザーはログイン状態を維持します。
各リクエストでは、クライアントから送信されたセッションデータのみをチェックすればよく、サーバー側での認証は不要です。
CSRF攻撃への対策として、ミドルウェアとCSRFトークンを利用しています。サーバーはCSRFトークンの有効性をチェックし、無効な場合はリクエストを拒否します。 CSRFトークンの生成とCSRFトークンの検証はCSRFMiddlewareで行います。
Eメール検証機能やパスワードリセット機能に使用する署名付きURLの確認にもミドルウェアを使用しています。 SignatureValidationMiddlewareではURLの署名の有効性や有効期限のチェックを行います。
このSNSウェブアプリケーションでは、アカウント作成やログイン、プロフィール編集、投稿など、ユーザーが入力する機会が多くあります。ユーザーが入力した情報はすべて厳密なバリデーションが行われており、誤ったデータ入力によるバグを防止しています。
バリデーション関数はValidationHelperクラスで管理しています。また、バリデーション関数が適切に機能していることを確認するために、PHPUnitを使用してテストを行っています。
テストにはValidationHelperTestクラスとValidationHelperDataProviderクラスを使用しています。
さらに、SQLやスクリプト、コマンドなどの注入攻撃に対する対策も実施しています。クエリの実行にはプリペアドステートメントを使用し、HTMLのレンダリング時にはhtmlspecialchars関数を使用してサニタイズを行っています。
また、機密データを保護するために適切なタイミングでテキストの暗号化やハッシュ化を行っています。例えば、アカウント作成に使用されるパスワードは検証が必要であるため、password_hash関数を使用してハッシュ化しています。
また、ダイレクトメッセージなど、元のメッセージに戻す必要がある場合は、openssl_encrypt関数を使用して暗号化を行っています。暗号化に関する関数はCipherHelperクラスで管理しています。
このSNSウェブアプリケーションでは、定期的な処理を実行するためにcronを活用しています。
まず、予約投稿機能を実現するために、PostScheduledというコマンドを作成しました。このコマンドは、スケジュールされた投稿データの中で現在の時間を過ぎているデータのステータスをスケジューリング状態から公開状態に変更します。そして、このコマンドを実行するためのスクリプトpost_scheduled.phpをcronで毎分実行しています。
また、データシーディングも定期的に行っています。このSNSウェブアプリケーションでは、実際の利用状況を模倣するために、数千人のユーザーがサービスを利用しているかのような状況を再現するためにデータシーディングを行っています。
まず、本番環境にアップした際に以下のデータを生成しました。
- 2000人のユーザー
- 6000の投稿
- 36000のいいね
- 18000のコメント
- 6000のコメントへの返信
- 3000のコメントへのいいね
- 1ユーザーあたり10 ~ 100のフォロー
その中で、50人をインフルエンサーとして設定し、フォローデータ生成時には、3分の1の確率でインフルエンサーをフォローするようにしました。
本番環境でアップ後は、実際のソーシャルメディアの動向を模倣するために、以下のデータ生成をランダムな時間でスケジューリングしています。
- 各ユーザーは毎日ランダムな内容の投稿を3つ行う
- 各ユーザーは毎日1つのランダムな投稿に返信を行う
- 各ユーザーはインフルエンサーアカウントの中から20の投稿にいいねをする
これらのデータ生成のスケジューリングにはMySQLのCREATE EVENTステートメントを使用しています。 また、データシーディングを定期的に実行するために、SeedDaoというコマンドを作成し、それをcronで実行するためのスクリプトseed_prototype.phpを作成しました。
このSNSアプリケーションでは非同期によるダイレクトメッセージ機能を実装するためにWebSocketを導入しました。
実装にあたってRatchetというライブラリを使用しています。 Ratchetが提供しているMessageComponentInterfaceを実装して、Chatクラスを作成しました。
また、安全なダイレクトメッセージを実現するために、NGINXのリバースプロキシ機能を使ってWSS化も行っています。
- 自分のコメントに返信された際の通知発行
- 画像の複数枚アップロード
- 投稿を検索する機能の実装