6

I used the following code:

services:
  foo:
    class: Drupal\MYMODULE\Foo
    arguments: ['@request']

In MYMODULE/src/Foo.php

namespace Drupal\MYMODULE;

use Symfony\Component\HttpFoundation\Request;

class Foo {
  /**
   * @var \Symfony\Component\HttpFoundation\Request
   */
  protected $request;

  /**
   * Constructs a Foo object.
   *
   * @param Symfony\Component\HttpFoundation\Request $request
   *   The request object.
   */
  public function __construct(Request $request) {
    $this->request = $request;
  }

  public function bar() {
    if ($ip == $this->request->getClientIp()) {
      drupal_set_message('ip', t('You may not ban your own IP address.'));
    }
  }

}

but this gives me error:

Symfony\Component\DependencyInjection\Exception\ServiceNotFoundException' with message 'The service "foo" has a dependency on a non-existent service "request".

  • There is no service called @request, you need to use the service called @request_stack, and call getCurrentRequest() on the injected RequestStack object. – phayes Aug 15 '17 at 18:44
14

According to Get the user IP address and Symfony HttpFoundation you can get visitor IP by

first add use Symfony\Component\HttpFoundation; then

 \Drupal::request()->getClientIp()
  • 2
    With DI in the class, you would get the request from the RequestStack, which is available as a service. – mpdonadio Sep 23 '16 at 23:44
  • It's better to use service injection instead of relying on the global \Drupal object. See more details in my answer below. – phayes Aug 15 '17 at 18:45
4

The correct way to do this is via service injection. This way your class is unit testable.

In your mymodule.services.yml file:

services:
  foo:
    class: Drupal\MYMODULE\Foo
    arguments: ['@request_stack']

In your class:

namespace Drupal\MYMODULE;

use Symfony\Component\HttpFoundation\RequestStack;    

class Foo {
  /**
   * @var \Symfony\Component\HttpFoundation\Request
   */
  protected $request;

  /**
   * Constructs a Foo object.
   *
   * @param Symfony\Component\HttpFoundation\RequestStack $request_stack
   *   The request stack object.
   */
  public function __construct(RequestStack $request_stack) {
    $this->request = $request_stack->getCurrentRequest();
  }

  public function bar() {
    $ip == $this->request->getClientIp();

    // Do something with $ip, just return it back as an exampe.
    return $ip;
  }

}

In your test file:

namespace Drupal\Tests\MYMODULE\Unit;

use Drupal\MYMODULE\Foo;
use Drupal\Tests\UnitTestCase;
use Prophecy\Argument;

class FooTest extends UnitTestCase {

  public function testBar() {
    $request = $this->prophesize('\Symfony\Component\HttpFoundation\Request');
    $request->getClientIp()->willReturn('123.123.123.123');
    $request = $request->reveal();

    $request_stack = $this->prophesize('\Symfony\Component\HttpFoundation\RequestStack');
    $request_stack->getCurrentRequest()->willReturn($request);
    $request_stack = $request_stack->reveal();

    $foo = new Foo($request_stack);

    $this->assertEquals($foo->bar(), '123.123.123.123');
  }
}
1

What does the error you received tell you? It tells you that the service request does not exist. You can look/discover requests loaded by core reading the core.services.yml file, and discover something similar, a service called request_stack.

The request_stack service provides Symfony\Component\HttpFoundation\RequestStack with which you can get the current request. The static \Drupal::request is an example implementation of getting the current request.

  public function __construct(RequestStack $requestStack) {
    $this->request = $requestStack->getCurrentRequest();
  }

  public function bar() {
    if ($ip == $this->request->getClientIp()) {
      drupal_set_message('ip', t('You may not ban your own IP address.'));
    }
  }
  • Almost correct, but by assinging the request in the constructor, you're defeating the whole point of why request_stack exists :) The current request can change (sub requests and stuff like that). Always assing the request stack and get the request when you actually need it. – Berdir Sep 7 '16 at 18:07
  • I have used exactly same code now and page gives "The drupal-8 page isn’t working drupal-8 is currently unable to handle this request. HTTP ERROR 500" without any error in log messages. Whenever i call this bar function inside any file. – neha Sep 7 '16 at 18:31
0

Following code worked for me:

use Symfony\Component\HttpFoundation;
$ip_address = Drupal::request()->getClientIp();
-1

If you want to show the ip in twig:

Suppose you want to get the ip in the page.html.twig file.

in your

YOURTHEME.theme

you can try

use Symfony\Component\HttpFoundation;

function YOURTHEME_preprocess_page(&$variables) {
  $variables['page']['ip'] = \Drupal::request()->getClientIp();

}

in your template

page.html.twig

you can try:

{{ page.ip }}
  • This won’t work, as the code in preprocess functions is going to be cached until you flush the cache the next time. – leymannx Dec 20 '18 at 2:20
-1

I make the following module for get ip address of visitors

create following route custom_location/custom_location.info.yml and following info

name: Custom Location
description: Custom Location.
package: Custom
type: module
version: 1.0
core: 8.x

custom_location/custom_location.links.menu.yml

location.admin:
  title: 'Location module settings'
  description: 'location'
  parent: system.admin_config_development
  route_name: location.content
  weight: 100

custom_location/custom_location.routing.yml

location.content:
  path: '/location'
  defaults:
    _controller: '\Drupal\custom_location\Controller\CustomLocation::content'
    _title: 'Ip Table'
  requirements:
    _permission: 'access content'

in the route custom_location/src/Controller/CustomLocation.php

<?php
/**
 * @file
 * Contains \Drupal\custom_location\Controller\CustomLocation.
 */
namespace Drupal\custom_location\Controller;
use Symfony\Component\HttpFoundation;
use Symfony\Component\HttpFoundation\RequestStack;

class CustomLocation {
  public function content() {
    $ip_address = \Drupal::request()->getClientIp();
    $html = $ip_address;
    return array(
      '#type' => 'markup',
      '#markup' => $html,
    );
  }
}

and visit in your path your location in /location and ready appear the ip

  • There are already answers showing how to get the IP from a controller, so this answer doesn't add anything to what the other answers already say. \Drupal should never be used in a controller class, though. It is also probable the output is going to be wrongly cached, without using cache tags or cache contexts. – kiamlaluno Dec 21 '18 at 7:59
  • oh yes you try the module, without \Drupal no working – jonathan Dec 21 '18 at 15:33
  • See this answer, which doesn't use \Drupal but correctly uses dependency injection. – kiamlaluno Dec 21 '18 at 16:38

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.