Geoip::getRegions()   A
last analyzed

Complexity

Conditions 3
Paths 3

Size

Total Lines 18
Code Lines 10

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 18
rs 9.4285
c 0
b 0
f 0
cc 3
eloc 10
nc 3
nop 0
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
    /**
25
     * @var \GeoIP
26
     */
27
    private $geoip;
28
29
    /**
30
     * @var ServiceManager
31
     */
32
    private $serviceManager;
33
34
    /**
35
     * @var EventManagerInterface
36
     */
37
    private $eventManager;
38
39
    /**
40
     * @var GeoipCoreRecord[]
41
     */
42
    private $records;
43
44
    /**
45
     * @var string|bool
46
     */
47
    private $defaultIp;
48
49
    /**
50
     * @var DatabaseConfig
51
     */
52
    private $config;
53
54
    /**
55
     * @var array
56
     */
57
    private $regions;
58
59
    /**
60
     * Geoip constructor.
61
     * @param ServiceManager $serviceManager
62
     */
63
    public function __construct(ServiceManager $serviceManager)
64
    {
65
        $this->serviceManager = $serviceManager;
66
    }
67
68
    /**
69
     * Destructor
70
     */
71
    public function __destruct()
72
    {
73
        $this->closeGeoip();
74
    }
75
76
    /**
77
     * @return \GeoIP
78
     */
79
    public function getGeoip()
80
    {
81
        if (!$this->geoip) {
82
            $database = $this->getConfig()->getDatabasePath();
83
            if (file_exists($database)) {
84
                $this->geoip = geoip_open($database, $this->getConfig()->getFlag());
85
            } else {
86
                throw new DomainException('You need to download Maxmind database. You can use ZFTool or composer.json for that :)');
87
            }
88
        }
89
        return $this->geoip;
90
    }
91
92
    /**
93
     * @param string $ipAddress
94
     * @return GeoipCoreRecord
95
     */
96
    public function getGeoipRecord($ipAddress)
97
    {
98
        $ipAddress = $this->getIp($ipAddress);
99
100
        if (!isset($this->records[$ipAddress])) {
101
            $this->records[$ipAddress] = GeoIP_record_by_addr($this->getGeoip(), $ipAddress);
102
        }
103
104
        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 104 which is incompatible with the return type documented by ZfSnapGeoip\Service\Geoip::getGeoipRecord of type geoiprecord|null.
Loading history...
105
    }
106
107
    /**
108
     * @param string $ipAddress
109
     * @return string
110
     */
111
    private function getIp($ipAddress)
112
    {
113
        if ($ipAddress === null) {
114
            $ipAddress = $this->getDefaultIp();
115
        }
116
117
        if ($ipAddress instanceof IpAwareInterface) {
118
            $ipAddress = $ipAddress->getIpAddress();
119
        }
120
        $this->getEventManager()->trigger(__FUNCTION__, $this, [
121
            'ip' => $ipAddress,
122
        ]);
123
124
        return $ipAddress;
125
    }
126
127
    /**
128
     * @param string $ipAdress
129
     * @return RecordInterface
130
     */
131
    public function getRecord($ipAdress = null)
132
    {
133
        $record = $this->serviceManager->get('geoip_record');
134
        /* @var $record RecordInterface */
135
136
        if (!$record instanceof RecordInterface) {
137
            throw new DomainException('Incorrect record implementation');
138
        }
139
140
        $geoipRecord = $this->getGeoipRecord($ipAdress);
141
142
        if (!$geoipRecord instanceof GeoipCoreRecord) {
143
            return $record;
144
        }
145
146
        $data = get_object_vars($geoipRecord);
147
        $data['region_name'] = $this->getRegionName($data);
148
149
        $hydrator = $this->serviceManager->get('geoip_hydrator');
150
        /* @var $hydrator \Zend\Stdlib\Hydrator\HydratorInterface */
151
152
        $hydrator->hydrate($data, $record);
153
154
        $this->getEventManager()->trigger(__FUNCTION__, $this, [
155
            'record' => $record,
156
        ]);
157
158
        return $record;
159
    }
160
161
    /**
162
     * @param string $ipAddress
163
     * @return RecordInterface
164
     */
165
    public function lookup($ipAddress = null)
166
    {
167
        return $this->getRecord($ipAddress);
168
    }
169
170
    /**
171
     * @return self
172
     */
173
    private function closeGeoip()
174
    {
175
        if ($this->geoip) {
176
            geoip_close($this->geoip);
177
            $this->geoip = null;
178
        }
179
        return $this;
180
    }
181
182
    /**
183
     * @return array
184
     */
185
    private function getRegions()
186
    {
187
        if ($this->regions === null) {
188
            $regionVarPath = $this->getConfig()->getRegionVarsPath();
189
            include($regionVarPath);
190
191
            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...
192
                throw new DomainException(sprintf('Missing region names data in path %s', $regionVarPath));
193
            }
194
195
            $this->regions = $GEOIP_REGION_NAME;
196
197
            $this->getEventManager()->trigger(__FUNCTION__, $this, [
198
                'regions' => $this->regions,
199
            ]);
200
        }
201
        return $this->regions;
202
    }
203
204
    /**
205
     * @return DatabaseConfig
206
     */
207
    private function getConfig()
208
    {
209
        if ($this->config === null) {
210
            /* @var $config DatabaseConfig */
211
            $config = $this->serviceManager->get('ZfSnapGeoip\DatabaseConfig');
212
            $this->config = $config;
213
        }
214
        return $this->config;
215
    }
216
217
    /**
218
     * @return string|null
219
     */
220
    private function getDefaultIp()
221
    {
222
        if ($this->defaultIp === null) {
223
            $request = $this->serviceManager->get('Request');
224
225
            if ($request instanceof HttpRequest) {
226
                $ipAddress = $request->getServer('REMOTE_ADDR', false);
227
                $this->defaultIp = $ipAddress;
228
            } else {
229
                $this->defaultIp = false;
230
                return null;
231
            }
232
        }
233
        return $this->defaultIp;
234
    }
235
236
    /**
237
     * @param array $data
238
     * @return string
239
     */
240
    private function getRegionName(array $data = [])
241
    {
242
        $regions = $this->getRegions();
243
        $countryCode = isset($data['country_code']) ? $data['country_code'] : null;
244
245
        if (isset($regions[$countryCode])) {
246
            $regionCodes = $regions[$countryCode];
247
            $regionCode = isset($data['region']) ? $data['region'] : null;
248
249
            if (isset($regionCodes[$regionCode])) {
250
                return $regionCodes[$regionCode];
251
            }
252
        }
253
        return null;
254
    }
255
256
    /**
257
     * @return EventManagerInterface
258
     */
259
    public function getEventManager()
260
    {
261
        if ($this->eventManager === null) {
262
            $this->eventManager = new EventManager();
263
        }
264
        return $this->eventManager;
265
    }
266
267
    /**
268
     * @param EventManagerInterface $eventManager
269
     * @return self
270
     */
271
    public function setEventManager(EventManagerInterface $eventManager)
272
    {
273
        $eventManager->setIdentifiers([
274
            __CLASS__,
275
            get_called_class(),
276
        ]);
277
        $this->eventManager = $eventManager;
278
279
        return $this;
280
    }
281
}
282