Suscriber IP address

Rob

Active Member
Hi

I have MW installed beehind a load balancer which uses the X-FORWARDED-FOR Header to pass on the real IP of any traffic.

This is working fine in my apache logs.

However in my customer/lists/xxxxx/subscribers area the IP displayed is the load balancer IP for all subscribers. Where in the code does MW pick up the IP and can it be changed?

Thanks

Rob
 
Hey Rob,

Have a look in apps/common/components/helpers/AppInitHelper.php in the fixRemoteAddress() method.

Thanks.
 
  • Like
Reactions: Rob
Hi

Having searched around to find the best way to do this I came across this article http://stackoverflow.com/questions/...to-retrieve-a-users-correct-ip-address-in-php


I've tried to get this to work within the file you mention but with no luck, how would you insert it if it is possible?
PHP:
/**
  * Retrieves the best guess of the client's actual IP address.
  * Takes into account numerous HTTP proxy headers due to variations
  * in how different ISPs handle IP addresses in headers between hops.
  */
public function get_ip_address() {
  // Check for shared internet/ISP IP
  if (!empty($_SERVER['HTTP_CLIENT_IP']) && $this->validate_ip($_SERVER['HTTP_CLIENT_IP']))
   return $_SERVER['HTTP_CLIENT_IP'];

  // Check for IPs passing through proxies
  if (!empty($_SERVER['HTTP_X_FORWARDED_FOR'])) {
   // Check if multiple IP addresses exist in var
    $iplist = explode(',', $_SERVER['HTTP_X_FORWARDED_FOR']);
    foreach ($iplist as $ip) {
     if ($this->validate_ip($ip))
      return $ip;
    }
   }
  }
  if (!empty($_SERVER['HTTP_X_FORWARDED']) && $this->validate_ip($_SERVER['HTTP_X_FORWARDED']))
   return $_SERVER['HTTP_X_FORWARDED'];
  if (!empty($_SERVER['HTTP_X_CLUSTER_CLIENT_IP']) && $this->validate_ip($_SERVER['HTTP_X_CLUSTER_CLIENT_IP']))
   return $_SERVER['HTTP_X_CLUSTER_CLIENT_IP'];
  if (!empty($_SERVER['HTTP_FORWARDED_FOR']) && $this->validate_ip($_SERVER['HTTP_FORWARDED_FOR']))
   return $_SERVER['HTTP_FORWARDED_FOR'];
  if (!empty($_SERVER['HTTP_FORWARDED']) && $this->validate_ip($_SERVER['HTTP_FORWARDED']))
   return $_SERVER['HTTP_FORWARDED'];

  // Return unreliable IP address since all else failed
  return $_SERVER['REMOTE_ADDR'];
}

/**
  * Ensures an IP address is both a valid IP address and does not fall within
  * a private network range.
  *
  * @access public
  * @param string $ip
  */
public function validate_ip($ip) {
     if (filter_var($ip, FILTER_VALIDATE_IP,
                         FILTER_FLAG_IPV4 |
                         FILTER_FLAG_IPV6 |
                         FILTER_FLAG_NO_PRIV_RANGE |
                         FILTER_FLAG_NO_RES_RANGE) === false)
         return false;
     self::$ip = $ip;
     return true;
}
Cheers

Rob
 
Last edited by a moderator:
How about you try:
PHP:
/**
     * AppInitHelper::fixRemoteAddress()
     *
     * @return
     */
    public static function fixRemoteAddress()
    {
        static $hasRan = false;
        if ($hasRan) {
            return;
        }
        $hasRan = true;
      
        // keep a reference
        $_SERVER['ORIGINAL_REMOTE_ADDR'] = $_SERVER['REMOTE_ADDR'];
      
        $keys = array(
            'HTTP_CF_CONNECTING_IP', 'HTTP_CLIENT_IP', 'HTTP_X_REAL_IP', 'HTTP_X_FORWARDED_FOR',
            'HTTP_X_FORWARDED', 'HTTP_X_CLUSTER_CLIENT_IP', 'HTTP_FORWARDED_FOR', 'HTTP_FORWARDED'
        );
      
        foreach ($keys as $key) {
            if (empty($_SERVER[$key])) {
                continue;
            }
            $ips = explode(',', $_SERVER[$key]);
            foreach ($ips as $ip) {
                if (self::isValidIp($ip)) {
                    return $_SERVER['REMOTE_ADDR'] = $ip;
                }
            }
        }
    }
  
    /**
     * AppInitHelper::isValidIp()
     *
     * @param string $ip
     * @return bool
     */
    public static function isValidIp($ip)
    {
        return filter_var($ip, FILTER_VALIDATE_IP, FILTER_FLAG_IPV4 | FILTER_FLAG_IPV6 | FILTER_FLAG_NO_PRIV_RANGE | FILTER_FLAG_NO_RES_RANGE);
    }
 
  • Like
Reactions: Rob
P.S: In same file, just replace the existing fixRemoteAddress() method with these block of code (this is actually two separate methods)
 
Hi

Thanks for the code, when I use that code I get the following error when going to /customer/campaigns/index

Cheers

Rob

17:23:51.962543 error php
reset() expects parameter 1 to be array, string given
(/var/www/html/apps/common/framework/db/schema/CDbCriteria.php:321)
Stack trace:
#0 /var/www/html/apps/customer/views/campaigns/index.php(95):
Campaign->getGroupsDropDownArray()
#1 /var/www/html/apps/common/framework/web/CBaseController.php(126):
require()
#2 /var/www/html/apps/common/components/web/BaseController.php(245):
CampaignsController->renderInternal()
#3 /var/www/html/apps/common/framework/web/CBaseController.php(95):
CampaignsController->renderInternal()
#4 /var/www/html/apps/common/framework/web/CController.php(869):
CampaignsController->renderFile()
#5 /var/www/html/apps/common/framework/web/CController.php(782):
CampaignsController->renderPartial()
#6 /var/www/html/apps/customer/controllers/CampaignsController.php(66):
CampaignsController->render()
#7 /var/www/html/apps/common/framework/web/actions/CInlineAction.php(49):
CampaignsController->actionIndex()
#8 /var/www/html/apps/common/framework/web/CController.php(308):
CInlineAction->runWithParams()
#9 /var/www/html/apps/common/framework/web/filters/CFilterChain.php(133):
CampaignsController->runAction()
#10 /var/www/html/apps/common/framework/web/CController.php(291):
CFilterChain->run()
#11 /var/www/html/apps/common/framework/web/CController.php(265):
CampaignsController->runActionWithFilters()
#12 /var/www/html/apps/common/framework/web/CWebApplication.php(282):
CampaignsController->run()
#13 /var/www/html/apps/common/framework/web/CWebApplication.php(141):
CWebApplication->runController()
#14 /var/www/html/apps/common/framework/base/CApplication.php(184):
CWebApplication->processRequest()
#15 /var/www/html/apps/init.php(196): CWebApplication->run()
#16 /var/www/html/customer/index.php(18): require_once()
REQUEST_URI=/customer/campaigns/index
in /var/www/html/apps/common/models/Campaign.php (706)
in /var/www/html/apps/customer/views/campaigns/index.php (95)
in /var/www/html/apps/common/components/web/BaseController.php (245)
 
That error isn't actually related to our changes, it's a bug.
here's how that method inside apps/common/models/Campaign.php should look like:
PHP:
public function getGroupsDropDownArray()
    {
        static $_options = array();
        if (!empty($_options)) {
            return $_options;
        }
       
        $criteria = new CDbCriteria();
        $criteria->compare('customer_id', (int)$this->customer_id);
        $criteria->order = 'group_id DESC';
        $models = CampaignGroup::model()->findAll($criteria);
       
        foreach ($models as $model) {
            $criteria = new CDbCriteria();
            $criteria->compare('group_id', (int)$model->group_id);
            $criteria->addNotInCondition('status', array(self::STATUS_PENDING_DELETE));
            $count = Campaign::model()->count($criteria);
           
            $_options[$model->group_id] = $model->name . ' ('. Yii::t('campaigns', '{campaignsCount} campaigns', array(
                '{campaignsCount}' => Yii::app()->format->formatNumber($count)
            )).')';
        }
       
        return $_options;
    }
 
  • Like
Reactions: Rob
Back
Top