Completed
Push — master ( ccba76...bda572 )
by Witold
06:38
created

Geoip::getIp()   A

Complexity

Conditions 3
Paths 4

Size

Total Lines 15
Code Lines 8

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 15
rs 9.4285
c 0
b 0
f 0
cc 3
eloc 8
nc 4
nop 1
1
<?php
2
3
namespace ZfSnapGeoip\Service;
4
5
use ZfSnapGeoip\DatabaseConfig;
6
use ZfSnapGeoip\Entity\RecordInterface;
7
use ZfSnapGeoip\Exception\DomainException;
8
use ZfSnapGeoip\IpAwareInterface;
9
use Zend\EventManager\EventManagerAwareInterface;
10
use Zend\EventManager\EventManagerInterface;
11
use Zend\EventManager\EventManager;
12
use Zend\Http\PhpEnvironment\Request as HttpRequest;
13
use Zend\ServiceManager\ServiceManager;
14
use geoiprecord as GeoipCoreRecord;
15
16
/**
17
 * Geoip Service
18
 *
19
 * @author Witold Wasiczko <[email protected]>
20
 */
21
class Geoip implements EventManagerAwareInterface
22
{
23
    /**
24
     * @var \GeoIP
25
     */
26
    private $geoip;
27
28
    /**
29
     * @var ServiceManager
30
     */
31
    private $serviceManager;
32
33
    /**
34
     * @var EventManagerInterface
35
     */
36
    private $eventManager;
37
38
    /**
39
     * @var GeoipCoreRecord[]
40
     */
41
    private $records;
42
43
    /**
44
     * @var string|bool
45
     */
46
    private $defaultIp;
47
48
    /**
49
     * @var DatabaseConfig
50
     */
51
    private $config;
52
53
    /**
54
     * @var array
55
     */
56
    private $regions;
57
58
    /**
59
     * Geoip constructor.
60
     * @param ServiceManager $serviceManager
61
     */
62
    public function __construct(ServiceManager $serviceManager)
63
    {
64
        $this->serviceManager = $serviceManager;
65
    }
66
67
    /**
68
     * Destructor
69
     */
70
    public function __destruct()
71
    {
72
        $this->closeGeoip();
73
    }
74
75
    /**
76
     * @return \GeoIP
77
     */
78
    public function getGeoip()
79
    {
80
        if (!$this->geoip) {
81
            $database = $this->getConfig()->getDatabasePath();
82
            if (file_exists($database)) {
83
                $this->geoip = geoip_open($database, $this->getConfig()->getFlag());
84
            } else {
85
                throw new DomainException('You need to download Maxmind database. You can use ZFTool or composer.json for that :)');
86
            }
87
        }
88
        return $this->geoip;
89
    }
90
91
    /**
92
     * @param string $ipAddress
93
     * @return GeoipCoreRecord
94
     */
95
    public function getGeoipRecord($ipAddress)
96
    {
97
        $ipAddress = $this->getIp($ipAddress);
98
99
        if (!isset($this->records[$ipAddress])) {
100
            $this->records[$ipAddress] = GeoIP_record_by_addr($this->getGeoip(), $ipAddress);
101
        }
102
103
        return $this->records[$ipAddress];
0 ignored issues
show
Bug Compatibility introduced by
The expression $this->records[$ipAddress]; of type integer|null|geoiprecord adds the type integer to the return on line 103 which is incompatible with the return type documented by ZfSnapGeoip\Service\Geoip::getGeoipRecord of type geoiprecord|null.
Loading history...
104
    }
105
106
    /**
107
     * @param string $ipAddress
108
     * @return string
109
     */
110
    private function getIp($ipAddress)
111
    {
112
        if ($ipAddress === null) {
113
            $ipAddress = $this->getDefaultIp();
114
        }
115
116
        if ($ipAddress instanceof IpAwareInterface) {
117
            $ipAddress = $ipAddress->getIpAddress();
118
        }
119
        $this->getEventManager()->trigger(__FUNCTION__, $this, array(
120
            'ip' => $ipAddress,
121
        ));
122
123
        return $ipAddress;
124
    }
125
126
    /**
127
     * @param string $ipAdress
128
     * @return RecordInterface
129
     */
130
    public function getRecord($ipAdress = null)
131
    {
132
        $record = $this->serviceManager->get('geoip_record');
133
        /* @var $record RecordInterface */
134
135
        if (!$record instanceof RecordInterface) {
136
            throw new DomainException('Incorrect record implementation');
137
        }
138
139
        $geoipRecord = $this->getGeoipRecord($ipAdress);
140
141
        if (!$geoipRecord instanceof GeoipCoreRecord) {
142
            return $record;
143
        }
144
145
        $data = get_object_vars($geoipRecord);
146
        $data['region_name'] = $this->getRegionName($data);
147
148
        $hydrator = $this->serviceManager->get('geoip_hydrator');
149
        /* @var $hydrator \Zend\Stdlib\Hydrator\HydratorInterface */
150
151
        $hydrator->hydrate($data, $record);
152
153
        $this->getEventManager()->trigger(__FUNCTION__, $this, array(
154
            'record' => $record,
155
        ));
156
157
        return $record;
158
    }
159
160
    /**
161
     * @param string $ipAddress
162
     * @return RecordInterface
163
     */
164
    public function lookup($ipAddress = null)
165
    {
166
        return $this->getRecord($ipAddress);
167
    }
168
169
    /**
170
     * @return self
171
     */
172
    private function closeGeoip()
173
    {
174
        if ($this->geoip) {
175
            geoip_close($this->geoip);
176
            $this->geoip = null;
177
        }
178
        return $this;
179
    }
180
181
    /**
182
     * @return array
183
     */
184
    private function getRegions()
185
    {
186
        if ($this->regions === null) {
187
            $regionVarPath = $this->getConfig()->getRegionVarsPath();
188
            include($regionVarPath);
189
190
            if (!isset($GEOIP_REGION_NAME)) {
0 ignored issues
show
Bug introduced by
The variable $GEOIP_REGION_NAME seems to never exist, and therefore isset should always return false. Did you maybe rename this variable?

This check looks for calls to isset(...) or empty() on variables that are yet undefined. These calls will always produce the same result and can be removed.

This is most likely caused by the renaming of a variable or the removal of a function/method parameter.

Loading history...
191
                throw new DomainException(sprintf('Missing region names data in path %s', $regionVarPath));
192
            }
193
194
            $this->regions = $GEOIP_REGION_NAME;
195
196
            $this->getEventManager()->trigger(__FUNCTION__, $this, array(
197
                'regions' => $this->regions,
198
            ));
199
        }
200
        return $this->regions;
201
    }
202
203
    /**
204
     * @return DatabaseConfig
205
     */
206
    private function getConfig()
207
    {
208
        if ($this->config === null) {
209
            /* @var $config DatabaseConfig */
210
            $config = $this->serviceManager->get('ZfSnapGeoip\DatabaseConfig');
211
            $this->config = $config;
212
        }
213
        return $this->config;
214
    }
215
216
    /**
217
     * @return string|null
218
     */
219
    private function getDefaultIp()
220
    {
221
        if ($this->defaultIp === null) {
222
            $request = $this->serviceManager->get('Request');
223
224
            if ($request instanceof HttpRequest) {
225
                $ipAddress = $request->getServer('REMOTE_ADDR', false);
226
                $this->defaultIp = $ipAddress;
227
            } else {
228
                $this->defaultIp = false;
229
                return null;
230
            }
231
        }
232
        return $this->defaultIp;
233
    }
234
235
    /**
236
     * @param array $data
237
     * @return string
238
     */
239
    private function getRegionName(array $data = array())
240
    {
241
        $regions = $this->getRegions();
242
        $countryCode = isset($data['country_code']) ? $data['country_code'] : null;
243
244
        if (isset($regions[$countryCode])) {
245
            $regionCodes = $regions[$countryCode];
246
            $regionCode = isset($data['region']) ? $data['region'] : null;
247
248
            if (isset($regionCodes[$regionCode])) {
249
                return $regionCodes[$regionCode];
250
            }
251
        }
252
        return null;
253
    }
254
255
    /**
256
     * @return EventManagerInterface
257
     */
258
    public function getEventManager()
259
    {
260
        if ($this->eventManager === null) {
261
            $this->eventManager = new EventManager();
262
        }
263
        return $this->eventManager;
264
    }
265
266
    /**
267
     * @param EventManagerInterface $eventManager
268
     * @return self
269
     */
270
    public function setEventManager(EventManagerInterface $eventManager)
271
    {
272
        $eventManager->setIdentifiers(array(
273
            __CLASS__,
274
            get_called_class(),
275
        ));
276
        $this->eventManager = $eventManager;
277
278
        return $this;
279
    }
280
281
}
282