イタズラ投稿者のIPアドレスを、簡単に取得する方法（Laravel）

##はじめに

私は未経験からプログラミングを学習して、Laravel等の技術を使用した
自作アプリをポートフォリオとして一般公開していました。

すると幸いにも、多くの方に実際にアプリを利用してもらうことができたものの、
やはり**イタズラ投稿や連続投稿等、迷惑な投稿**もされるようになりました。

→そんな体験の一部をまとめた記事：
[ポートフォリオのアプリを公開したらイタズラされまくった話](https://qiita.com/nasuB7373/items/10bebd8e9f0b3331f348)
（1,000LGTM突破ありがとうございます🙇‍♂️）

そこで、次の対策にも繋げるために、アプリに**「投稿者のIPアドレスを取得する機能」**を追加することにしました。
調べてみると、**Laravelで非常に簡単に**実現できることがわかったので、今回はその方法をご紹介いたします。

##前提条件

私は、以下の環境等で実現しました。


- Laravel 6.18.36
- 既に投稿機能が実装されている


##実際に、イタズラ投稿者のIPアドレスを取得してみた

まず初めに、デモンストレーションです。
私が公開しているアプリへの、イタズラ投稿者のIPアドレスを取得してみます。
では、どんなイタズラ投稿があるというと・・

![スクリーンショット 2021-01-22 9.44.53.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/613419/d86b6b06-c80c-c39b-ae8d-7593cb22b488.png)

はい！下ネタ全開のイタズラ投稿ですね。笑
このような投稿が、日々ちょくちょく投稿されていました。^^;

ということで、IPアドレスを取得する処理を実装済みなので、
早速IPアドレスが取れたか確認してみます。

※ゲストユーザーというのは、パスワード等を入力しなくても、誰でも簡単にログイン可能なユーザーのことです。

###DBの中身を確認してみた

ということで、DBを覗いてみました。

![スクリーンショット 2021-01-22 9.46.38のコピー.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/613419/307a3dbf-7a59-5814-0dda-4281443246d7.png)

おぉ。。`ip_address`カラムにしっかりと、下ネタ投稿者のIPアドレスが取得できていました。
流石にIPアドレスをこのまま載せるのは避けますが、<font color='Red'>**赤色**</font>で
伏せてる部分が、同一IPアドレスでした。
一方<font color='Blue'>**青色**</font>で伏せている部分は、それ以外の複数のIPアドレスです。

###三日間の投稿の、IPアドレスを調べてみた

2020年1月21日〜23日の投稿を確認してみました。

![スクリーンショット 2021-01-23 17.04.21.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/613419/d5017437-00ae-adc6-e757-a3edd6962323.png)

- <font color='Red'>**赤色**</font>で伏せてる部分が、全て同一IPアドレスでした。
　1月22日から23日にかけて、下ネタを投稿したり、「おはようございます！」と連続投稿していたことがわかります。

- <font color='Blue'>**青色**</font>で伏せている部分は、それ以外の複数のIPアドレスです。

- ip_addressカラムの中身が`「NULL」`となっているものは、IPアドレスを取得する処理が未実装だった頃の投稿です。IPアドレスが取得できていません。

こうして見てみると、下ネタ投稿ユーザーが
二日間に渡って投稿してきていることがわかります。
同一人物だったんか・・・というのがわかるとちょっと面白いですよね。

それでは、いよいよIPアドレス取得機能の実装方法についてご紹介していきます。


##IPアドレスの取得方法

これが、とても簡単です。
Requestクラスの、**ip()メソッド**を利用するだけです。
ユーザーがアプリ上で投稿を行った際に、Controller側でユーザーのIPアドレスを
`$request->ip()` といった形で扱うことができます。

例えば、投稿機能に関する処理をまとめたControllerである
`ArticleController.php`に、
登録処理を定義したstore()メソッドがあるとします。
内容としては、ユーザーが投稿したメッセージを、そのままDBに保存するだけのシンプルな処理です。

```ArticleController.php
public function store(ArticleRequest $request, Article $article)
{
    // 投稿をDBに保存
    $user = $request->user();
    $article = $user
                ->articles()
                ->create($request->validated()); // バリデーション済みの値だけ保存
    return redirect()->route('articles.index');
}
```

※ちなみに、上記のコードでは、`$request->validated()`で、バリデーション済みの値のみを取得しています。
こちらの方が、`$request->all()`で値を取得するより安全です。


それでは、storeメソッドの処理の一番最初に、試しに**dd( )メソッド**で`$request->ip()`を取ってみましょう。
この状態で、アプリから自分で適当な投稿をしてみると、ちゃんと自分のIPアドレスが取得できていることが確認できると思います。

```ArticleController.php
public function store(ArticleRequest $request, Article $article)
{
    dd($request->ip());  // 投稿者のIPアドレスが取得できているか確認

    // 投稿をDBに保存
    $user = $request->user();
    $article = $user
                ->articles()
                ->create($request->validated()); // バリデーション済みの値だけ保存
    return redirect()->route('articles.index');
}
```

たったこれだけでIPアドレスを取得できてしまうので、Laravelって本当に便利ですね。。


なお、本記事でご紹介する実装の主な手順としては、以下のようになっています。
（あまり難しくありません）

1. DBの`articlesテーブル`に、`「ip_address」カラム`を追加し、IPアドレスを保存できるようにする。
1. 上記store()メソッドで、IPアドレスをDBに保存するようコードを編集
1. fillableにコードを一行追加 

※投稿に関する情報を保存するDBのテーブルを、`articlesテーブル`と定義する場合



##IPアドレス取得機能の実装方法

###DBのテーブルに、IPアドレス用のカラムを追加

本記事では、以下の前提で実装を進めていきます。

- ユーザー投稿に関する情報を保存するテーブルを、`articlesテーブル`とする
- IPアドレスを保存するカラムを、`ip_address`カラムとする

まずカラム追加のマイグレーションファイルを作成します。
ターミナルから以下のコマンドを実行してください。

```
$ php artisan make:migration add_ip_address_to_articles_table --table=articles
```
新しいマイグレーションファイルが作成されるので、そちらを以下のように編集してください。

```php
<?php

use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;

class AddIpAddressToArticlesTable extends Migration
{
    /**
     * Run the migrations.
     *
     * @return void
     */
    public function up()
    {
        // ここから追記　ーーーーーーーーーーーーーーーーー
        Schema::table('articles', function (Blueprint $table) {
            $table->ipAddress('ip_address')->nullable();
        });
        // 追記ここまで　ーーーーーーーーーーーーーーーーー
    }

    /**
     * Reverse the migrations.
     *
     * @return void
     */
    public function down()
    {
        // ここから追記　ーーーーーーーーーーーーーーーーー
        Schema::table('articles', function (Blueprint $table) {
            $table->dropColumn('ip_address');
        // 追記ここまで　ーーーーーーーーーーーーーーーーー
        });
    }
}
```

新しく追加する`ip_address`カラムの
カラムタイプには`ipAddress`を指定しており、
またIPアドレスが取得できなかった際にエラーで落ちないように`nullable`もかけています。

参考：[Laravel 6.x データベース：マイグレーション
](https://readouble.com/laravel/6.x/ja/migrations.html)

マイグレーションファイルの編集が完了したら、マイグレーションを実行します。

```
$ php artisan migrate
```

これでDBに`ip_addressカラム`が追加されました。

###Controller側に、IPアドレスを保存する処理を追加

先ほど例に出しました、ArtcleController.phpの一行に追記します。

```ArticleController.php
public function store(ArticleRequest $request, Article $article)
{
    // 投稿をDBに保存
    $user = $request->user();
    $article = $user
                ->articles()
                ->create($request->validated() + ['ip_address' => $request->ip()]); // 取得したIPアドレスを保存するよう修正
    return redirect()->route('articles.index');
}
```

ここでは、DBへの保存処理を行う`create()メソッド`の引数を編集しています。
バリデーション済みの値である、
`$request->validated()`という連想配列に、更に1つ` + 演算子`で連想配列の要素を追加しています。
追加された連想配列が、`['ip_address' => $request->ip()]`です。
`'ip_address'`というキーに、バリューとして取得したIPアドレス`$request->ip()`を対応させています。
（今回、取得したIPアドレスはバリデーションにはかけていません。）



###fillableを追加
最後に、モデルの`Article.php`の`$fillable`に、一行追記します。
（以下のモデルは一例なので、みなさんの環境によって異なると思います。）

```Article.php
<?php

namespace App\Models;

use App\Models\User;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\BelongsTo;
use Illuminate\Database\Eloquent\Relations\BelongsToMany;

class Article extends Model
{
    protected $fillable = [
        'body',
        'user_id',
        'ip_address', // `ip_address`を追加
    ];

// 〜〜〜〜〜〜〜〜〜 略 〜〜〜〜〜〜〜〜〜

}
```

以上で、IPアドレスを取得する機能の実装は完了です！
お疲れ様でした！
これで、アプリ上でユーザー投稿があった時に、そのユーザーのIPアドレスをDBに保存できるようになりました。

##最後に
今回は、Laravelで簡単に投稿者のIPアドレスを取得する方法をご紹介しました。
IPアドレスを取得した先に繋げる迷惑投稿対策としては、

- 特定のIPアドレスにアクセス制限をかける
- 犯罪性の高い悪質な投稿に関しては、プロバイダーに問い合わせる等する

といったものが考えられると思います。

なお、IPアドレス取得機能を実装したアプリを公開する際には、プライバシーポリシー等を作成しておくことが望ましいです。
こちらのサイトで、コピペOKなプライバシーポリシーのテンプレートが公開されているので、ご自身のアプリ用に少し修正したものを作成しておきましょう！
[【コピペOK】ブログのプライバシーポリシー書き方＆設置方法を公開](https://homunclsblog.com/blog-privacy-policy)