Cara mendapatkan alamat IP klien di Laravel 5+

136

Saya mencoba untuk mendapatkan alamat IP klien di Laravel.

Sangat mudah untuk mendapatkan IP klien dalam PHP dengan menggunakan $_SERVER["REMOTE_ADDR"]. Ini berfungsi dengan baik di PHP inti, tetapi ketika saya menggunakan hal yang sama di Laravel, ia mengembalikan server IP bukan IP pengunjung.

Amrinder Singh
sumber

Jawaban:

194

Melihat API Laravel :

Request::ip();

Secara internal, ia menggunakan getClientIpsmetode dari Objek Permintaan Symfony :

public function getClientIps()
{
    $clientIps = array();
    $ip = $this->server->get('REMOTE_ADDR');
    if (!$this->isFromTrustedProxy()) {
        return array($ip);
    }
    if (self::$trustedHeaders[self::HEADER_FORWARDED] && $this->headers->has(self::$trustedHeaders[self::HEADER_FORWARDED])) {
        $forwardedHeader = $this->headers->get(self::$trustedHeaders[self::HEADER_FORWARDED]);
        preg_match_all('{(for)=("?\[?)([a-z0-9\.:_\-/]*)}', $forwardedHeader, $matches);
        $clientIps = $matches[3];
    } elseif (self::$trustedHeaders[self::HEADER_CLIENT_IP] && $this->headers->has(self::$trustedHeaders[self::HEADER_CLIENT_IP])) {
        $clientIps = array_map('trim', explode(',', $this->headers->get(self::$trustedHeaders[self::HEADER_CLIENT_IP])));
    }
    $clientIps[] = $ip; // Complete the IP chain with the IP the request actually came from
    $ip = $clientIps[0]; // Fallback to this when the client IP falls into the range of trusted proxies
    foreach ($clientIps as $key => $clientIp) {
        // Remove port (unfortunately, it does happen)
        if (preg_match('{((?:\d+\.){3}\d+)\:\d+}', $clientIp, $match)) {
            $clientIps[$key] = $clientIp = $match[1];
        }
        if (IpUtils::checkIp($clientIp, self::$trustedProxies)) {
            unset($clientIps[$key]);
        }
    }
    // Now the IP chain contains only untrusted proxies and the client IP
    return $clientIps ? array_reverse($clientIps) : array($ip);
} 
samlev
sumber
3
Menggunakan objek Permintaan tidak berfungsi untuk saya, itu mengembalikan alamat server Homestead saya. 192.168.10.10 yang jelas bukan alamat IP saya.
Vince Kronlein
@VinceKronlein untuk kasus Anda, periksa jawaban ini stackoverflow.com/a/41769505/3437790
Sebastien Horin
3
@VinceKronlein dalam kasus Anda itu sangat benar. Karena Anda mengakses Homestead, di jaringan LOCAL Anda, Anda memiliki 192. IP. jika Anda mengakses server homestead orang lain, melalui internet, IP Anda akan keluar melalui ISP Anda dan publik Anda akan digunakan.
ied3vil
83

Jika Anda berada di bawah penyeimbang beban, Laravel \Request::ip() selalu mengembalikan IP penyeimbang:

            echo $request->ip();
            // server ip

            echo \Request::ip();
            // server ip

            echo \request()->ip();
            // server ip

            echo $this->getIp(); //see the method below
            // clent ip

Metode khusus ini mengembalikan ip klien nyata:

public function getIp(){
    foreach (array('HTTP_CLIENT_IP', 'HTTP_X_FORWARDED_FOR', 'HTTP_X_FORWARDED', 'HTTP_X_CLUSTER_CLIENT_IP', 'HTTP_FORWARDED_FOR', 'HTTP_FORWARDED', 'REMOTE_ADDR') as $key){
        if (array_key_exists($key, $_SERVER) === true){
            foreach (explode(',', $_SERVER[$key]) as $ip){
                $ip = trim($ip); // just to be safe
                if (filter_var($ip, FILTER_VALIDATE_IP, FILTER_FLAG_NO_PRIV_RANGE | FILTER_FLAG_NO_RES_RANGE) !== false){
                    return $ip;
                }
            }
        }
    }
}

Selain itu, saya sarankan Anda untuk sangat berhati-hati menggunakan middleware throttle Laravel : Menggunakan Laravel'sRequest::ip() juga, sehingga semua pengunjung Anda akan diidentifikasi sebagai pengguna yang sama dan Anda akan mencapai batas throttle dengan sangat cepat. Saya mengalami ini langsung dan ini menyebabkan masalah besar.

Untuk memperbaikinya:

Menerangi \ Http \ Request.php

    public function ip()
    {
        //return $this->getClientIp(); //original method
        return $this->getIp(); // the above method
    }

Anda sekarang dapat juga menggunakan Request::ip(), yang seharusnya mengembalikan IP asli dalam produksi.

Sebastien Horin
sumber
1
apakah benar if (filter_var ...) di dalam foreach kedua? kode ini tidak akan pernah dieksekusi.
Mistre83
@ Mistre83 Ya Anda benar, saya pikir ini adalah pengawasan ujian. Saya memperbaruinya!
Sebastien Horin
6
ini benar-benar berfungsi dengan laravel 5.4 Harap pertimbangkan membuat PR di github. Saya pikir ini harus menjadi perilaku default
Crystal
1
Ini bekerja dengan baik di Laravel 5.3 ketika metode objek Laravel meminta ip () terus mengembalikan 127.0.0.1
w5m
3
Tidak bisakah Anda memperbaikinya dengan proksi tepercaya? - laravel.com/docs/master/requests#configuring-trusted-proxies
user2722667
74

Gunakan request()->ip().

Dari apa yang saya mengerti, karena Laravel 5 disarankan / praktik yang baik untuk menggunakan fungsi global seperti:

response()->json($v);
view('path.to.blade');
redirect();
route();
cookie();

Dan, jika ada, ketika menggunakan fungsi bukan notasi statis IDE saya tidak menyala seperti pohon Natal.

Stan Smulders
sumber
3
Anda benar bahwa itu requestadalah fungsi "global" - itu adalah salah satu fungsi pembantu global yang disediakan oleh laravel. Namun, Permintaan fasad, tidak statis (juga bukan metode ip) - request()->foo, dan Reqest::foodan $request->foosemua identik. Lihat intisari ini sebagai contoh: gist.github.com/cjke/026e3036c6a10c672dc5
Chris
1
Cukup adil - keduanya sama-sama benar. Saya hanya berpikir sedikit di mana Anda mengatakan "itu tidak Request::ipmungkin menyesatkan
Chris
3
Masalahnya adalah bahwa fungsi-fungsi global ini tidak mudah diuji — mereka tidak dapat diejek. Fasad bisa jadi. Saya mencoba untuk menghindari fungsi global, karena itu berarti menggali sumber fungsi global untuk mengejek panggilannya, yang merupakan pekerjaan ekstra, menjengkelkan, dan seharusnya tidak menjadi tanggung jawab saya.
hackel
1
Meskipun request()->ip()benar, teks di sekitarnya benar-benar menyesatkan - terutama untuk mengatakan "tidak Request::ip.
Chris
1
@ Chris Terima kasih, Anda memang benar. Diedit untuk kejelasan!
Stan Smulders
27

Tambahkan namespace

use Request;

Kemudian panggil fungsinya

Request::ip();
shalini
sumber
1
Jika Anda menggunakan namespace: -> gunakan Illuminate \ Http \ Request; bold Ganti nama namespace untuk permintaan karena keduanya akan berselisih
shalini
Jawaban aslinya benar. Anda perlu mengimpor use Requestkarena Anda mencoba menggunakan Fasad. Namespace yang Anda berikan adalah untuk kelas yang mendasarinya. Jika Anda mengimpor bahwa Anda akan mendapatkan kesalahan karena ip()tidak dapat dipanggil secara statis, itulah tujuan dari fasad.
jfadich
Jika Anda akan repot-repot mengimpor kelas, Anda harus menggunakan façade yang sebenarnya, bukan alias: use Illuminate\Support\Facades\Request. Jika tidak, gunakan saja \Request::.
retas
18

Untuk Laravel 5 Anda dapat menggunakan objek Permintaan. Sebut saja ip()metodenya, sesuatu seperti:

$request->ip();
Todor Todorov
sumber
16

Dalam Laravel 5

public function index(Request $request) {
  $request->ip();
}
Govind Samrow
sumber
12

Ada dua hal yang harus diperhatikan:

  1. Dapatkan fungsi pembantu yang mengembalikan a Illuminate\Http\Requestdan memanggil ->ip()metode:

    request()->ip();
  2. Pikirkan konfigurasi server Anda, mungkin menggunakan proxy atau load-balancer, terutama dalam konfigurasi AWS ELB.

Jika ini adalah kasus Anda, Anda harus mengikuti " Mengkonfigurasi Proxy Tepercaya " atau bahkan mungkin menyetel opsi "Percayai Semua Proxy".

Mengapa? Karena menjadi server Anda akan mendapatkan proxy / load-balancerIP Anda sebagai gantinya.

Jika Anda berada di loader-AWS, pergi ke App\Http\Middleware\TrustProxiesdan buat $proxiesdeklarasi terlihat seperti ini:

protected $proxies = '*';

Sekarang, uji dan rayakan karena Anda baru saja menyelamatkan diri dari masalah dengan middleware throttle. Itu juga bergantung pada request()->ip()dan tanpa mengatur "TrustProxies", Anda bisa membuat semua pengguna Anda diblokir dari masuk bukannya hanya memblokir IP pelakunya.

Dan karena throttle middleware tidak dijelaskan dengan benar dalam dokumentasi, saya sarankan menonton " tutorial laravel 5.2 untuk pemula, API Rate Limiting "

Diuji dalam Laravel 5.7

Yevgeniy Afanasyev
sumber
7

Di Laravel 5.4 kita tidak bisa memanggil ip static. Ini cara yang benar untuk mendapatkan IP pengguna:

 use Illuminate\Http\Request;

public function contactUS(Request $request)
    {
        echo $request->ip();
        return view('page.contactUS');
    }
Vahid Alvandi
sumber
7

Jika Anda memanggil fungsi ini maka Anda dengan mudah mendapatkan alamat IP klien. Saya sudah menggunakan ini dalam proyek saya yang ada:

public function getUserIpAddr(){
       $ipaddress = '';
       if (isset($_SERVER['HTTP_CLIENT_IP']))
           $ipaddress = $_SERVER['HTTP_CLIENT_IP'];
       else if(isset($_SERVER['HTTP_X_FORWARDED_FOR']))
           $ipaddress = $_SERVER['HTTP_X_FORWARDED_FOR'];
       else if(isset($_SERVER['HTTP_X_FORWARDED']))
           $ipaddress = $_SERVER['HTTP_X_FORWARDED'];
       else if(isset($_SERVER['HTTP_FORWARDED_FOR']))
           $ipaddress = $_SERVER['HTTP_FORWARDED_FOR'];
       else if(isset($_SERVER['HTTP_FORWARDED']))
           $ipaddress = $_SERVER['HTTP_FORWARDED'];
       else if(isset($_SERVER['REMOTE_ADDR']))
           $ipaddress = $_SERVER['REMOTE_ADDR'];
       else
           $ipaddress = 'UNKNOWN';    
       return $ipaddress;
    }
Dev216
sumber
5

Jika Anda masih mendapatkan 127.0.0.1 sebagai IP, Anda perlu menambahkan "proxy" Anda, tetapi perlu diketahui bahwa Anda harus mengubahnya sebelum mulai berproduksi!

Baca " Mengkonfigurasi Proxy Tepercaya ".

Dan tambahkan ini:

class TrustProxies extends Middleware
{
    /**
     * The trusted proxies for this application.
     *
     * @var array
     */
    protected $proxies = '*';

Sekarang request()->ip()memberi Anda IP yang benar.

Shadrix
sumber
4

Jika Anda ingin IP klien dan server Anda berada di belakang aws elb, maka gunakan kode berikut. Diuji untuk laravel 5.3

$elbSubnet = '172.31.0.0/16';
Request::setTrustedProxies([$elbSubnet]);
$clientIp = $request->ip();
Aung Bo
sumber
1
Tidak berfungsi lagi, sekarang "tepercayaHeaderSet" sudah benar
Shadrix
untuk versi laravel "baru", lihat docs laravel.com/docs/5.5/requests#configuring-trusted-proxies
Sandra
0

Jika Anda memiliki beberapa proksi layer seperti CDN + Load Balancer.
Menggunakan fungsi Laravel Request :: ip () akan mendapatkan IP proxy yang paling tepat tetapi bukan IP klien.
Anda dapat mencoba solusi berikut.

app / Http / Middleware / TrustProxies.php

protected $proxies = ['0.0.0.0/0'];

Referensi: https://github.com/fideloper/TrustedProxy/issues/107#issuecomment-373065215

Bing
sumber
0

Saya menggunakan fungsi Sebastien Horin getIp dan request () -> ip () (atas permintaan global), karena untuk localhost fungsi getIp mengembalikan null:

$this->getIp() ?? request()->ip();

Fungsi getIp:

public function getIp(){
foreach (array('HTTP_CLIENT_IP', 'HTTP_X_FORWARDED_FOR', 'HTTP_X_FORWARDED', 'HTTP_X_CLUSTER_CLIENT_IP', 'HTTP_FORWARDED_FOR', 'HTTP_FORWARDED', 'REMOTE_ADDR') as $key){
    if (array_key_exists($key, $_SERVER) === true){
        foreach (explode(',', $_SERVER[$key]) as $ip){
            $ip = trim($ip); // just to be safe
            if (filter_var($ip, FILTER_VALIDATE_IP, FILTER_FLAG_NO_PRIV_RANGE | FILTER_FLAG_NO_RES_RANGE) !== false){
                return $ip;
            }
        }
    }
}

}

pedro.caicedo.la
sumber
-2

Saat kami menginginkan pengguna ip_address:

$_SERVER['REMOTE_ADDR']

dan ingin alamat server:

$_SERVER['SERVER_ADDR']
parmar shashikant
sumber
-2
  $ip = $_SERVER['REMOTE_ADDR'];
ruam
sumber
1
Ini lebih membantu jika Anda memberikan penjelasan mengapa ini adalah solusi yang disukai dan menjelaskan cara kerjanya. Kami ingin mendidik, bukan hanya memberikan kode. Seperti, sistem menandai itu sebagai berkualitas rendah jadi cobalah untuk memperbaikinya.
the Tin Man
Terima kasih atas saranmu.
rashedcs