namespace BitFrame\Locale;
use \Psr\Http\Message\ServerRequestInterface;
use \Psr\Http\Message\ResponseInterface;
use \Psr\Http\Server\RequestHandlerInterface;
// implements:
use \Psr\Http\Server\MiddlewareInterface;
// uses:
use \BitFrame\Delegate\CallableMiddlewareTrait;
use \BitFrame\Locale\GeoLocationTrait;
/**
* Geo Location wrapper class to fetch user geo
* data as a middleware.
*/
class GeoLocation implements MiddlewareInterface
{
use CallableMiddlewareTrait;
use GeoLocationTrait;
/** @var bool */
private $remoteIpLookup;
/**
* @param bool $remoteIpLookup (optional, default: false
)
*/
public function __construct(
// if true, ip address is looked up
// via a remote service
$remoteIpLookup = false
);
/**
* Process an incoming server request and return a
* response, optionally delegating response creation
* to a handler.
*
* @param ServerRequestInterface $request
* @param RequestHandlerInterface $handler
*
* @return ResponseInterface
*/
public function process(
// http request to process
ServerRequestInterface $request,
// http request handler object
RequestHandlerInterface $handler
): ResponseInterface;
/**
* Set setting that determines whether IP
* will be looked up via an online service or not.
*
* This may especially be useful when using
* this on localhost.
*
* @return bool
*/
public function setRemoteIpLookup(
// if true, ip address is looked up
// via a remote service
bool $remoteIpLookup
): self;
/**
* Get remote ip lookup setting.
*
* @return bool
*/
public function getRemoteIpLookup(): bool;
}
namespace BitFrame\Locale;
// extends:
use \BitFrame\Data\ApplicationData
// exceptions:
use \BadMethodCallException;
/**
* Stores geo location data.
*/
class GeoLocationData extends ApplicationData
{
/**
* Store the specified data.
*
* Note that this specific implementation
* makes setting data method immutable.
*
* @see: ApplicationData::offsetSet()
*
* @throws BadMethodCallException
*/
public function offsetSet(
// key to identify the $value in store
$key,
// value to store
$value
);
/**
* Remove the data by the specified key.
*
* Note that this specific implementation
* makes unsetting data method immutable.
*
* @see: ApplicationData::offsetUnset()
*
* @throws BadMethodCallException
*/
public function offsetUnset(
// key to unset data for
$key
);
}
namespace BitFrame\Locale;
use \Psr\Http\Message\ServerRequestInterface;
use \Geocoder\Query\GeocodeQuery;
use \Geocoder\Provider\Provider;
use \Geocoder\Provider\Chain\Chain;
use \Geocoder\Provider\FreeGeoIp\FreeGeoIp;
use \Geocoder\Provider\GeoPlugin\GeoPlugin;
use \Geocoder\Collection;
// uses:
use \BitFrame\Locale\RemoteAddressTrait;
// exceptions:
use \InvalidArgumentException;
use \BitFrame\Locale\Exception\IpAddressNotFoundException;
/**
* Common wrapper for the Geocoder plugin.
*/
trait GeoLocationTrait
{
use RemoteAddressTrait;
/** @var Provider */
private $provider;
/**
* Set Geocoder Provider.
*
* @param Provider|array $provider
*
* @return $this
*
* @throws InvalidArgumentException
*/
public function setProvider(
// geocoder provider
$provider
): self;
/**
* Get Geocoder Provider (sets a default provider
* if no provider available).
*
* @return Provider
*/
public function getProvider(): Provider;
/**
* Get location data.
*
* @param ServerRequestInterface $request
* @param string $ip
*
* @return Collection
*
* @throws IpAddressNotFoundException
* @throws InvalidArgumentException
*/
public function getGeoLocationData(
// http request object
ServerRequestInterface $request,
// ip address to get location data for
string $ip
): Collection;
}
namespace BitFrame\Locale;
use \Psr\Http\Message\ServerRequestInterface;
/**
* Get user ip.
*/
trait RemoteAddressTrait
{
/** @var bool */
private $useProxy = false;
/** @var array */
private $trustedProxies = [];
/** @var array */
private $proxyHeader = [
'Forwarded',
'Forwarded-For',
'X-Forwarded',
'X-Forwarded-For',
'X-Cluster-Client-Ip',
'Client-Ip'
];
/** @var string */
private $remoteAddr = 'https://api.ipify.org/?format=text';
/**
* Changes proxy handling setting which
* determines whether to use proxy addresses
* or not.
*
* By default this setting is disabled - IP
* address is mostly needed to increase security.
* HTTP_* are not reliable since can easily be
* spoofed. Enabling this setting can provide more
* flexibility, but if user uses proxy to connect
* to trusted services it's their own risk; the only
* reliable field for IP address is
* `$_SERVER['REMOTE_ADDR']`.
*
* @param bool $useProxy (optional, default: true
)
*
* @return $this
*/
public function setUseProxy(
// check for proxied ip addresses?
bool $useProxy = true
): self;
/**
* Checks proxy handling setting.
*
* @return bool
*/
public function isUseProxy(): bool;
/**
* Set list of trusted proxy addresses.
*
* @param string[] $trustedProxies
*
* @return $this
*/
public function setTrustedProxies(
// list of trusted proxy addresses
array $trustedProxies
): self;
/**
* Get list of trusted proxy IP addresses.
*
* @return string[]
*/
public function getTrustedProxies(): array;
/**
* Set the header to introspect for proxy IPs.
*
* @param string[] $header (optional, default: [
* 'Forwarded',
* 'Forwarded-For',
* 'X-Forwarded',
* 'X-Forwarded-For',
* 'X-Cluster-Client-Ip',
* 'Client-Ip'
* ])
*
* @return $this
*/
public function setProxyHeader(
// list of headers to introspect for proxied ip
array $header = [
'Forwarded',
'Forwarded-For',
'X-Forwarded',
'X-Forwarded-For',
'X-Cluster-Client-Ip',
'Client-Ip'
]
): self;
/**
* Get HTTP headers to introspect for proxies.
*
* @return string[]
*/
public function getProxyHeader(): array;
/**
* Set the remote address from where the ip will be
* looked up.
*
* @param string $addr
*
* @return $this
*/
public function setRemoteAddr(
// ip address lookup service url
string $addr
): self;
/**
* Get the remote address from where the ip will be looked up.
*
* @return string
*/
public function getRemoteAddr(): string;
/**
* Returns client IP address.
*
* @param ServerRequestInterface $request
* @param bool $remoteLookup (optional, default: false
)
*
* @return string
*/
public function getIpAddress(
// http request object
ServerRequestInterface $request,
// if true, ip is looked up from a remote service
// as specified in `$this->$remoteAddr` (which
// can be set via `$this->setRemoteAddr()`)
bool $remoteLookup = false
): string;
/**
* Returns the IP address from remote service.
*
* @return string|null
*/
private function getRemoteIp(): ?string;
/**
* Attempt to get the IP address for a proxied client
*
* @param ServerRequestInterface $request
*
* @return string|null
*
* @see IETF HTTP Forwarded For Draft
*/
private function getProxiedIp(
// http request object
ServerRequestInterface $request
): ?string;
/**
* Returns the remote address of the request, if valid.
*
* @param ServerRequestInterface $request
*
* @return string|null
*/
private function getLocalIp(
// http request object
ServerRequestInterface $request
): ?string;
/**
* Normalize a header string.
*
* Normalizes a header string to a format that is
* compatible with $_SERVER.
*
* @param string $header
*
* @return string
*/
private function normalizeProxyHeader(
// header to normalize
string $header
): string;
/**
* Check that a given string is a valid IP address.
*
* @param string $ip
*
* @return bool
*/
private function isIpValid(
// ip address to validate
$ip
): bool;
}
namespace BitFrame\Locale\Exception;
// extends:
use \BitFrame\Exception\HttpException
/**
* IP Address not found error.
*/
class IpAddressNotFoundException extends HttpException
{
}