acf
This commit is contained in:
25
plugins/system/tgeoip/vendor/autoload.php
vendored
Normal file
25
plugins/system/tgeoip/vendor/autoload.php
vendored
Normal file
@ -0,0 +1,25 @@
|
||||
<?php
|
||||
|
||||
// autoload.php @generated by Composer
|
||||
|
||||
if (PHP_VERSION_ID < 50600) {
|
||||
if (!headers_sent()) {
|
||||
header('HTTP/1.1 500 Internal Server Error');
|
||||
}
|
||||
$err = 'Composer 2.3.0 dropped support for autoloading on PHP <5.6 and you are running '.PHP_VERSION.', please upgrade PHP or use Composer 2.2 LTS via "composer self-update --2.2". Aborting.'.PHP_EOL;
|
||||
if (!ini_get('display_errors')) {
|
||||
if (PHP_SAPI === 'cli' || PHP_SAPI === 'phpdbg') {
|
||||
fwrite(STDERR, $err);
|
||||
} elseif (!headers_sent()) {
|
||||
echo $err;
|
||||
}
|
||||
}
|
||||
trigger_error(
|
||||
$err,
|
||||
E_USER_ERROR
|
||||
);
|
||||
}
|
||||
|
||||
require_once __DIR__ . '/composer/autoload_real.php';
|
||||
|
||||
return ComposerAutoloaderInit087ac1c88c9dd7b872309175c7c60d7d::getLoader();
|
||||
579
plugins/system/tgeoip/vendor/composer/ClassLoader.php
vendored
Normal file
579
plugins/system/tgeoip/vendor/composer/ClassLoader.php
vendored
Normal file
@ -0,0 +1,579 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of Composer.
|
||||
*
|
||||
* (c) Nils Adermann <naderman@naderman.de>
|
||||
* Jordi Boggiano <j.boggiano@seld.be>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Composer\Autoload;
|
||||
|
||||
/**
|
||||
* ClassLoader implements a PSR-0, PSR-4 and classmap class loader.
|
||||
*
|
||||
* $loader = new \Composer\Autoload\ClassLoader();
|
||||
*
|
||||
* // register classes with namespaces
|
||||
* $loader->add('Symfony\Component', __DIR__.'/component');
|
||||
* $loader->add('Symfony', __DIR__.'/framework');
|
||||
*
|
||||
* // activate the autoloader
|
||||
* $loader->register();
|
||||
*
|
||||
* // to enable searching the include path (eg. for PEAR packages)
|
||||
* $loader->setUseIncludePath(true);
|
||||
*
|
||||
* In this example, if you try to use a class in the Symfony\Component
|
||||
* namespace or one of its children (Symfony\Component\Console for instance),
|
||||
* the autoloader will first look for the class under the component/
|
||||
* directory, and it will then fallback to the framework/ directory if not
|
||||
* found before giving up.
|
||||
*
|
||||
* This class is loosely based on the Symfony UniversalClassLoader.
|
||||
*
|
||||
* @author Fabien Potencier <fabien@symfony.com>
|
||||
* @author Jordi Boggiano <j.boggiano@seld.be>
|
||||
* @see https://www.php-fig.org/psr/psr-0/
|
||||
* @see https://www.php-fig.org/psr/psr-4/
|
||||
*/
|
||||
class ClassLoader
|
||||
{
|
||||
/** @var \Closure(string):void */
|
||||
private static $includeFile;
|
||||
|
||||
/** @var string|null */
|
||||
private $vendorDir;
|
||||
|
||||
// PSR-4
|
||||
/**
|
||||
* @var array<string, array<string, int>>
|
||||
*/
|
||||
private $prefixLengthsPsr4 = array();
|
||||
/**
|
||||
* @var array<string, list<string>>
|
||||
*/
|
||||
private $prefixDirsPsr4 = array();
|
||||
/**
|
||||
* @var list<string>
|
||||
*/
|
||||
private $fallbackDirsPsr4 = array();
|
||||
|
||||
// PSR-0
|
||||
/**
|
||||
* List of PSR-0 prefixes
|
||||
*
|
||||
* Structured as array('F (first letter)' => array('Foo\Bar (full prefix)' => array('path', 'path2')))
|
||||
*
|
||||
* @var array<string, array<string, list<string>>>
|
||||
*/
|
||||
private $prefixesPsr0 = array();
|
||||
/**
|
||||
* @var list<string>
|
||||
*/
|
||||
private $fallbackDirsPsr0 = array();
|
||||
|
||||
/** @var bool */
|
||||
private $useIncludePath = false;
|
||||
|
||||
/**
|
||||
* @var array<string, string>
|
||||
*/
|
||||
private $classMap = array();
|
||||
|
||||
/** @var bool */
|
||||
private $classMapAuthoritative = false;
|
||||
|
||||
/**
|
||||
* @var array<string, bool>
|
||||
*/
|
||||
private $missingClasses = array();
|
||||
|
||||
/** @var string|null */
|
||||
private $apcuPrefix;
|
||||
|
||||
/**
|
||||
* @var array<string, self>
|
||||
*/
|
||||
private static $registeredLoaders = array();
|
||||
|
||||
/**
|
||||
* @param string|null $vendorDir
|
||||
*/
|
||||
public function __construct($vendorDir = null)
|
||||
{
|
||||
$this->vendorDir = $vendorDir;
|
||||
self::initializeIncludeClosure();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array<string, list<string>>
|
||||
*/
|
||||
public function getPrefixes()
|
||||
{
|
||||
if (!empty($this->prefixesPsr0)) {
|
||||
return call_user_func_array('array_merge', array_values($this->prefixesPsr0));
|
||||
}
|
||||
|
||||
return array();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array<string, list<string>>
|
||||
*/
|
||||
public function getPrefixesPsr4()
|
||||
{
|
||||
return $this->prefixDirsPsr4;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return list<string>
|
||||
*/
|
||||
public function getFallbackDirs()
|
||||
{
|
||||
return $this->fallbackDirsPsr0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return list<string>
|
||||
*/
|
||||
public function getFallbackDirsPsr4()
|
||||
{
|
||||
return $this->fallbackDirsPsr4;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array<string, string> Array of classname => path
|
||||
*/
|
||||
public function getClassMap()
|
||||
{
|
||||
return $this->classMap;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array<string, string> $classMap Class to filename map
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function addClassMap(array $classMap)
|
||||
{
|
||||
if ($this->classMap) {
|
||||
$this->classMap = array_merge($this->classMap, $classMap);
|
||||
} else {
|
||||
$this->classMap = $classMap;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Registers a set of PSR-0 directories for a given prefix, either
|
||||
* appending or prepending to the ones previously set for this prefix.
|
||||
*
|
||||
* @param string $prefix The prefix
|
||||
* @param list<string>|string $paths The PSR-0 root directories
|
||||
* @param bool $prepend Whether to prepend the directories
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function add($prefix, $paths, $prepend = false)
|
||||
{
|
||||
$paths = (array) $paths;
|
||||
if (!$prefix) {
|
||||
if ($prepend) {
|
||||
$this->fallbackDirsPsr0 = array_merge(
|
||||
$paths,
|
||||
$this->fallbackDirsPsr0
|
||||
);
|
||||
} else {
|
||||
$this->fallbackDirsPsr0 = array_merge(
|
||||
$this->fallbackDirsPsr0,
|
||||
$paths
|
||||
);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
$first = $prefix[0];
|
||||
if (!isset($this->prefixesPsr0[$first][$prefix])) {
|
||||
$this->prefixesPsr0[$first][$prefix] = $paths;
|
||||
|
||||
return;
|
||||
}
|
||||
if ($prepend) {
|
||||
$this->prefixesPsr0[$first][$prefix] = array_merge(
|
||||
$paths,
|
||||
$this->prefixesPsr0[$first][$prefix]
|
||||
);
|
||||
} else {
|
||||
$this->prefixesPsr0[$first][$prefix] = array_merge(
|
||||
$this->prefixesPsr0[$first][$prefix],
|
||||
$paths
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Registers a set of PSR-4 directories for a given namespace, either
|
||||
* appending or prepending to the ones previously set for this namespace.
|
||||
*
|
||||
* @param string $prefix The prefix/namespace, with trailing '\\'
|
||||
* @param list<string>|string $paths The PSR-4 base directories
|
||||
* @param bool $prepend Whether to prepend the directories
|
||||
*
|
||||
* @throws \InvalidArgumentException
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function addPsr4($prefix, $paths, $prepend = false)
|
||||
{
|
||||
$paths = (array) $paths;
|
||||
if (!$prefix) {
|
||||
// Register directories for the root namespace.
|
||||
if ($prepend) {
|
||||
$this->fallbackDirsPsr4 = array_merge(
|
||||
$paths,
|
||||
$this->fallbackDirsPsr4
|
||||
);
|
||||
} else {
|
||||
$this->fallbackDirsPsr4 = array_merge(
|
||||
$this->fallbackDirsPsr4,
|
||||
$paths
|
||||
);
|
||||
}
|
||||
} elseif (!isset($this->prefixDirsPsr4[$prefix])) {
|
||||
// Register directories for a new namespace.
|
||||
$length = strlen($prefix);
|
||||
if ('\\' !== $prefix[$length - 1]) {
|
||||
throw new \InvalidArgumentException("A non-empty PSR-4 prefix must end with a namespace separator.");
|
||||
}
|
||||
$this->prefixLengthsPsr4[$prefix[0]][$prefix] = $length;
|
||||
$this->prefixDirsPsr4[$prefix] = $paths;
|
||||
} elseif ($prepend) {
|
||||
// Prepend directories for an already registered namespace.
|
||||
$this->prefixDirsPsr4[$prefix] = array_merge(
|
||||
$paths,
|
||||
$this->prefixDirsPsr4[$prefix]
|
||||
);
|
||||
} else {
|
||||
// Append directories for an already registered namespace.
|
||||
$this->prefixDirsPsr4[$prefix] = array_merge(
|
||||
$this->prefixDirsPsr4[$prefix],
|
||||
$paths
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Registers a set of PSR-0 directories for a given prefix,
|
||||
* replacing any others previously set for this prefix.
|
||||
*
|
||||
* @param string $prefix The prefix
|
||||
* @param list<string>|string $paths The PSR-0 base directories
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function set($prefix, $paths)
|
||||
{
|
||||
if (!$prefix) {
|
||||
$this->fallbackDirsPsr0 = (array) $paths;
|
||||
} else {
|
||||
$this->prefixesPsr0[$prefix[0]][$prefix] = (array) $paths;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Registers a set of PSR-4 directories for a given namespace,
|
||||
* replacing any others previously set for this namespace.
|
||||
*
|
||||
* @param string $prefix The prefix/namespace, with trailing '\\'
|
||||
* @param list<string>|string $paths The PSR-4 base directories
|
||||
*
|
||||
* @throws \InvalidArgumentException
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function setPsr4($prefix, $paths)
|
||||
{
|
||||
if (!$prefix) {
|
||||
$this->fallbackDirsPsr4 = (array) $paths;
|
||||
} else {
|
||||
$length = strlen($prefix);
|
||||
if ('\\' !== $prefix[$length - 1]) {
|
||||
throw new \InvalidArgumentException("A non-empty PSR-4 prefix must end with a namespace separator.");
|
||||
}
|
||||
$this->prefixLengthsPsr4[$prefix[0]][$prefix] = $length;
|
||||
$this->prefixDirsPsr4[$prefix] = (array) $paths;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Turns on searching the include path for class files.
|
||||
*
|
||||
* @param bool $useIncludePath
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function setUseIncludePath($useIncludePath)
|
||||
{
|
||||
$this->useIncludePath = $useIncludePath;
|
||||
}
|
||||
|
||||
/**
|
||||
* Can be used to check if the autoloader uses the include path to check
|
||||
* for classes.
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function getUseIncludePath()
|
||||
{
|
||||
return $this->useIncludePath;
|
||||
}
|
||||
|
||||
/**
|
||||
* Turns off searching the prefix and fallback directories for classes
|
||||
* that have not been registered with the class map.
|
||||
*
|
||||
* @param bool $classMapAuthoritative
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function setClassMapAuthoritative($classMapAuthoritative)
|
||||
{
|
||||
$this->classMapAuthoritative = $classMapAuthoritative;
|
||||
}
|
||||
|
||||
/**
|
||||
* Should class lookup fail if not found in the current class map?
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function isClassMapAuthoritative()
|
||||
{
|
||||
return $this->classMapAuthoritative;
|
||||
}
|
||||
|
||||
/**
|
||||
* APCu prefix to use to cache found/not-found classes, if the extension is enabled.
|
||||
*
|
||||
* @param string|null $apcuPrefix
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function setApcuPrefix($apcuPrefix)
|
||||
{
|
||||
$this->apcuPrefix = function_exists('apcu_fetch') && filter_var(ini_get('apc.enabled'), FILTER_VALIDATE_BOOLEAN) ? $apcuPrefix : null;
|
||||
}
|
||||
|
||||
/**
|
||||
* The APCu prefix in use, or null if APCu caching is not enabled.
|
||||
*
|
||||
* @return string|null
|
||||
*/
|
||||
public function getApcuPrefix()
|
||||
{
|
||||
return $this->apcuPrefix;
|
||||
}
|
||||
|
||||
/**
|
||||
* Registers this instance as an autoloader.
|
||||
*
|
||||
* @param bool $prepend Whether to prepend the autoloader or not
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function register($prepend = false)
|
||||
{
|
||||
spl_autoload_register(array($this, 'loadClass'), true, $prepend);
|
||||
|
||||
if (null === $this->vendorDir) {
|
||||
return;
|
||||
}
|
||||
|
||||
if ($prepend) {
|
||||
self::$registeredLoaders = array($this->vendorDir => $this) + self::$registeredLoaders;
|
||||
} else {
|
||||
unset(self::$registeredLoaders[$this->vendorDir]);
|
||||
self::$registeredLoaders[$this->vendorDir] = $this;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Unregisters this instance as an autoloader.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function unregister()
|
||||
{
|
||||
spl_autoload_unregister(array($this, 'loadClass'));
|
||||
|
||||
if (null !== $this->vendorDir) {
|
||||
unset(self::$registeredLoaders[$this->vendorDir]);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Loads the given class or interface.
|
||||
*
|
||||
* @param string $class The name of the class
|
||||
* @return true|null True if loaded, null otherwise
|
||||
*/
|
||||
public function loadClass($class)
|
||||
{
|
||||
if ($file = $this->findFile($class)) {
|
||||
$includeFile = self::$includeFile;
|
||||
$includeFile($file);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Finds the path to the file where the class is defined.
|
||||
*
|
||||
* @param string $class The name of the class
|
||||
*
|
||||
* @return string|false The path if found, false otherwise
|
||||
*/
|
||||
public function findFile($class)
|
||||
{
|
||||
// class map lookup
|
||||
if (isset($this->classMap[$class])) {
|
||||
return $this->classMap[$class];
|
||||
}
|
||||
if ($this->classMapAuthoritative || isset($this->missingClasses[$class])) {
|
||||
return false;
|
||||
}
|
||||
if (null !== $this->apcuPrefix) {
|
||||
$file = apcu_fetch($this->apcuPrefix.$class, $hit);
|
||||
if ($hit) {
|
||||
return $file;
|
||||
}
|
||||
}
|
||||
|
||||
$file = $this->findFileWithExtension($class, '.php');
|
||||
|
||||
// Search for Hack files if we are running on HHVM
|
||||
if (false === $file && defined('HHVM_VERSION')) {
|
||||
$file = $this->findFileWithExtension($class, '.hh');
|
||||
}
|
||||
|
||||
if (null !== $this->apcuPrefix) {
|
||||
apcu_add($this->apcuPrefix.$class, $file);
|
||||
}
|
||||
|
||||
if (false === $file) {
|
||||
// Remember that this class does not exist.
|
||||
$this->missingClasses[$class] = true;
|
||||
}
|
||||
|
||||
return $file;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the currently registered loaders keyed by their corresponding vendor directories.
|
||||
*
|
||||
* @return array<string, self>
|
||||
*/
|
||||
public static function getRegisteredLoaders()
|
||||
{
|
||||
return self::$registeredLoaders;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $class
|
||||
* @param string $ext
|
||||
* @return string|false
|
||||
*/
|
||||
private function findFileWithExtension($class, $ext)
|
||||
{
|
||||
// PSR-4 lookup
|
||||
$logicalPathPsr4 = strtr($class, '\\', DIRECTORY_SEPARATOR) . $ext;
|
||||
|
||||
$first = $class[0];
|
||||
if (isset($this->prefixLengthsPsr4[$first])) {
|
||||
$subPath = $class;
|
||||
while (false !== $lastPos = strrpos($subPath, '\\')) {
|
||||
$subPath = substr($subPath, 0, $lastPos);
|
||||
$search = $subPath . '\\';
|
||||
if (isset($this->prefixDirsPsr4[$search])) {
|
||||
$pathEnd = DIRECTORY_SEPARATOR . substr($logicalPathPsr4, $lastPos + 1);
|
||||
foreach ($this->prefixDirsPsr4[$search] as $dir) {
|
||||
if (file_exists($file = $dir . $pathEnd)) {
|
||||
return $file;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// PSR-4 fallback dirs
|
||||
foreach ($this->fallbackDirsPsr4 as $dir) {
|
||||
if (file_exists($file = $dir . DIRECTORY_SEPARATOR . $logicalPathPsr4)) {
|
||||
return $file;
|
||||
}
|
||||
}
|
||||
|
||||
// PSR-0 lookup
|
||||
if (false !== $pos = strrpos($class, '\\')) {
|
||||
// namespaced class name
|
||||
$logicalPathPsr0 = substr($logicalPathPsr4, 0, $pos + 1)
|
||||
. strtr(substr($logicalPathPsr4, $pos + 1), '_', DIRECTORY_SEPARATOR);
|
||||
} else {
|
||||
// PEAR-like class name
|
||||
$logicalPathPsr0 = strtr($class, '_', DIRECTORY_SEPARATOR) . $ext;
|
||||
}
|
||||
|
||||
if (isset($this->prefixesPsr0[$first])) {
|
||||
foreach ($this->prefixesPsr0[$first] as $prefix => $dirs) {
|
||||
if (0 === strpos($class, $prefix)) {
|
||||
foreach ($dirs as $dir) {
|
||||
if (file_exists($file = $dir . DIRECTORY_SEPARATOR . $logicalPathPsr0)) {
|
||||
return $file;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// PSR-0 fallback dirs
|
||||
foreach ($this->fallbackDirsPsr0 as $dir) {
|
||||
if (file_exists($file = $dir . DIRECTORY_SEPARATOR . $logicalPathPsr0)) {
|
||||
return $file;
|
||||
}
|
||||
}
|
||||
|
||||
// PSR-0 include paths.
|
||||
if ($this->useIncludePath && $file = stream_resolve_include_path($logicalPathPsr0)) {
|
||||
return $file;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return void
|
||||
*/
|
||||
private static function initializeIncludeClosure()
|
||||
{
|
||||
if (self::$includeFile !== null) {
|
||||
return;
|
||||
}
|
||||
|
||||
/**
|
||||
* Scope isolated include.
|
||||
*
|
||||
* Prevents access to $this/self from included files.
|
||||
*
|
||||
* @param string $file
|
||||
* @return void
|
||||
*/
|
||||
self::$includeFile = \Closure::bind(static function($file) {
|
||||
include $file;
|
||||
}, null, null);
|
||||
}
|
||||
}
|
||||
313
plugins/system/tgeoip/vendor/composer/InstalledVersions.php
vendored
Normal file
313
plugins/system/tgeoip/vendor/composer/InstalledVersions.php
vendored
Normal file
@ -0,0 +1,313 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of Composer.
|
||||
*
|
||||
* (c) Nils Adermann <naderman@naderman.de>
|
||||
* Jordi Boggiano <j.boggiano@seld.be>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
namespace Tassos\Vendor\Composer;
|
||||
|
||||
use Tassos\Vendor\Composer\Autoload\ClassLoader;
|
||||
use Tassos\Vendor\Composer\Semver\VersionParser;
|
||||
/**
|
||||
* This class is copied in every Composer installed project and available to all
|
||||
*
|
||||
* See also https://getcomposer.org/doc/07-runtime.md#installed-versions
|
||||
*
|
||||
* To require its presence, you can require `composer-runtime-api ^2.0`
|
||||
*
|
||||
* @final
|
||||
*/
|
||||
class InstalledVersions
|
||||
{
|
||||
/**
|
||||
* @var mixed[]|null
|
||||
* @psalm-var array{root: array{name: string, pretty_version: string, version: string, reference: string|null, type: string, install_path: string, aliases: string[], dev: bool}, versions: array<string, array{pretty_version?: string, version?: string, reference?: string|null, type?: string, install_path?: string, aliases?: string[], dev_requirement: bool, replaced?: string[], provided?: string[]}>}|array{}|null
|
||||
*/
|
||||
private static $installed;
|
||||
/**
|
||||
* @var bool|null
|
||||
*/
|
||||
private static $canGetVendors;
|
||||
/**
|
||||
* @var array[]
|
||||
* @psalm-var array<string, array{root: array{name: string, pretty_version: string, version: string, reference: string|null, type: string, install_path: string, aliases: string[], dev: bool}, versions: array<string, array{pretty_version?: string, version?: string, reference?: string|null, type?: string, install_path?: string, aliases?: string[], dev_requirement: bool, replaced?: string[], provided?: string[]}>}>
|
||||
*/
|
||||
private static $installedByVendor = array();
|
||||
/**
|
||||
* Returns a list of all package names which are present, either by being installed, replaced or provided
|
||||
*
|
||||
* @return string[]
|
||||
* @psalm-return list<string>
|
||||
*/
|
||||
public static function getInstalledPackages()
|
||||
{
|
||||
$packages = array();
|
||||
foreach (self::getInstalled() as $installed) {
|
||||
$packages[] = \array_keys($installed['versions']);
|
||||
}
|
||||
if (1 === \count($packages)) {
|
||||
return $packages[0];
|
||||
}
|
||||
return \array_keys(\array_flip(\call_user_func_array('array_merge', $packages)));
|
||||
}
|
||||
/**
|
||||
* Returns a list of all package names with a specific type e.g. 'library'
|
||||
*
|
||||
* @param string $type
|
||||
* @return string[]
|
||||
* @psalm-return list<string>
|
||||
*/
|
||||
public static function getInstalledPackagesByType($type)
|
||||
{
|
||||
$packagesByType = array();
|
||||
foreach (self::getInstalled() as $installed) {
|
||||
foreach ($installed['versions'] as $name => $package) {
|
||||
if (isset($package['type']) && $package['type'] === $type) {
|
||||
$packagesByType[] = $name;
|
||||
}
|
||||
}
|
||||
}
|
||||
return $packagesByType;
|
||||
}
|
||||
/**
|
||||
* Checks whether the given package is installed
|
||||
*
|
||||
* This also returns true if the package name is provided or replaced by another package
|
||||
*
|
||||
* @param string $packageName
|
||||
* @param bool $includeDevRequirements
|
||||
* @return bool
|
||||
*/
|
||||
public static function isInstalled($packageName, $includeDevRequirements = \true)
|
||||
{
|
||||
foreach (self::getInstalled() as $installed) {
|
||||
if (isset($installed['versions'][$packageName])) {
|
||||
return $includeDevRequirements || !isset($installed['versions'][$packageName]['dev_requirement']) || $installed['versions'][$packageName]['dev_requirement'] === \false;
|
||||
}
|
||||
}
|
||||
return \false;
|
||||
}
|
||||
/**
|
||||
* Checks whether the given package satisfies a version constraint
|
||||
*
|
||||
* e.g. If you want to know whether version 2.3+ of package foo/bar is installed, you would call:
|
||||
*
|
||||
* Composer\InstalledVersions::satisfies(new VersionParser, 'foo/bar', '^2.3')
|
||||
*
|
||||
* @param VersionParser $parser Install composer/semver to have access to this class and functionality
|
||||
* @param string $packageName
|
||||
* @param string|null $constraint A version constraint to check for, if you pass one you have to make sure composer/semver is required by your package
|
||||
* @return bool
|
||||
*/
|
||||
public static function satisfies(VersionParser $parser, $packageName, $constraint)
|
||||
{
|
||||
$constraint = $parser->parseConstraints((string) $constraint);
|
||||
$provided = $parser->parseConstraints(self::getVersionRanges($packageName));
|
||||
return $provided->matches($constraint);
|
||||
}
|
||||
/**
|
||||
* Returns a version constraint representing all the range(s) which are installed for a given package
|
||||
*
|
||||
* It is easier to use this via isInstalled() with the $constraint argument if you need to check
|
||||
* whether a given version of a package is installed, and not just whether it exists
|
||||
*
|
||||
* @param string $packageName
|
||||
* @return string Version constraint usable with composer/semver
|
||||
*/
|
||||
public static function getVersionRanges($packageName)
|
||||
{
|
||||
foreach (self::getInstalled() as $installed) {
|
||||
if (!isset($installed['versions'][$packageName])) {
|
||||
continue;
|
||||
}
|
||||
$ranges = array();
|
||||
if (isset($installed['versions'][$packageName]['pretty_version'])) {
|
||||
$ranges[] = $installed['versions'][$packageName]['pretty_version'];
|
||||
}
|
||||
if (\array_key_exists('aliases', $installed['versions'][$packageName])) {
|
||||
$ranges = \array_merge($ranges, $installed['versions'][$packageName]['aliases']);
|
||||
}
|
||||
if (\array_key_exists('replaced', $installed['versions'][$packageName])) {
|
||||
$ranges = \array_merge($ranges, $installed['versions'][$packageName]['replaced']);
|
||||
}
|
||||
if (\array_key_exists('provided', $installed['versions'][$packageName])) {
|
||||
$ranges = \array_merge($ranges, $installed['versions'][$packageName]['provided']);
|
||||
}
|
||||
return \implode(' || ', $ranges);
|
||||
}
|
||||
throw new \OutOfBoundsException('Package "' . $packageName . '" is not installed');
|
||||
}
|
||||
/**
|
||||
* @param string $packageName
|
||||
* @return string|null If the package is being replaced or provided but is not really installed, null will be returned as version, use satisfies or getVersionRanges if you need to know if a given version is present
|
||||
*/
|
||||
public static function getVersion($packageName)
|
||||
{
|
||||
foreach (self::getInstalled() as $installed) {
|
||||
if (!isset($installed['versions'][$packageName])) {
|
||||
continue;
|
||||
}
|
||||
if (!isset($installed['versions'][$packageName]['version'])) {
|
||||
return null;
|
||||
}
|
||||
return $installed['versions'][$packageName]['version'];
|
||||
}
|
||||
throw new \OutOfBoundsException('Package "' . $packageName . '" is not installed');
|
||||
}
|
||||
/**
|
||||
* @param string $packageName
|
||||
* @return string|null If the package is being replaced or provided but is not really installed, null will be returned as version, use satisfies or getVersionRanges if you need to know if a given version is present
|
||||
*/
|
||||
public static function getPrettyVersion($packageName)
|
||||
{
|
||||
foreach (self::getInstalled() as $installed) {
|
||||
if (!isset($installed['versions'][$packageName])) {
|
||||
continue;
|
||||
}
|
||||
if (!isset($installed['versions'][$packageName]['pretty_version'])) {
|
||||
return null;
|
||||
}
|
||||
return $installed['versions'][$packageName]['pretty_version'];
|
||||
}
|
||||
throw new \OutOfBoundsException('Package "' . $packageName . '" is not installed');
|
||||
}
|
||||
/**
|
||||
* @param string $packageName
|
||||
* @return string|null If the package is being replaced or provided but is not really installed, null will be returned as reference
|
||||
*/
|
||||
public static function getReference($packageName)
|
||||
{
|
||||
foreach (self::getInstalled() as $installed) {
|
||||
if (!isset($installed['versions'][$packageName])) {
|
||||
continue;
|
||||
}
|
||||
if (!isset($installed['versions'][$packageName]['reference'])) {
|
||||
return null;
|
||||
}
|
||||
return $installed['versions'][$packageName]['reference'];
|
||||
}
|
||||
throw new \OutOfBoundsException('Package "' . $packageName . '" is not installed');
|
||||
}
|
||||
/**
|
||||
* @param string $packageName
|
||||
* @return string|null If the package is being replaced or provided but is not really installed, null will be returned as install path. Packages of type metapackages also have a null install path.
|
||||
*/
|
||||
public static function getInstallPath($packageName)
|
||||
{
|
||||
foreach (self::getInstalled() as $installed) {
|
||||
if (!isset($installed['versions'][$packageName])) {
|
||||
continue;
|
||||
}
|
||||
return isset($installed['versions'][$packageName]['install_path']) ? $installed['versions'][$packageName]['install_path'] : null;
|
||||
}
|
||||
throw new \OutOfBoundsException('Package "' . $packageName . '" is not installed');
|
||||
}
|
||||
/**
|
||||
* @return array
|
||||
* @psalm-return array{name: string, pretty_version: string, version: string, reference: string|null, type: string, install_path: string, aliases: string[], dev: bool}
|
||||
*/
|
||||
public static function getRootPackage()
|
||||
{
|
||||
$installed = self::getInstalled();
|
||||
return $installed[0]['root'];
|
||||
}
|
||||
/**
|
||||
* Returns the raw installed.php data for custom implementations
|
||||
*
|
||||
* @deprecated Use getAllRawData() instead which returns all datasets for all autoloaders present in the process. getRawData only returns the first dataset loaded, which may not be what you expect.
|
||||
* @return array[]
|
||||
* @psalm-return array{root: array{name: string, pretty_version: string, version: string, reference: string|null, type: string, install_path: string, aliases: string[], dev: bool}, versions: array<string, array{pretty_version?: string, version?: string, reference?: string|null, type?: string, install_path?: string, aliases?: string[], dev_requirement: bool, replaced?: string[], provided?: string[]}>}
|
||||
*/
|
||||
public static function getRawData()
|
||||
{
|
||||
@\trigger_error('getRawData only returns the first dataset loaded, which may not be what you expect. Use getAllRawData() instead which returns all datasets for all autoloaders present in the process.', \E_USER_DEPRECATED);
|
||||
if (null === self::$installed) {
|
||||
// only require the installed.php file if this file is loaded from its dumped location,
|
||||
// and not from its source location in the composer/composer package, see https://github.com/composer/composer/issues/9937
|
||||
if (\substr(__DIR__, -8, 1) !== 'C') {
|
||||
self::$installed = (include __DIR__ . '/installed.php');
|
||||
} else {
|
||||
self::$installed = array();
|
||||
}
|
||||
}
|
||||
return self::$installed;
|
||||
}
|
||||
/**
|
||||
* Returns the raw data of all installed.php which are currently loaded for custom implementations
|
||||
*
|
||||
* @return array[]
|
||||
* @psalm-return list<array{root: array{name: string, pretty_version: string, version: string, reference: string|null, type: string, install_path: string, aliases: string[], dev: bool}, versions: array<string, array{pretty_version?: string, version?: string, reference?: string|null, type?: string, install_path?: string, aliases?: string[], dev_requirement: bool, replaced?: string[], provided?: string[]}>}>
|
||||
*/
|
||||
public static function getAllRawData()
|
||||
{
|
||||
return self::getInstalled();
|
||||
}
|
||||
/**
|
||||
* Lets you reload the static array from another file
|
||||
*
|
||||
* This is only useful for complex integrations in which a project needs to use
|
||||
* this class but then also needs to execute another project's autoloader in process,
|
||||
* and wants to ensure both projects have access to their version of installed.php.
|
||||
*
|
||||
* A typical case would be PHPUnit, where it would need to make sure it reads all
|
||||
* the data it needs from this class, then call reload() with
|
||||
* `require $CWD/vendor/composer/installed.php` (or similar) as input to make sure
|
||||
* the project in which it runs can then also use this class safely, without
|
||||
* interference between PHPUnit's dependencies and the project's dependencies.
|
||||
*
|
||||
* @param array[] $data A vendor/composer/installed.php data set
|
||||
* @return void
|
||||
*
|
||||
* @psalm-param array{root: array{name: string, pretty_version: string, version: string, reference: string|null, type: string, install_path: string, aliases: string[], dev: bool}, versions: array<string, array{pretty_version?: string, version?: string, reference?: string|null, type?: string, install_path?: string, aliases?: string[], dev_requirement: bool, replaced?: string[], provided?: string[]}>} $data
|
||||
*/
|
||||
public static function reload($data)
|
||||
{
|
||||
self::$installed = $data;
|
||||
self::$installedByVendor = array();
|
||||
}
|
||||
/**
|
||||
* @return array[]
|
||||
* @psalm-return list<array{root: array{name: string, pretty_version: string, version: string, reference: string|null, type: string, install_path: string, aliases: string[], dev: bool}, versions: array<string, array{pretty_version?: string, version?: string, reference?: string|null, type?: string, install_path?: string, aliases?: string[], dev_requirement: bool, replaced?: string[], provided?: string[]}>}>
|
||||
*/
|
||||
private static function getInstalled()
|
||||
{
|
||||
if (null === self::$canGetVendors) {
|
||||
self::$canGetVendors = \method_exists('Tassos\\Vendor\\Composer\\Autoload\\ClassLoader', 'getRegisteredLoaders');
|
||||
}
|
||||
$installed = array();
|
||||
if (self::$canGetVendors) {
|
||||
foreach (ClassLoader::getRegisteredLoaders() as $vendorDir => $loader) {
|
||||
if (isset(self::$installedByVendor[$vendorDir])) {
|
||||
$installed[] = self::$installedByVendor[$vendorDir];
|
||||
} elseif (\is_file($vendorDir . '/composer/installed.php')) {
|
||||
/** @var array{root: array{name: string, pretty_version: string, version: string, reference: string|null, type: string, install_path: string, aliases: string[], dev: bool}, versions: array<string, array{pretty_version?: string, version?: string, reference?: string|null, type?: string, install_path?: string, aliases?: string[], dev_requirement: bool, replaced?: string[], provided?: string[]}>} $required */
|
||||
$required = (require $vendorDir . '/composer/installed.php');
|
||||
$installed[] = self::$installedByVendor[$vendorDir] = $required;
|
||||
if (null === self::$installed && \strtr($vendorDir . '/composer', '\\', '/') === \strtr(__DIR__, '\\', '/')) {
|
||||
self::$installed = $installed[\count($installed) - 1];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (null === self::$installed) {
|
||||
// only require the installed.php file if this file is loaded from its dumped location,
|
||||
// and not from its source location in the composer/composer package, see https://github.com/composer/composer/issues/9937
|
||||
if (\substr(__DIR__, -8, 1) !== 'C') {
|
||||
/** @var array{root: array{name: string, pretty_version: string, version: string, reference: string|null, type: string, install_path: string, aliases: string[], dev: bool}, versions: array<string, array{pretty_version?: string, version?: string, reference?: string|null, type?: string, install_path?: string, aliases?: string[], dev_requirement: bool, replaced?: string[], provided?: string[]}>} $required */
|
||||
$required = (require __DIR__ . '/installed.php');
|
||||
self::$installed = $required;
|
||||
} else {
|
||||
self::$installed = array();
|
||||
}
|
||||
}
|
||||
if (self::$installed !== array()) {
|
||||
$installed[] = self::$installed;
|
||||
}
|
||||
return $installed;
|
||||
}
|
||||
}
|
||||
10
plugins/system/tgeoip/vendor/composer/autoload_classmap.php
vendored
Normal file
10
plugins/system/tgeoip/vendor/composer/autoload_classmap.php
vendored
Normal file
@ -0,0 +1,10 @@
|
||||
<?php
|
||||
|
||||
// autoload_classmap.php @generated by Composer
|
||||
|
||||
$vendorDir = dirname(__DIR__);
|
||||
$baseDir = dirname($vendorDir);
|
||||
|
||||
return array(
|
||||
'Composer\\InstalledVersions' => $vendorDir . '/composer/InstalledVersions.php',
|
||||
);
|
||||
9
plugins/system/tgeoip/vendor/composer/autoload_namespaces.php
vendored
Normal file
9
plugins/system/tgeoip/vendor/composer/autoload_namespaces.php
vendored
Normal file
@ -0,0 +1,9 @@
|
||||
<?php
|
||||
|
||||
// autoload_namespaces.php @generated by Composer
|
||||
|
||||
$vendorDir = dirname(__DIR__);
|
||||
$baseDir = dirname($vendorDir);
|
||||
|
||||
return array(
|
||||
);
|
||||
15
plugins/system/tgeoip/vendor/composer/autoload_psr4.php
vendored
Normal file
15
plugins/system/tgeoip/vendor/composer/autoload_psr4.php
vendored
Normal file
@ -0,0 +1,15 @@
|
||||
<?php
|
||||
|
||||
// autoload_psr4.php @generated by Composer
|
||||
|
||||
$vendorDir = dirname(__DIR__);
|
||||
$baseDir = dirname($vendorDir);
|
||||
|
||||
return array(
|
||||
'Tassos\\Vendor\\splitbrain\\PHPArchive\\' => array($vendorDir . '/splitbrain/php-archive/src'),
|
||||
'Tassos\\Vendor\\MaxMind\\WebService\\' => array($vendorDir . '/maxmind/web-service-common/src/WebService'),
|
||||
'Tassos\\Vendor\\MaxMind\\Exception\\' => array($vendorDir . '/maxmind/web-service-common/src/Exception'),
|
||||
'Tassos\\Vendor\\MaxMind\\Db\\' => array($vendorDir . '/maxmind-db/reader/src/MaxMind/Db'),
|
||||
'Tassos\\Vendor\\GeoIp2\\' => array($vendorDir . '/geoip2/geoip2/src'),
|
||||
'Tassos\\Vendor\\Composer\\CaBundle\\' => array($vendorDir . '/composer/ca-bundle/src'),
|
||||
);
|
||||
38
plugins/system/tgeoip/vendor/composer/autoload_real.php
vendored
Normal file
38
plugins/system/tgeoip/vendor/composer/autoload_real.php
vendored
Normal file
@ -0,0 +1,38 @@
|
||||
<?php
|
||||
|
||||
// autoload_real.php @generated by Composer
|
||||
|
||||
class ComposerAutoloaderInit087ac1c88c9dd7b872309175c7c60d7d
|
||||
{
|
||||
private static $loader;
|
||||
|
||||
public static function loadClassLoader($class)
|
||||
{
|
||||
if ('Composer\Autoload\ClassLoader' === $class) {
|
||||
require __DIR__ . '/ClassLoader.php';
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @return \Composer\Autoload\ClassLoader
|
||||
*/
|
||||
public static function getLoader()
|
||||
{
|
||||
if (null !== self::$loader) {
|
||||
return self::$loader;
|
||||
}
|
||||
|
||||
require __DIR__ . '/platform_check.php';
|
||||
|
||||
spl_autoload_register(array('ComposerAutoloaderInit087ac1c88c9dd7b872309175c7c60d7d', 'loadClassLoader'), true, true);
|
||||
self::$loader = $loader = new \Composer\Autoload\ClassLoader(\dirname(__DIR__));
|
||||
spl_autoload_unregister(array('ComposerAutoloaderInit087ac1c88c9dd7b872309175c7c60d7d', 'loadClassLoader'));
|
||||
|
||||
require __DIR__ . '/autoload_static.php';
|
||||
call_user_func(\Composer\Autoload\ComposerStaticInit087ac1c88c9dd7b872309175c7c60d7d::getInitializer($loader));
|
||||
|
||||
$loader->register(true);
|
||||
|
||||
return $loader;
|
||||
}
|
||||
}
|
||||
61
plugins/system/tgeoip/vendor/composer/autoload_static.php
vendored
Normal file
61
plugins/system/tgeoip/vendor/composer/autoload_static.php
vendored
Normal file
@ -0,0 +1,61 @@
|
||||
<?php
|
||||
|
||||
// autoload_static.php @generated by Composer
|
||||
|
||||
namespace Composer\Autoload;
|
||||
|
||||
class ComposerStaticInit087ac1c88c9dd7b872309175c7c60d7d
|
||||
{
|
||||
public static $prefixLengthsPsr4 = array (
|
||||
'T' =>
|
||||
array (
|
||||
'Tassos\\Vendor\\splitbrain\\PHPArchive\\' => 36,
|
||||
'Tassos\\Vendor\\MaxMind\\WebService\\' => 33,
|
||||
'Tassos\\Vendor\\MaxMind\\Exception\\' => 32,
|
||||
'Tassos\\Vendor\\MaxMind\\Db\\' => 25,
|
||||
'Tassos\\Vendor\\GeoIp2\\' => 21,
|
||||
'Tassos\\Vendor\\Composer\\CaBundle\\' => 32,
|
||||
),
|
||||
);
|
||||
|
||||
public static $prefixDirsPsr4 = array (
|
||||
'Tassos\\Vendor\\splitbrain\\PHPArchive\\' =>
|
||||
array (
|
||||
0 => __DIR__ . '/..' . '/splitbrain/php-archive/src',
|
||||
),
|
||||
'Tassos\\Vendor\\MaxMind\\WebService\\' =>
|
||||
array (
|
||||
0 => __DIR__ . '/..' . '/maxmind/web-service-common/src/WebService',
|
||||
),
|
||||
'Tassos\\Vendor\\MaxMind\\Exception\\' =>
|
||||
array (
|
||||
0 => __DIR__ . '/..' . '/maxmind/web-service-common/src/Exception',
|
||||
),
|
||||
'Tassos\\Vendor\\MaxMind\\Db\\' =>
|
||||
array (
|
||||
0 => __DIR__ . '/..' . '/maxmind-db/reader/src/MaxMind/Db',
|
||||
),
|
||||
'Tassos\\Vendor\\GeoIp2\\' =>
|
||||
array (
|
||||
0 => __DIR__ . '/..' . '/geoip2/geoip2/src',
|
||||
),
|
||||
'Tassos\\Vendor\\Composer\\CaBundle\\' =>
|
||||
array (
|
||||
0 => __DIR__ . '/..' . '/composer/ca-bundle/src',
|
||||
),
|
||||
);
|
||||
|
||||
public static $classMap = array (
|
||||
'Composer\\InstalledVersions' => __DIR__ . '/..' . '/composer/InstalledVersions.php',
|
||||
);
|
||||
|
||||
public static function getInitializer(ClassLoader $loader)
|
||||
{
|
||||
return \Closure::bind(function () use ($loader) {
|
||||
$loader->prefixLengthsPsr4 = ComposerStaticInit087ac1c88c9dd7b872309175c7c60d7d::$prefixLengthsPsr4;
|
||||
$loader->prefixDirsPsr4 = ComposerStaticInit087ac1c88c9dd7b872309175c7c60d7d::$prefixDirsPsr4;
|
||||
$loader->classMap = ComposerStaticInit087ac1c88c9dd7b872309175c7c60d7d::$classMap;
|
||||
|
||||
}, null, ClassLoader::class);
|
||||
}
|
||||
}
|
||||
3372
plugins/system/tgeoip/vendor/composer/ca-bundle/res/cacert.pem
vendored
Normal file
3372
plugins/system/tgeoip/vendor/composer/ca-bundle/res/cacert.pem
vendored
Normal file
File diff suppressed because it is too large
Load Diff
361
plugins/system/tgeoip/vendor/composer/ca-bundle/src/CaBundle.php
vendored
Normal file
361
plugins/system/tgeoip/vendor/composer/ca-bundle/src/CaBundle.php
vendored
Normal file
@ -0,0 +1,361 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of composer/ca-bundle.
|
||||
*
|
||||
* (c) Composer <https://github.com/composer>
|
||||
*
|
||||
* For the full copyright and license information, please view
|
||||
* the LICENSE file that was distributed with this source code.
|
||||
*/
|
||||
namespace Tassos\Vendor\Composer\CaBundle;
|
||||
|
||||
use Tassos\Vendor\Psr\Log\LoggerInterface;
|
||||
use Tassos\Vendor\Symfony\Component\Process\PhpProcess;
|
||||
/**
|
||||
* @author Chris Smith <chris@cs278.org>
|
||||
* @author Jordi Boggiano <j.boggiano@seld.be>
|
||||
*/
|
||||
class CaBundle
|
||||
{
|
||||
/** @var string|null */
|
||||
private static $caPath;
|
||||
/** @var array<string, bool> */
|
||||
private static $caFileValidity = array();
|
||||
/** @var bool|null */
|
||||
private static $useOpensslParse;
|
||||
/**
|
||||
* Returns the system CA bundle path, or a path to the bundled one
|
||||
*
|
||||
* This method was adapted from Sslurp.
|
||||
* https://github.com/EvanDotPro/Sslurp
|
||||
*
|
||||
* (c) Evan Coury <me@evancoury.com>
|
||||
*
|
||||
* For the full copyright and license information, please see below:
|
||||
*
|
||||
* Copyright (c) 2013, Evan Coury
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without modification,
|
||||
* are permitted provided that the following conditions are met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the following disclaimer.
|
||||
*
|
||||
* * Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
|
||||
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
||||
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
* @param LoggerInterface $logger optional logger for information about which CA files were loaded
|
||||
* @return string path to a CA bundle file or directory
|
||||
*/
|
||||
public static function getSystemCaRootBundlePath(LoggerInterface $logger = null)
|
||||
{
|
||||
if (self::$caPath !== null) {
|
||||
return self::$caPath;
|
||||
}
|
||||
$caBundlePaths = array();
|
||||
// If SSL_CERT_FILE env variable points to a valid certificate/bundle, use that.
|
||||
// This mimics how OpenSSL uses the SSL_CERT_FILE env variable.
|
||||
$caBundlePaths[] = self::getEnvVariable('SSL_CERT_FILE');
|
||||
// If SSL_CERT_DIR env variable points to a valid certificate/bundle, use that.
|
||||
// This mimics how OpenSSL uses the SSL_CERT_FILE env variable.
|
||||
$caBundlePaths[] = self::getEnvVariable('SSL_CERT_DIR');
|
||||
$caBundlePaths[] = \ini_get('openssl.cafile');
|
||||
$caBundlePaths[] = \ini_get('openssl.capath');
|
||||
$otherLocations = array(
|
||||
'/etc/pki/tls/certs/ca-bundle.crt',
|
||||
// Fedora, RHEL, CentOS (ca-certificates package)
|
||||
'/etc/ssl/certs/ca-certificates.crt',
|
||||
// Debian, Ubuntu, Gentoo, Arch Linux (ca-certificates package)
|
||||
'/etc/ssl/ca-bundle.pem',
|
||||
// SUSE, openSUSE (ca-certificates package)
|
||||
'/usr/local/share/certs/ca-root-nss.crt',
|
||||
// FreeBSD (ca_root_nss_package)
|
||||
'/usr/ssl/certs/ca-bundle.crt',
|
||||
// Cygwin
|
||||
'/opt/local/share/curl/curl-ca-bundle.crt',
|
||||
// OS X macports, curl-ca-bundle package
|
||||
'/usr/local/share/curl/curl-ca-bundle.crt',
|
||||
// Default cURL CA bunde path (without --with-ca-bundle option)
|
||||
'/usr/share/ssl/certs/ca-bundle.crt',
|
||||
// Really old RedHat?
|
||||
'/etc/ssl/cert.pem',
|
||||
// OpenBSD
|
||||
'/usr/local/etc/ssl/cert.pem',
|
||||
// FreeBSD 10.x
|
||||
'/usr/local/etc/openssl/cert.pem',
|
||||
// OS X homebrew, openssl package
|
||||
'/usr/local/etc/openssl@1.1/cert.pem',
|
||||
);
|
||||
foreach ($otherLocations as $location) {
|
||||
$otherLocations[] = \dirname($location);
|
||||
}
|
||||
$caBundlePaths = \array_merge($caBundlePaths, $otherLocations);
|
||||
foreach ($caBundlePaths as $caBundle) {
|
||||
if ($caBundle && self::caFileUsable($caBundle, $logger)) {
|
||||
return self::$caPath = $caBundle;
|
||||
}
|
||||
if ($caBundle && self::caDirUsable($caBundle, $logger)) {
|
||||
return self::$caPath = $caBundle;
|
||||
}
|
||||
}
|
||||
return self::$caPath = static::getBundledCaBundlePath();
|
||||
// Bundled CA file, last resort
|
||||
}
|
||||
/**
|
||||
* Returns the path to the bundled CA file
|
||||
*
|
||||
* In case you don't want to trust the user or the system, you can use this directly
|
||||
*
|
||||
* @return string path to a CA bundle file
|
||||
*/
|
||||
public static function getBundledCaBundlePath()
|
||||
{
|
||||
$caBundleFile = __DIR__ . '/../res/cacert.pem';
|
||||
// cURL does not understand 'phar://' paths
|
||||
// see https://github.com/composer/ca-bundle/issues/10
|
||||
if (0 === \strpos($caBundleFile, 'phar://')) {
|
||||
$tempCaBundleFile = \tempnam(\sys_get_temp_dir(), 'openssl-ca-bundle-');
|
||||
if (\false === $tempCaBundleFile) {
|
||||
throw new \RuntimeException('Could not create a temporary file to store the bundled CA file');
|
||||
}
|
||||
\file_put_contents($tempCaBundleFile, \file_get_contents($caBundleFile));
|
||||
\register_shutdown_function(function () use($tempCaBundleFile) {
|
||||
@\unlink($tempCaBundleFile);
|
||||
});
|
||||
$caBundleFile = $tempCaBundleFile;
|
||||
}
|
||||
return $caBundleFile;
|
||||
}
|
||||
/**
|
||||
* Validates a CA file using opensl_x509_parse only if it is safe to use
|
||||
*
|
||||
* @param string $filename
|
||||
* @param LoggerInterface $logger optional logger for information about which CA files were loaded
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public static function validateCaFile($filename, LoggerInterface $logger = null)
|
||||
{
|
||||
static $warned = \false;
|
||||
if (isset(self::$caFileValidity[$filename])) {
|
||||
return self::$caFileValidity[$filename];
|
||||
}
|
||||
$contents = \file_get_contents($filename);
|
||||
// assume the CA is valid if php is vulnerable to
|
||||
// https://www.sektioneins.de/advisories/advisory-012013-php-openssl_x509_parse-memory-corruption-vulnerability.html
|
||||
if (!static::isOpensslParseSafe()) {
|
||||
if (!$warned && $logger) {
|
||||
$logger->warning(\sprintf('Your version of PHP, %s, is affected by CVE-2013-6420 and cannot safely perform certificate validation, we strongly suggest you upgrade.', \PHP_VERSION));
|
||||
$warned = \true;
|
||||
}
|
||||
$isValid = !empty($contents);
|
||||
} elseif (\is_string($contents) && \strlen($contents) > 0) {
|
||||
$contents = \preg_replace("/^(\\-+(?:BEGIN|END))\\s+TRUSTED\\s+(CERTIFICATE\\-+)\$/m", '$1 $2', $contents);
|
||||
if (null === $contents) {
|
||||
// regex extraction failed
|
||||
$isValid = \false;
|
||||
} else {
|
||||
$isValid = (bool) \openssl_x509_parse($contents);
|
||||
}
|
||||
} else {
|
||||
$isValid = \false;
|
||||
}
|
||||
if ($logger) {
|
||||
$logger->debug('Checked CA file ' . \realpath($filename) . ': ' . ($isValid ? 'valid' : 'invalid'));
|
||||
}
|
||||
return self::$caFileValidity[$filename] = $isValid;
|
||||
}
|
||||
/**
|
||||
* Test if it is safe to use the PHP function openssl_x509_parse().
|
||||
*
|
||||
* This checks if OpenSSL extensions is vulnerable to remote code execution
|
||||
* via the exploit documented as CVE-2013-6420.
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public static function isOpensslParseSafe()
|
||||
{
|
||||
if (null !== self::$useOpensslParse) {
|
||||
return self::$useOpensslParse;
|
||||
}
|
||||
if (\PHP_VERSION_ID >= 50600) {
|
||||
return self::$useOpensslParse = \true;
|
||||
}
|
||||
// Vulnerable:
|
||||
// PHP 5.3.0 - PHP 5.3.27
|
||||
// PHP 5.4.0 - PHP 5.4.22
|
||||
// PHP 5.5.0 - PHP 5.5.6
|
||||
if (\PHP_VERSION_ID < 50400 && \PHP_VERSION_ID >= 50328 || \PHP_VERSION_ID < 50500 && \PHP_VERSION_ID >= 50423 || \PHP_VERSION_ID >= 50507) {
|
||||
// This version of PHP has the fix for CVE-2013-6420 applied.
|
||||
return self::$useOpensslParse = \true;
|
||||
}
|
||||
if (\defined('PHP_WINDOWS_VERSION_BUILD')) {
|
||||
// Windows is probably insecure in this case.
|
||||
return self::$useOpensslParse = \false;
|
||||
}
|
||||
$compareDistroVersionPrefix = function ($prefix, $fixedVersion) {
|
||||
$regex = '{^' . \preg_quote($prefix) . '([0-9]+)$}';
|
||||
if (\preg_match($regex, \PHP_VERSION, $m)) {
|
||||
return (int) $m[1] >= $fixedVersion;
|
||||
}
|
||||
return \false;
|
||||
};
|
||||
// Hard coded list of PHP distributions with the fix backported.
|
||||
if ($compareDistroVersionPrefix('5.3.3-7+squeeze', 18) || $compareDistroVersionPrefix('5.4.4-14+deb7u', 7) || $compareDistroVersionPrefix('5.3.10-1ubuntu3.', 9)) {
|
||||
return self::$useOpensslParse = \true;
|
||||
}
|
||||
// Symfony Process component is missing so we assume it is unsafe at this point
|
||||
if (!\class_exists('Tassos\\Vendor\\Symfony\\Component\\Process\\PhpProcess')) {
|
||||
return self::$useOpensslParse = \false;
|
||||
}
|
||||
// This is where things get crazy, because distros backport security
|
||||
// fixes the chances are on NIX systems the fix has been applied but
|
||||
// it's not possible to verify that from the PHP version.
|
||||
//
|
||||
// To verify exec a new PHP process and run the issue testcase with
|
||||
// known safe input that replicates the bug.
|
||||
// Based on testcase in https://github.com/php/php-src/commit/c1224573c773b6845e83505f717fbf820fc18415
|
||||
// changes in https://github.com/php/php-src/commit/76a7fd893b7d6101300cc656058704a73254d593
|
||||
$cert = 'LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUVwRENDQTR5Z0F3SUJBZ0lKQUp6dThyNnU2ZUJjTUEwR0NTcUdTSWIzRFFFQkJRVUFNSUhETVFzd0NRWUQKVlFRR0V3SkVSVEVjTUJvR0ExVUVDQXdUVG05eVpISm9aV2x1TFZkbGMzUm1ZV3hsYmpFUU1BNEdBMVVFQnd3SApTOE9Ed3Jac2JqRVVNQklHQTFVRUNnd0xVMlZyZEdsdmJrVnBibk14SHpBZEJnTlZCQXNNRmsxaGJHbGphVzkxCmN5QkRaWEowSUZObFkzUnBiMjR4SVRBZkJnTlZCQU1NR0cxaGJHbGphVzkxY3k1elpXdDBhVzl1WldsdWN5NWsKWlRFcU1DZ0dDU3FHU0liM0RRRUpBUlliYzNSbFptRnVMbVZ6YzJWeVFITmxhM1JwYjI1bGFXNXpMbVJsTUhVWQpaREU1TnpBd01UQXhNREF3TURBd1dnQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBCkFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUEKQUFBQUFBQVhEVEUwTVRFeU9ERXhNemt6TlZvd2djTXhDekFKQmdOVkJBWVRBa1JGTVJ3d0dnWURWUVFJREJOTwpiM0prY21obGFXNHRWMlZ6ZEdaaGJHVnVNUkF3RGdZRFZRUUhEQWRMdzRQQ3RteHVNUlF3RWdZRFZRUUtEQXRUClpXdDBhVzl1UldsdWN6RWZNQjBHQTFVRUN3d1dUV0ZzYVdOcGIzVnpJRU5sY25RZ1UyVmpkR2x2YmpFaE1COEcKQTFVRUF3d1liV0ZzYVdOcGIzVnpMbk5sYTNScGIyNWxhVzV6TG1SbE1Tb3dLQVlKS29aSWh2Y05BUWtCRmh0egpkR1ZtWVc0dVpYTnpaWEpBYzJWcmRHbHZibVZwYm5NdVpHVXdnZ0VpTUEwR0NTcUdTSWIzRFFFQkFRVUFBNElCCkR3QXdnZ0VLQW9JQkFRRERBZjNobDdKWTBYY0ZuaXlFSnBTU0RxbjBPcUJyNlFQNjV1c0pQUnQvOFBhRG9xQnUKd0VZVC9OYSs2ZnNnUGpDMHVLOURaZ1dnMnRIV1dvYW5TYmxBTW96NVBINlorUzRTSFJaN2UyZERJalBqZGhqaAowbUxnMlVNTzV5cDBWNzk3R2dzOWxOdDZKUmZIODFNTjJvYlhXczROdHp0TE11RDZlZ3FwcjhkRGJyMzRhT3M4CnBrZHVpNVVhd1Raa3N5NXBMUEhxNWNNaEZHbTA2djY1Q0xvMFYyUGQ5K0tBb2tQclBjTjVLTEtlYno3bUxwazYKU01lRVhPS1A0aWRFcXh5UTdPN2ZCdUhNZWRzUWh1K3ByWTNzaTNCVXlLZlF0UDVDWm5YMmJwMHdLSHhYMTJEWAoxbmZGSXQ5RGJHdkhUY3lPdU4rblpMUEJtM3ZXeG50eUlJdlZBZ01CQUFHalFqQkFNQWtHQTFVZEV3UUNNQUF3CkVRWUpZSVpJQVliNFFnRUJCQVFEQWdlQU1Bc0dBMVVkRHdRRUF3SUZvREFUQmdOVkhTVUVEREFLQmdnckJnRUYKQlFjREFqQU5CZ2txaGtpRzl3MEJBUVVGQUFPQ0FRRUFHMGZaWVlDVGJkajFYWWMrMVNub2FQUit2SThDOENhRAo4KzBVWWhkbnlVNGdnYTBCQWNEclk5ZTk0ZUVBdTZacXljRjZGakxxWFhkQWJvcHBXb2NyNlQ2R0QxeDMzQ2tsClZBcnpHL0t4UW9oR0QySmVxa2hJTWxEb214SE83a2EzOStPYThpMnZXTFZ5alU4QVp2V01BcnVIYTRFRU55RzcKbFcyQWFnYUZLRkNyOVRuWFRmcmR4R1ZFYnY3S1ZRNmJkaGc1cDVTanBXSDErTXEwM3VSM1pYUEJZZHlWODMxOQpvMGxWajFLRkkyRENML2xpV2lzSlJvb2YrMWNSMzVDdGQwd1lCY3BCNlRac2xNY09QbDc2ZHdLd0pnZUpvMlFnClpzZm1jMnZDMS9xT2xOdU5xLzBUenprVkd2OEVUVDNDZ2FVK1VYZTRYT1Z2a2NjZWJKbjJkZz09Ci0tLS0tRU5EIENFUlRJRklDQVRFLS0tLS0K';
|
||||
$script = <<<'EOT'
|
||||
|
||||
error_reporting(-1);
|
||||
$info = openssl_x509_parse(base64_decode('%s'));
|
||||
var_dump(PHP_VERSION, $info['issuer']['emailAddress'], $info['validFrom_time_t']);
|
||||
|
||||
EOT;
|
||||
$script = '<' . "?php\n" . \sprintf($script, $cert);
|
||||
try {
|
||||
$process = new PhpProcess($script);
|
||||
$process->mustRun();
|
||||
} catch (\Exception $e) {
|
||||
// In the case of any exceptions just accept it is not possible to
|
||||
// determine the safety of openssl_x509_parse and bail out.
|
||||
return self::$useOpensslParse = \false;
|
||||
}
|
||||
$output = \preg_split('{\\r?\\n}', \trim($process->getOutput()));
|
||||
$errorOutput = \trim($process->getErrorOutput());
|
||||
if (\is_array($output) && \count($output) === 3 && $output[0] === \sprintf('string(%d) "%s"', \strlen(\PHP_VERSION), \PHP_VERSION) && $output[1] === 'string(27) "stefan.esser@sektioneins.de"' && $output[2] === 'int(-1)' && \preg_match('{openssl_x509_parse\\(\\): illegal (?:ASN1 data type for|length in) timestamp in - on line \\d+}', $errorOutput)) {
|
||||
// This PHP has the fix backported probably by a distro security team.
|
||||
return self::$useOpensslParse = \true;
|
||||
}
|
||||
return self::$useOpensslParse = \false;
|
||||
}
|
||||
/**
|
||||
* Resets the static caches
|
||||
* @return void
|
||||
*/
|
||||
public static function reset()
|
||||
{
|
||||
self::$caFileValidity = array();
|
||||
self::$caPath = null;
|
||||
self::$useOpensslParse = null;
|
||||
}
|
||||
/**
|
||||
* @param string $name
|
||||
* @return string|false
|
||||
*/
|
||||
private static function getEnvVariable($name)
|
||||
{
|
||||
if (isset($_SERVER[$name])) {
|
||||
return (string) $_SERVER[$name];
|
||||
}
|
||||
if (\PHP_SAPI === 'cli' && ($value = \getenv($name)) !== \false && $value !== null) {
|
||||
return (string) $value;
|
||||
}
|
||||
return \false;
|
||||
}
|
||||
/**
|
||||
* @param string|false $certFile
|
||||
* @param LoggerInterface|null $logger
|
||||
* @return bool
|
||||
*/
|
||||
private static function caFileUsable($certFile, LoggerInterface $logger = null)
|
||||
{
|
||||
return $certFile && static::isFile($certFile, $logger) && static::isReadable($certFile, $logger) && static::validateCaFile($certFile, $logger);
|
||||
}
|
||||
/**
|
||||
* @param string|false $certDir
|
||||
* @param LoggerInterface|null $logger
|
||||
* @return bool
|
||||
*/
|
||||
private static function caDirUsable($certDir, LoggerInterface $logger = null)
|
||||
{
|
||||
return $certDir && static::isDir($certDir, $logger) && static::isReadable($certDir, $logger) && static::glob($certDir . '/*', $logger);
|
||||
}
|
||||
/**
|
||||
* @param string $certFile
|
||||
* @param LoggerInterface|null $logger
|
||||
* @return bool
|
||||
*/
|
||||
private static function isFile($certFile, LoggerInterface $logger = null)
|
||||
{
|
||||
$isFile = @\is_file($certFile);
|
||||
if (!$isFile && $logger) {
|
||||
$logger->debug(\sprintf('Checked CA file %s does not exist or it is not a file.', $certFile));
|
||||
}
|
||||
return $isFile;
|
||||
}
|
||||
/**
|
||||
* @param string $certDir
|
||||
* @param LoggerInterface|null $logger
|
||||
* @return bool
|
||||
*/
|
||||
private static function isDir($certDir, LoggerInterface $logger = null)
|
||||
{
|
||||
$isDir = @\is_dir($certDir);
|
||||
if (!$isDir && $logger) {
|
||||
$logger->debug(\sprintf('Checked directory %s does not exist or it is not a directory.', $certDir));
|
||||
}
|
||||
return $isDir;
|
||||
}
|
||||
/**
|
||||
* @param string $certFileOrDir
|
||||
* @param LoggerInterface|null $logger
|
||||
* @return bool
|
||||
*/
|
||||
private static function isReadable($certFileOrDir, LoggerInterface $logger = null)
|
||||
{
|
||||
$isReadable = @\is_readable($certFileOrDir);
|
||||
if (!$isReadable && $logger) {
|
||||
$logger->debug(\sprintf('Checked file or directory %s is not readable.', $certFileOrDir));
|
||||
}
|
||||
return $isReadable;
|
||||
}
|
||||
/**
|
||||
* @param string $pattern
|
||||
* @param LoggerInterface|null $logger
|
||||
* @return bool
|
||||
*/
|
||||
private static function glob($pattern, LoggerInterface $logger = null)
|
||||
{
|
||||
$certs = \glob($pattern);
|
||||
if ($certs === \false) {
|
||||
if ($logger) {
|
||||
$logger->debug(\sprintf("An error occurred while trying to find certificates for pattern: %s", $pattern));
|
||||
}
|
||||
return \false;
|
||||
}
|
||||
if (\count($certs) === 0) {
|
||||
if ($logger) {
|
||||
$logger->debug(\sprintf("No CA files found for pattern: %s", $pattern));
|
||||
}
|
||||
return \false;
|
||||
}
|
||||
return \true;
|
||||
}
|
||||
}
|
||||
327
plugins/system/tgeoip/vendor/composer/installed.json
vendored
Normal file
327
plugins/system/tgeoip/vendor/composer/installed.json
vendored
Normal file
@ -0,0 +1,327 @@
|
||||
{
|
||||
"packages": [
|
||||
{
|
||||
"name": "composer\/ca-bundle",
|
||||
"version": "1.3.5",
|
||||
"version_normalized": "1.3.5.0",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https:\/\/github.com\/composer\/ca-bundle.git",
|
||||
"reference": "74780ccf8c19d6acb8d65c5f39cd72110e132bbd"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https:\/\/api.github.com\/repos\/composer\/ca-bundle\/zipball\/74780ccf8c19d6acb8d65c5f39cd72110e132bbd",
|
||||
"reference": "74780ccf8c19d6acb8d65c5f39cd72110e132bbd",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"ext-openssl": "*",
|
||||
"ext-pcre": "*",
|
||||
"php": "^5.3.2 || ^7.0 || ^8.0"
|
||||
},
|
||||
"require-dev": {
|
||||
"phpstan\/phpstan": "^0.12.55",
|
||||
"psr\/log": "^1.0",
|
||||
"symfony\/phpunit-bridge": "^4.2 || ^5",
|
||||
"symfony\/process": "^2.5 || ^3.0 || ^4.0 || ^5.0 || ^6.0"
|
||||
},
|
||||
"time": "2023-01-11T08:27:00+00:00",
|
||||
"type": "library",
|
||||
"extra": {
|
||||
"branch-alias": {
|
||||
"dev-main": "1.x-dev"
|
||||
}
|
||||
},
|
||||
"installation-source": "dist",
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"Tassos\\Vendor\\Composer\\CaBundle\\": "src"
|
||||
}
|
||||
},
|
||||
"notification-url": "https:\/\/packagist.org\/downloads\/",
|
||||
"license": [
|
||||
"MIT"
|
||||
],
|
||||
"authors": [
|
||||
{
|
||||
"name": "Jordi Boggiano",
|
||||
"email": "j.boggiano@seld.be",
|
||||
"homepage": "http:\/\/seld.be"
|
||||
}
|
||||
],
|
||||
"description": "Lets you find a path to the system CA bundle, and includes a fallback to the Mozilla CA bundle.",
|
||||
"keywords": [
|
||||
"cabundle",
|
||||
"cacert",
|
||||
"certificate",
|
||||
"ssl",
|
||||
"tls"
|
||||
],
|
||||
"support": {
|
||||
"irc": "irc:\/\/irc.freenode.org\/composer",
|
||||
"issues": "https:\/\/github.com\/composer\/ca-bundle\/issues",
|
||||
"source": "https:\/\/github.com\/composer\/ca-bundle\/tree\/1.3.5"
|
||||
},
|
||||
"funding": [
|
||||
{
|
||||
"url": "https:\/\/packagist.com",
|
||||
"type": "custom"
|
||||
},
|
||||
{
|
||||
"url": "https:\/\/github.com\/composer",
|
||||
"type": "github"
|
||||
},
|
||||
{
|
||||
"url": "https:\/\/tidelift.com\/funding\/github\/packagist\/composer\/composer",
|
||||
"type": "tidelift"
|
||||
}
|
||||
],
|
||||
"install-path": ".\/ca-bundle"
|
||||
},
|
||||
{
|
||||
"name": "geoip2\/geoip2",
|
||||
"version": "v2.13.0",
|
||||
"version_normalized": "2.13.0.0",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "git@github.com:maxmind\/GeoIP2-php.git",
|
||||
"reference": "6a41d8fbd6b90052bc34dff3b4252d0f88067b23"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https:\/\/api.github.com\/repos\/maxmind\/GeoIP2-php\/zipball\/6a41d8fbd6b90052bc34dff3b4252d0f88067b23",
|
||||
"reference": "6a41d8fbd6b90052bc34dff3b4252d0f88067b23",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"ext-json": "*",
|
||||
"maxmind-db\/reader": "~1.8",
|
||||
"maxmind\/web-service-common": "~0.8",
|
||||
"php": ">=7.2"
|
||||
},
|
||||
"require-dev": {
|
||||
"friendsofphp\/php-cs-fixer": "3.*",
|
||||
"phpstan\/phpstan": "*",
|
||||
"phpunit\/phpunit": "^8.0 || ^9.0",
|
||||
"squizlabs\/php_codesniffer": "3.*"
|
||||
},
|
||||
"time": "2022-08-05T20:32:58+00:00",
|
||||
"type": "library",
|
||||
"installation-source": "dist",
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"Tassos\\Vendor\\GeoIp2\\": "src"
|
||||
}
|
||||
},
|
||||
"notification-url": "https:\/\/packagist.org\/downloads\/",
|
||||
"license": [
|
||||
"Apache-2.0"
|
||||
],
|
||||
"authors": [
|
||||
{
|
||||
"name": "Gregory J. Oschwald",
|
||||
"email": "goschwald@maxmind.com",
|
||||
"homepage": "https:\/\/www.maxmind.com\/"
|
||||
}
|
||||
],
|
||||
"description": "MaxMind GeoIP2 PHP API",
|
||||
"homepage": "https:\/\/github.com\/maxmind\/GeoIP2-php",
|
||||
"keywords": [
|
||||
"IP",
|
||||
"geoip",
|
||||
"geoip2",
|
||||
"geolocation",
|
||||
"maxmind"
|
||||
],
|
||||
"install-path": "..\/geoip2\/geoip2"
|
||||
},
|
||||
{
|
||||
"name": "maxmind-db\/reader",
|
||||
"version": "v1.11.0",
|
||||
"version_normalized": "1.11.0.0",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https:\/\/github.com\/maxmind\/MaxMind-DB-Reader-php.git",
|
||||
"reference": "b1f3c0699525336d09cc5161a2861268d9f2ae5b"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https:\/\/api.github.com\/repos\/maxmind\/MaxMind-DB-Reader-php\/zipball\/b1f3c0699525336d09cc5161a2861268d9f2ae5b",
|
||||
"reference": "b1f3c0699525336d09cc5161a2861268d9f2ae5b",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"php": ">=7.2"
|
||||
},
|
||||
"conflict": {
|
||||
"ext-maxminddb": "<1.10.1,>=2.0.0"
|
||||
},
|
||||
"require-dev": {
|
||||
"friendsofphp\/php-cs-fixer": "3.*",
|
||||
"php-coveralls\/php-coveralls": "^2.1",
|
||||
"phpstan\/phpstan": "*",
|
||||
"phpunit\/phpcov": ">=6.0.0",
|
||||
"phpunit\/phpunit": ">=8.0.0,<10.0.0",
|
||||
"squizlabs\/php_codesniffer": "3.*"
|
||||
},
|
||||
"suggest": {
|
||||
"ext-bcmath": "bcmath or gmp is required for decoding larger integers with the pure PHP decoder",
|
||||
"ext-gmp": "bcmath or gmp is required for decoding larger integers with the pure PHP decoder",
|
||||
"ext-maxminddb": "A C-based database decoder that provides significantly faster lookups"
|
||||
},
|
||||
"time": "2021-10-18T15:23:10+00:00",
|
||||
"type": "library",
|
||||
"installation-source": "dist",
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"Tassos\\Vendor\\MaxMind\\Db\\": "src\/MaxMind\/Db"
|
||||
}
|
||||
},
|
||||
"notification-url": "https:\/\/packagist.org\/downloads\/",
|
||||
"license": [
|
||||
"Apache-2.0"
|
||||
],
|
||||
"authors": [
|
||||
{
|
||||
"name": "Gregory J. Oschwald",
|
||||
"email": "goschwald@maxmind.com",
|
||||
"homepage": "https:\/\/www.maxmind.com\/"
|
||||
}
|
||||
],
|
||||
"description": "MaxMind DB Reader API",
|
||||
"homepage": "https:\/\/github.com\/maxmind\/MaxMind-DB-Reader-php",
|
||||
"keywords": [
|
||||
"database",
|
||||
"geoip",
|
||||
"geoip2",
|
||||
"geolocation",
|
||||
"maxmind"
|
||||
],
|
||||
"support": {
|
||||
"issues": "https:\/\/github.com\/maxmind\/MaxMind-DB-Reader-php\/issues",
|
||||
"source": "https:\/\/github.com\/maxmind\/MaxMind-DB-Reader-php\/tree\/v1.11.0"
|
||||
},
|
||||
"install-path": "..\/maxmind-db\/reader"
|
||||
},
|
||||
{
|
||||
"name": "maxmind\/web-service-common",
|
||||
"version": "v0.9.0",
|
||||
"version_normalized": "0.9.0.0",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https:\/\/github.com\/maxmind\/web-service-common-php.git",
|
||||
"reference": "4dc5a3e8df38aea4ca3b1096cee3a038094e9b53"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https:\/\/api.github.com\/repos\/maxmind\/web-service-common-php\/zipball\/4dc5a3e8df38aea4ca3b1096cee3a038094e9b53",
|
||||
"reference": "4dc5a3e8df38aea4ca3b1096cee3a038094e9b53",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"composer\/ca-bundle": "^1.0.3",
|
||||
"ext-curl": "*",
|
||||
"ext-json": "*",
|
||||
"php": ">=7.2"
|
||||
},
|
||||
"require-dev": {
|
||||
"friendsofphp\/php-cs-fixer": "3.*",
|
||||
"phpstan\/phpstan": "*",
|
||||
"phpunit\/phpunit": "^8.0 || ^9.0",
|
||||
"squizlabs\/php_codesniffer": "3.*"
|
||||
},
|
||||
"time": "2022-03-28T17:43:20+00:00",
|
||||
"type": "library",
|
||||
"installation-source": "dist",
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"Tassos\\Vendor\\MaxMind\\Exception\\": "src\/Exception",
|
||||
"Tassos\\Vendor\\MaxMind\\WebService\\": "src\/WebService"
|
||||
}
|
||||
},
|
||||
"notification-url": "https:\/\/packagist.org\/downloads\/",
|
||||
"license": [
|
||||
"Apache-2.0"
|
||||
],
|
||||
"authors": [
|
||||
{
|
||||
"name": "Gregory Oschwald",
|
||||
"email": "goschwald@maxmind.com"
|
||||
}
|
||||
],
|
||||
"description": "Internal MaxMind Web Service API",
|
||||
"homepage": "https:\/\/github.com\/maxmind\/web-service-common-php",
|
||||
"support": {
|
||||
"issues": "https:\/\/github.com\/maxmind\/web-service-common-php\/issues",
|
||||
"source": "https:\/\/github.com\/maxmind\/web-service-common-php\/tree\/v0.9.0"
|
||||
},
|
||||
"install-path": "..\/maxmind\/web-service-common"
|
||||
},
|
||||
{
|
||||
"name": "splitbrain\/php-archive",
|
||||
"version": "1.3.1",
|
||||
"version_normalized": "1.3.1.0",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https:\/\/github.com\/splitbrain\/php-archive.git",
|
||||
"reference": "d274e5190ba309777926348900cf9578d9e533c9"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https:\/\/api.github.com\/repos\/splitbrain\/php-archive\/zipball\/d274e5190ba309777926348900cf9578d9e533c9",
|
||||
"reference": "d274e5190ba309777926348900cf9578d9e533c9",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"php": ">=7.0"
|
||||
},
|
||||
"require-dev": {
|
||||
"ext-bz2": "*",
|
||||
"ext-zip": "*",
|
||||
"mikey179\/vfsstream": "^1.6",
|
||||
"phpunit\/phpunit": "^8"
|
||||
},
|
||||
"suggest": {
|
||||
"ext-bz2": "For bz2 compression",
|
||||
"ext-iconv": "Used for proper filename encode handling",
|
||||
"ext-mbstring": "Can be used alternatively for handling filename encoding",
|
||||
"ext-zlib": "For zlib compression"
|
||||
},
|
||||
"time": "2022-03-23T09:21:55+00:00",
|
||||
"type": "library",
|
||||
"installation-source": "dist",
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"Tassos\\Vendor\\splitbrain\\PHPArchive\\": "src"
|
||||
}
|
||||
},
|
||||
"notification-url": "https:\/\/packagist.org\/downloads\/",
|
||||
"license": [
|
||||
"MIT"
|
||||
],
|
||||
"authors": [
|
||||
{
|
||||
"name": "Andreas Gohr",
|
||||
"email": "andi@splitbrain.org"
|
||||
}
|
||||
],
|
||||
"description": "Pure-PHP implementation to read and write TAR and ZIP archives",
|
||||
"keywords": [
|
||||
"archive",
|
||||
"extract",
|
||||
"tar",
|
||||
"unpack",
|
||||
"unzip",
|
||||
"zip"
|
||||
],
|
||||
"support": {
|
||||
"issues": "https:\/\/github.com\/splitbrain\/php-archive\/issues",
|
||||
"source": "https:\/\/github.com\/splitbrain\/php-archive\/tree\/1.3.1"
|
||||
},
|
||||
"install-path": "..\/splitbrain\/php-archive"
|
||||
}
|
||||
],
|
||||
"dev": true,
|
||||
"dev-package-names": []
|
||||
}
|
||||
5
plugins/system/tgeoip/vendor/composer/installed.php
vendored
Normal file
5
plugins/system/tgeoip/vendor/composer/installed.php
vendored
Normal file
@ -0,0 +1,5 @@
|
||||
<?php
|
||||
|
||||
namespace Tassos\Vendor;
|
||||
|
||||
return array('root' => array('name' => '__root__', 'pretty_version' => 'dev-master', 'version' => 'dev-master', 'reference' => '015eb26a70321a57e0c514ec4742cbe8a2580208', 'type' => 'library', 'install_path' => __DIR__ . '/../../', 'aliases' => array(), 'dev' => \true), 'versions' => array('__root__' => array('pretty_version' => 'dev-master', 'version' => 'dev-master', 'reference' => '015eb26a70321a57e0c514ec4742cbe8a2580208', 'type' => 'library', 'install_path' => __DIR__ . '/../../', 'aliases' => array(), 'dev_requirement' => \false), 'composer/ca-bundle' => array('pretty_version' => '1.3.5', 'version' => '1.3.5.0', 'reference' => '74780ccf8c19d6acb8d65c5f39cd72110e132bbd', 'type' => 'library', 'install_path' => __DIR__ . '/./ca-bundle', 'aliases' => array(), 'dev_requirement' => \false), 'geoip2/geoip2' => array('pretty_version' => 'v2.13.0', 'version' => '2.13.0.0', 'reference' => '6a41d8fbd6b90052bc34dff3b4252d0f88067b23', 'type' => 'library', 'install_path' => __DIR__ . '/../geoip2/geoip2', 'aliases' => array(), 'dev_requirement' => \false), 'maxmind-db/reader' => array('pretty_version' => 'v1.11.0', 'version' => '1.11.0.0', 'reference' => 'b1f3c0699525336d09cc5161a2861268d9f2ae5b', 'type' => 'library', 'install_path' => __DIR__ . '/../maxmind-db/reader', 'aliases' => array(), 'dev_requirement' => \false), 'maxmind/web-service-common' => array('pretty_version' => 'v0.9.0', 'version' => '0.9.0.0', 'reference' => '4dc5a3e8df38aea4ca3b1096cee3a038094e9b53', 'type' => 'library', 'install_path' => __DIR__ . '/../maxmind/web-service-common', 'aliases' => array(), 'dev_requirement' => \false), 'splitbrain/php-archive' => array('pretty_version' => '1.3.1', 'version' => '1.3.1.0', 'reference' => 'd274e5190ba309777926348900cf9578d9e533c9', 'type' => 'library', 'install_path' => __DIR__ . '/../splitbrain/php-archive', 'aliases' => array(), 'dev_requirement' => \false)));
|
||||
26
plugins/system/tgeoip/vendor/composer/platform_check.php
vendored
Normal file
26
plugins/system/tgeoip/vendor/composer/platform_check.php
vendored
Normal file
@ -0,0 +1,26 @@
|
||||
<?php
|
||||
|
||||
// platform_check.php @generated by Composer
|
||||
|
||||
$issues = array();
|
||||
|
||||
if (!(PHP_VERSION_ID >= 70200)) {
|
||||
$issues[] = 'Your Composer dependencies require a PHP version ">= 7.2.0". You are running ' . PHP_VERSION . '.';
|
||||
}
|
||||
|
||||
if ($issues) {
|
||||
if (!headers_sent()) {
|
||||
header('HTTP/1.1 500 Internal Server Error');
|
||||
}
|
||||
if (!ini_get('display_errors')) {
|
||||
if (PHP_SAPI === 'cli' || PHP_SAPI === 'phpdbg') {
|
||||
fwrite(STDERR, 'Composer detected issues in your platform:' . PHP_EOL.PHP_EOL . implode(PHP_EOL, $issues) . PHP_EOL.PHP_EOL);
|
||||
} elseif (!headers_sent()) {
|
||||
echo 'Composer detected issues in your platform:' . PHP_EOL.PHP_EOL . str_replace('You are running '.PHP_VERSION.'.', '', implode(PHP_EOL, $issues)) . PHP_EOL.PHP_EOL;
|
||||
}
|
||||
}
|
||||
trigger_error(
|
||||
'Composer detected issues in your platform: ' . implode(' ', $issues),
|
||||
E_USER_ERROR
|
||||
);
|
||||
}
|
||||
23
plugins/system/tgeoip/vendor/geoip2/geoip2/examples/benchmark.php
vendored
Normal file
23
plugins/system/tgeoip/vendor/geoip2/geoip2/examples/benchmark.php
vendored
Normal file
@ -0,0 +1,23 @@
|
||||
<?php
|
||||
|
||||
namespace Tassos\Vendor;
|
||||
|
||||
require __DIR__ . '/../vendor/autoload.php';
|
||||
use Tassos\Vendor\GeoIp2\Database\Reader;
|
||||
\srand(0);
|
||||
$reader = new Reader('GeoIP2-City.mmdb');
|
||||
$count = 500000;
|
||||
$startTime = \microtime(\true);
|
||||
for ($i = 0; $i < $count; ++$i) {
|
||||
$ip = \long2ip(\rand(0, 2 ** 32 - 1));
|
||||
try {
|
||||
$t = $reader->city($ip);
|
||||
} catch (\Tassos\Vendor\GeoIp2\Exception\AddressNotFoundException $e) {
|
||||
}
|
||||
if ($i % 10000 === 0) {
|
||||
echo $i . ' ' . $ip . "\n";
|
||||
}
|
||||
}
|
||||
$endTime = \microtime(\true);
|
||||
$duration = $endTime - $startTime;
|
||||
echo 'Requests per second: ' . $count / $duration . "\n";
|
||||
246
plugins/system/tgeoip/vendor/geoip2/geoip2/src/Database/Reader.php
vendored
Normal file
246
plugins/system/tgeoip/vendor/geoip2/geoip2/src/Database/Reader.php
vendored
Normal file
@ -0,0 +1,246 @@
|
||||
<?php
|
||||
|
||||
declare (strict_types=1);
|
||||
namespace Tassos\Vendor\GeoIp2\Database;
|
||||
|
||||
use Tassos\Vendor\GeoIp2\Exception\AddressNotFoundException;
|
||||
use Tassos\Vendor\GeoIp2\Model\AbstractModel;
|
||||
use Tassos\Vendor\GeoIp2\Model\AnonymousIp;
|
||||
use Tassos\Vendor\GeoIp2\Model\Asn;
|
||||
use Tassos\Vendor\GeoIp2\Model\City;
|
||||
use Tassos\Vendor\GeoIp2\Model\ConnectionType;
|
||||
use Tassos\Vendor\GeoIp2\Model\Country;
|
||||
use Tassos\Vendor\GeoIp2\Model\Domain;
|
||||
use Tassos\Vendor\GeoIp2\Model\Enterprise;
|
||||
use Tassos\Vendor\GeoIp2\Model\Isp;
|
||||
use Tassos\Vendor\GeoIp2\ProviderInterface;
|
||||
use Tassos\Vendor\MaxMind\Db\Reader as DbReader;
|
||||
use Tassos\Vendor\MaxMind\Db\Reader\InvalidDatabaseException;
|
||||
/**
|
||||
* Instances of this class provide a reader for the GeoIP2 database format.
|
||||
* IP addresses can be looked up using the database specific methods.
|
||||
*
|
||||
* ## Usage ##
|
||||
*
|
||||
* The basic API for this class is the same for every database. First, you
|
||||
* create a reader object, specifying a file name. You then call the method
|
||||
* corresponding to the specific database, passing it the IP address you want
|
||||
* to look up.
|
||||
*
|
||||
* If the request succeeds, the method call will return a model class for
|
||||
* the method you called. This model in turn contains multiple record classes,
|
||||
* each of which represents part of the data returned by the database. If
|
||||
* the database does not contain the requested information, the attributes
|
||||
* on the record class will have a `null` value.
|
||||
*
|
||||
* If the address is not in the database, an
|
||||
* {@link \GeoIp2\Exception\AddressNotFoundException} exception will be
|
||||
* thrown. If an invalid IP address is passed to one of the methods, a
|
||||
* SPL {@link \InvalidArgumentException} will be thrown. If the database is
|
||||
* corrupt or invalid, a {@link \MaxMind\Db\Reader\InvalidDatabaseException}
|
||||
* will be thrown.
|
||||
*/
|
||||
class Reader implements ProviderInterface
|
||||
{
|
||||
/**
|
||||
* @var DbReader
|
||||
*/
|
||||
private $dbReader;
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
private $dbType;
|
||||
/**
|
||||
* @var array<string>
|
||||
*/
|
||||
private $locales;
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* @param string $filename the path to the GeoIP2 database file
|
||||
* @param array $locales list of locale codes to use in name property
|
||||
* from most preferred to least preferred
|
||||
*
|
||||
* @throws \MaxMind\Db\Reader\InvalidDatabaseException if the database
|
||||
* is corrupt or invalid
|
||||
*/
|
||||
public function __construct(string $filename, array $locales = ['en'])
|
||||
{
|
||||
$this->dbReader = new DbReader($filename);
|
||||
$this->dbType = $this->dbReader->metadata()->databaseType;
|
||||
$this->locales = $locales;
|
||||
}
|
||||
/**
|
||||
* This method returns a GeoIP2 City model.
|
||||
*
|
||||
* @param string $ipAddress an IPv4 or IPv6 address as a string
|
||||
*
|
||||
* @throws \GeoIp2\Exception\AddressNotFoundException if the address is
|
||||
* not in the database
|
||||
* @throws \MaxMind\Db\Reader\InvalidDatabaseException if the database
|
||||
* is corrupt or invalid
|
||||
*/
|
||||
public function city(string $ipAddress) : City
|
||||
{
|
||||
// @phpstan-ignore-next-line
|
||||
return $this->modelFor(City::class, 'City', $ipAddress);
|
||||
}
|
||||
/**
|
||||
* This method returns a GeoIP2 Country model.
|
||||
*
|
||||
* @param string $ipAddress an IPv4 or IPv6 address as a string
|
||||
*
|
||||
* @throws \GeoIp2\Exception\AddressNotFoundException if the address is
|
||||
* not in the database
|
||||
* @throws \MaxMind\Db\Reader\InvalidDatabaseException if the database
|
||||
* is corrupt or invalid
|
||||
*/
|
||||
public function country(string $ipAddress) : Country
|
||||
{
|
||||
// @phpstan-ignore-next-line
|
||||
return $this->modelFor(Country::class, 'Country', $ipAddress);
|
||||
}
|
||||
/**
|
||||
* This method returns a GeoIP2 Anonymous IP model.
|
||||
*
|
||||
* @param string $ipAddress an IPv4 or IPv6 address as a string
|
||||
*
|
||||
* @throws \GeoIp2\Exception\AddressNotFoundException if the address is
|
||||
* not in the database
|
||||
* @throws \MaxMind\Db\Reader\InvalidDatabaseException if the database
|
||||
* is corrupt or invalid
|
||||
*/
|
||||
public function anonymousIp(string $ipAddress) : AnonymousIp
|
||||
{
|
||||
// @phpstan-ignore-next-line
|
||||
return $this->flatModelFor(AnonymousIp::class, 'GeoIP2-Anonymous-IP', $ipAddress);
|
||||
}
|
||||
/**
|
||||
* This method returns a GeoLite2 ASN model.
|
||||
*
|
||||
* @param string $ipAddress an IPv4 or IPv6 address as a string
|
||||
*
|
||||
* @throws \GeoIp2\Exception\AddressNotFoundException if the address is
|
||||
* not in the database
|
||||
* @throws \MaxMind\Db\Reader\InvalidDatabaseException if the database
|
||||
* is corrupt or invalid
|
||||
*/
|
||||
public function asn(string $ipAddress) : Asn
|
||||
{
|
||||
// @phpstan-ignore-next-line
|
||||
return $this->flatModelFor(Asn::class, 'GeoLite2-ASN', $ipAddress);
|
||||
}
|
||||
/**
|
||||
* This method returns a GeoIP2 Connection Type model.
|
||||
*
|
||||
* @param string $ipAddress an IPv4 or IPv6 address as a string
|
||||
*
|
||||
* @throws \GeoIp2\Exception\AddressNotFoundException if the address is
|
||||
* not in the database
|
||||
* @throws \MaxMind\Db\Reader\InvalidDatabaseException if the database
|
||||
* is corrupt or invalid
|
||||
*/
|
||||
public function connectionType(string $ipAddress) : ConnectionType
|
||||
{
|
||||
// @phpstan-ignore-next-line
|
||||
return $this->flatModelFor(ConnectionType::class, 'GeoIP2-Connection-Type', $ipAddress);
|
||||
}
|
||||
/**
|
||||
* This method returns a GeoIP2 Domain model.
|
||||
*
|
||||
* @param string $ipAddress an IPv4 or IPv6 address as a string
|
||||
*
|
||||
* @throws \GeoIp2\Exception\AddressNotFoundException if the address is
|
||||
* not in the database
|
||||
* @throws \MaxMind\Db\Reader\InvalidDatabaseException if the database
|
||||
* is corrupt or invalid
|
||||
*/
|
||||
public function domain(string $ipAddress) : Domain
|
||||
{
|
||||
// @phpstan-ignore-next-line
|
||||
return $this->flatModelFor(Domain::class, 'GeoIP2-Domain', $ipAddress);
|
||||
}
|
||||
/**
|
||||
* This method returns a GeoIP2 Enterprise model.
|
||||
*
|
||||
* @param string $ipAddress an IPv4 or IPv6 address as a string
|
||||
*
|
||||
* @throws \GeoIp2\Exception\AddressNotFoundException if the address is
|
||||
* not in the database
|
||||
* @throws \MaxMind\Db\Reader\InvalidDatabaseException if the database
|
||||
* is corrupt or invalid
|
||||
*/
|
||||
public function enterprise(string $ipAddress) : Enterprise
|
||||
{
|
||||
// @phpstan-ignore-next-line
|
||||
return $this->modelFor(Enterprise::class, 'Enterprise', $ipAddress);
|
||||
}
|
||||
/**
|
||||
* This method returns a GeoIP2 ISP model.
|
||||
*
|
||||
* @param string $ipAddress an IPv4 or IPv6 address as a string
|
||||
*
|
||||
* @throws \GeoIp2\Exception\AddressNotFoundException if the address is
|
||||
* not in the database
|
||||
* @throws \MaxMind\Db\Reader\InvalidDatabaseException if the database
|
||||
* is corrupt or invalid
|
||||
*/
|
||||
public function isp(string $ipAddress) : Isp
|
||||
{
|
||||
// @phpstan-ignore-next-line
|
||||
return $this->flatModelFor(Isp::class, 'GeoIP2-ISP', $ipAddress);
|
||||
}
|
||||
private function modelFor(string $class, string $type, string $ipAddress) : AbstractModel
|
||||
{
|
||||
[$record, $prefixLen] = $this->getRecord($class, $type, $ipAddress);
|
||||
$record['traits']['ip_address'] = $ipAddress;
|
||||
$record['traits']['prefix_len'] = $prefixLen;
|
||||
return new $class($record, $this->locales);
|
||||
}
|
||||
private function flatModelFor(string $class, string $type, string $ipAddress) : AbstractModel
|
||||
{
|
||||
[$record, $prefixLen] = $this->getRecord($class, $type, $ipAddress);
|
||||
$record['ip_address'] = $ipAddress;
|
||||
$record['prefix_len'] = $prefixLen;
|
||||
return new $class($record);
|
||||
}
|
||||
private function getRecord(string $class, string $type, string $ipAddress) : array
|
||||
{
|
||||
if (\strpos($this->dbType, $type) === \false) {
|
||||
$method = \lcfirst((new \ReflectionClass($class))->getShortName());
|
||||
throw new \BadMethodCallException("The {$method} method cannot be used to open a {$this->dbType} database");
|
||||
}
|
||||
[$record, $prefixLen] = $this->dbReader->getWithPrefixLen($ipAddress);
|
||||
if ($record === null) {
|
||||
throw new AddressNotFoundException("The address {$ipAddress} is not in the database.");
|
||||
}
|
||||
if (!\is_array($record)) {
|
||||
// This can happen on corrupt databases. Generally,
|
||||
// MaxMind\Db\Reader will throw a
|
||||
// MaxMind\Db\Reader\InvalidDatabaseException, but occasionally
|
||||
// the lookup may result in a record that looks valid but is not
|
||||
// an array. This mostly happens when the user is ignoring all
|
||||
// exceptions and the more frequent InvalidDatabaseException
|
||||
// exceptions go unnoticed.
|
||||
throw new InvalidDatabaseException("Expected an array when looking up {$ipAddress} but received: " . \gettype($record));
|
||||
}
|
||||
return [$record, $prefixLen];
|
||||
}
|
||||
/**
|
||||
* @throws \InvalidArgumentException if arguments are passed to the method
|
||||
* @throws \BadMethodCallException if the database has been closed
|
||||
*
|
||||
* @return \MaxMind\Db\Reader\Metadata object for the database
|
||||
*/
|
||||
public function metadata() : DbReader\Metadata
|
||||
{
|
||||
return $this->dbReader->metadata();
|
||||
}
|
||||
/**
|
||||
* Closes the GeoIP2 database and returns the resources to the system.
|
||||
*/
|
||||
public function close() : void
|
||||
{
|
||||
$this->dbReader->close();
|
||||
}
|
||||
}
|
||||
11
plugins/system/tgeoip/vendor/geoip2/geoip2/src/Exception/AddressNotFoundException.php
vendored
Normal file
11
plugins/system/tgeoip/vendor/geoip2/geoip2/src/Exception/AddressNotFoundException.php
vendored
Normal file
@ -0,0 +1,11 @@
|
||||
<?php
|
||||
|
||||
declare (strict_types=1);
|
||||
namespace Tassos\Vendor\GeoIp2\Exception;
|
||||
|
||||
/**
|
||||
* This class represents a generic error.
|
||||
*/
|
||||
class AddressNotFoundException extends GeoIp2Exception
|
||||
{
|
||||
}
|
||||
11
plugins/system/tgeoip/vendor/geoip2/geoip2/src/Exception/AuthenticationException.php
vendored
Normal file
11
plugins/system/tgeoip/vendor/geoip2/geoip2/src/Exception/AuthenticationException.php
vendored
Normal file
@ -0,0 +1,11 @@
|
||||
<?php
|
||||
|
||||
declare (strict_types=1);
|
||||
namespace Tassos\Vendor\GeoIp2\Exception;
|
||||
|
||||
/**
|
||||
* This class represents a generic error.
|
||||
*/
|
||||
class AuthenticationException extends GeoIp2Exception
|
||||
{
|
||||
}
|
||||
11
plugins/system/tgeoip/vendor/geoip2/geoip2/src/Exception/GeoIp2Exception.php
vendored
Normal file
11
plugins/system/tgeoip/vendor/geoip2/geoip2/src/Exception/GeoIp2Exception.php
vendored
Normal file
@ -0,0 +1,11 @@
|
||||
<?php
|
||||
|
||||
declare (strict_types=1);
|
||||
namespace Tassos\Vendor\GeoIp2\Exception;
|
||||
|
||||
/**
|
||||
* This class represents a generic error.
|
||||
*/
|
||||
class GeoIp2Exception extends \Exception
|
||||
{
|
||||
}
|
||||
22
plugins/system/tgeoip/vendor/geoip2/geoip2/src/Exception/HttpException.php
vendored
Normal file
22
plugins/system/tgeoip/vendor/geoip2/geoip2/src/Exception/HttpException.php
vendored
Normal file
@ -0,0 +1,22 @@
|
||||
<?php
|
||||
|
||||
declare (strict_types=1);
|
||||
namespace Tassos\Vendor\GeoIp2\Exception;
|
||||
|
||||
/**
|
||||
* This class represents an HTTP transport error.
|
||||
*/
|
||||
class HttpException extends GeoIp2Exception
|
||||
{
|
||||
/**
|
||||
* The URI queried.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
public $uri;
|
||||
public function __construct(string $message, int $httpStatus, string $uri, \Exception $previous = null)
|
||||
{
|
||||
$this->uri = $uri;
|
||||
parent::__construct($message, $httpStatus, $previous);
|
||||
}
|
||||
}
|
||||
23
plugins/system/tgeoip/vendor/geoip2/geoip2/src/Exception/InvalidRequestException.php
vendored
Normal file
23
plugins/system/tgeoip/vendor/geoip2/geoip2/src/Exception/InvalidRequestException.php
vendored
Normal file
@ -0,0 +1,23 @@
|
||||
<?php
|
||||
|
||||
declare (strict_types=1);
|
||||
namespace Tassos\Vendor\GeoIp2\Exception;
|
||||
|
||||
/**
|
||||
* This class represents an error returned by MaxMind's GeoIP2
|
||||
* web service.
|
||||
*/
|
||||
class InvalidRequestException extends HttpException
|
||||
{
|
||||
/**
|
||||
* The code returned by the MaxMind web service.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
public $error;
|
||||
public function __construct(string $message, string $error, int $httpStatus, string $uri, \Exception $previous = null)
|
||||
{
|
||||
$this->error = $error;
|
||||
parent::__construct($message, $httpStatus, $uri, $previous);
|
||||
}
|
||||
}
|
||||
11
plugins/system/tgeoip/vendor/geoip2/geoip2/src/Exception/OutOfQueriesException.php
vendored
Normal file
11
plugins/system/tgeoip/vendor/geoip2/geoip2/src/Exception/OutOfQueriesException.php
vendored
Normal file
@ -0,0 +1,11 @@
|
||||
<?php
|
||||
|
||||
declare (strict_types=1);
|
||||
namespace Tassos\Vendor\GeoIp2\Exception;
|
||||
|
||||
/**
|
||||
* This class represents a generic error.
|
||||
*/
|
||||
class OutOfQueriesException extends GeoIp2Exception
|
||||
{
|
||||
}
|
||||
60
plugins/system/tgeoip/vendor/geoip2/geoip2/src/Model/AbstractModel.php
vendored
Normal file
60
plugins/system/tgeoip/vendor/geoip2/geoip2/src/Model/AbstractModel.php
vendored
Normal file
@ -0,0 +1,60 @@
|
||||
<?php
|
||||
|
||||
declare (strict_types=1);
|
||||
namespace Tassos\Vendor\GeoIp2\Model;
|
||||
|
||||
/**
|
||||
* @ignore
|
||||
*/
|
||||
abstract class AbstractModel implements \JsonSerializable
|
||||
{
|
||||
/**
|
||||
* @var array<string, mixed>
|
||||
*/
|
||||
protected $raw;
|
||||
/**
|
||||
* @ignore
|
||||
*/
|
||||
public function __construct(array $raw)
|
||||
{
|
||||
$this->raw = $raw;
|
||||
}
|
||||
/**
|
||||
* @ignore
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
protected function get(string $field)
|
||||
{
|
||||
if (isset($this->raw[$field])) {
|
||||
return $this->raw[$field];
|
||||
}
|
||||
if (\preg_match('/^is_/', $field)) {
|
||||
return \false;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
/**
|
||||
* @ignore
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
public function __get(string $attr)
|
||||
{
|
||||
if ($attr !== 'instance' && \property_exists($this, $attr)) {
|
||||
return $this->{$attr};
|
||||
}
|
||||
throw new \RuntimeException("Unknown attribute: {$attr}");
|
||||
}
|
||||
/**
|
||||
* @ignore
|
||||
*/
|
||||
public function __isset(string $attr) : bool
|
||||
{
|
||||
return $attr !== 'instance' && isset($this->{$attr});
|
||||
}
|
||||
public function jsonSerialize() : array
|
||||
{
|
||||
return $this->raw;
|
||||
}
|
||||
}
|
||||
80
plugins/system/tgeoip/vendor/geoip2/geoip2/src/Model/AnonymousIp.php
vendored
Normal file
80
plugins/system/tgeoip/vendor/geoip2/geoip2/src/Model/AnonymousIp.php
vendored
Normal file
@ -0,0 +1,80 @@
|
||||
<?php
|
||||
|
||||
declare (strict_types=1);
|
||||
namespace Tassos\Vendor\GeoIp2\Model;
|
||||
|
||||
use Tassos\Vendor\GeoIp2\Util;
|
||||
/**
|
||||
* This class provides the GeoIP2 Anonymous IP model.
|
||||
*
|
||||
* @property-read bool $isAnonymous This is true if the IP address belongs to
|
||||
* any sort of anonymous network.
|
||||
* @property-read bool $isAnonymousVpn This is true if the IP address is
|
||||
* registered to an anonymous VPN provider. If a VPN provider does not
|
||||
* register subnets under names associated with them, we will likely only
|
||||
* flag their IP ranges using the isHostingProvider property.
|
||||
* @property-read bool $isHostingProvider This is true if the IP address belongs
|
||||
* to a hosting or VPN provider (see description of isAnonymousVpn property).
|
||||
* @property-read bool $isPublicProxy This is true if the IP address belongs to
|
||||
* a public proxy.
|
||||
* @property-read bool $isResidentialProxy This is true if the IP address is
|
||||
* on a suspected anonymizing network and belongs to a residential ISP.
|
||||
* @property-read bool $isTorExitNode This is true if the IP address is a Tor
|
||||
* exit node.
|
||||
* @property-read string $ipAddress The IP address that the data in the model is
|
||||
* for.
|
||||
* @property-read string $network The network in CIDR notation associated with
|
||||
* the record. In particular, this is the largest network where all of the
|
||||
* fields besides $ipAddress have the same value.
|
||||
*/
|
||||
class AnonymousIp extends AbstractModel
|
||||
{
|
||||
/**
|
||||
* @var bool
|
||||
*/
|
||||
protected $isAnonymous;
|
||||
/**
|
||||
* @var bool
|
||||
*/
|
||||
protected $isAnonymousVpn;
|
||||
/**
|
||||
* @var bool
|
||||
*/
|
||||
protected $isHostingProvider;
|
||||
/**
|
||||
* @var bool
|
||||
*/
|
||||
protected $isPublicProxy;
|
||||
/**
|
||||
* @var bool
|
||||
*/
|
||||
protected $isResidentialProxy;
|
||||
/**
|
||||
* @var bool
|
||||
*/
|
||||
protected $isTorExitNode;
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
protected $ipAddress;
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
protected $network;
|
||||
/**
|
||||
* @ignore
|
||||
*/
|
||||
public function __construct(array $raw)
|
||||
{
|
||||
parent::__construct($raw);
|
||||
$this->isAnonymous = $this->get('is_anonymous');
|
||||
$this->isAnonymousVpn = $this->get('is_anonymous_vpn');
|
||||
$this->isHostingProvider = $this->get('is_hosting_provider');
|
||||
$this->isPublicProxy = $this->get('is_public_proxy');
|
||||
$this->isResidentialProxy = $this->get('is_residential_proxy');
|
||||
$this->isTorExitNode = $this->get('is_tor_exit_node');
|
||||
$ipAddress = $this->get('ip_address');
|
||||
$this->ipAddress = $ipAddress;
|
||||
$this->network = Util::cidr($ipAddress, $this->get('prefix_len'));
|
||||
}
|
||||
}
|
||||
51
plugins/system/tgeoip/vendor/geoip2/geoip2/src/Model/Asn.php
vendored
Normal file
51
plugins/system/tgeoip/vendor/geoip2/geoip2/src/Model/Asn.php
vendored
Normal file
@ -0,0 +1,51 @@
|
||||
<?php
|
||||
|
||||
declare (strict_types=1);
|
||||
namespace Tassos\Vendor\GeoIp2\Model;
|
||||
|
||||
use Tassos\Vendor\GeoIp2\Util;
|
||||
/**
|
||||
* This class provides the GeoLite2 ASN model.
|
||||
*
|
||||
* @property-read int|null $autonomousSystemNumber The autonomous system number
|
||||
* associated with the IP address.
|
||||
* @property-read string|null $autonomousSystemOrganization The organization
|
||||
* associated with the registered autonomous system number for the IP
|
||||
* address.
|
||||
* @property-read string $ipAddress The IP address that the data in the model is
|
||||
* for.
|
||||
* @property-read string $network The network in CIDR notation associated with
|
||||
* the record. In particular, this is the largest network where all of the
|
||||
* fields besides $ipAddress have the same value.
|
||||
*/
|
||||
class Asn extends AbstractModel
|
||||
{
|
||||
/**
|
||||
* @var int|null
|
||||
*/
|
||||
protected $autonomousSystemNumber;
|
||||
/**
|
||||
* @var string|null
|
||||
*/
|
||||
protected $autonomousSystemOrganization;
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
protected $ipAddress;
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
protected $network;
|
||||
/**
|
||||
* @ignore
|
||||
*/
|
||||
public function __construct(array $raw)
|
||||
{
|
||||
parent::__construct($raw);
|
||||
$this->autonomousSystemNumber = $this->get('autonomous_system_number');
|
||||
$this->autonomousSystemOrganization = $this->get('autonomous_system_organization');
|
||||
$ipAddress = $this->get('ip_address');
|
||||
$this->ipAddress = $ipAddress;
|
||||
$this->network = Util::cidr($ipAddress, $this->get('prefix_len'));
|
||||
}
|
||||
}
|
||||
105
plugins/system/tgeoip/vendor/geoip2/geoip2/src/Model/City.php
vendored
Normal file
105
plugins/system/tgeoip/vendor/geoip2/geoip2/src/Model/City.php
vendored
Normal file
@ -0,0 +1,105 @@
|
||||
<?php
|
||||
|
||||
declare (strict_types=1);
|
||||
namespace Tassos\Vendor\GeoIp2\Model;
|
||||
|
||||
/**
|
||||
* Model class for the data returned by City Plus web service and City
|
||||
* database.
|
||||
*
|
||||
* See https://dev.maxmind.com/geoip/docs/web-services?lang=en for more
|
||||
* details.
|
||||
*
|
||||
* @property-read \GeoIp2\Record\City $city City data for the requested IP
|
||||
* address.
|
||||
* @property-read \GeoIp2\Record\Location $location Location data for the
|
||||
* requested IP address.
|
||||
* @property-read \GeoIp2\Record\Postal $postal Postal data for the
|
||||
* requested IP address.
|
||||
* @property-read array $subdivisions An array \GeoIp2\Record\Subdivision
|
||||
* objects representing the country subdivisions for the requested IP
|
||||
* address. The number and type of subdivisions varies by country, but a
|
||||
* subdivision is typically a state, province, county, etc. Subdivisions
|
||||
* are ordered from most general (largest) to most specific (smallest).
|
||||
* If the response did not contain any subdivisions, this method returns
|
||||
* an empty array.
|
||||
* @property-read \GeoIp2\Record\Subdivision $mostSpecificSubdivision An object
|
||||
* representing the most specific subdivision returned. If the response
|
||||
* did not contain any subdivisions, this method returns an empty
|
||||
* \GeoIp2\Record\Subdivision object.
|
||||
*/
|
||||
class City extends Country
|
||||
{
|
||||
/**
|
||||
* @ignore
|
||||
*
|
||||
* @var \GeoIp2\Record\City
|
||||
*/
|
||||
protected $city;
|
||||
/**
|
||||
* @ignore
|
||||
*
|
||||
* @var \GeoIp2\Record\Location
|
||||
*/
|
||||
protected $location;
|
||||
/**
|
||||
* @ignore
|
||||
*
|
||||
* @var \GeoIp2\Record\Postal
|
||||
*/
|
||||
protected $postal;
|
||||
/**
|
||||
* @ignore
|
||||
*
|
||||
* @var array<\GeoIp2\Record\Subdivision>
|
||||
*/
|
||||
protected $subdivisions = [];
|
||||
/**
|
||||
* @ignore
|
||||
*/
|
||||
public function __construct(array $raw, array $locales = ['en'])
|
||||
{
|
||||
parent::__construct($raw, $locales);
|
||||
$this->city = new \Tassos\Vendor\GeoIp2\Record\City($this->get('city'), $locales);
|
||||
$this->location = new \Tassos\Vendor\GeoIp2\Record\Location($this->get('location'));
|
||||
$this->postal = new \Tassos\Vendor\GeoIp2\Record\Postal($this->get('postal'));
|
||||
$this->createSubdivisions($raw, $locales);
|
||||
}
|
||||
private function createSubdivisions(array $raw, array $locales) : void
|
||||
{
|
||||
if (!isset($raw['subdivisions'])) {
|
||||
return;
|
||||
}
|
||||
foreach ($raw['subdivisions'] as $sub) {
|
||||
$this->subdivisions[] = new \Tassos\Vendor\GeoIp2\Record\Subdivision($sub, $locales);
|
||||
}
|
||||
}
|
||||
/**
|
||||
* @ignore
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
public function __get(string $attr)
|
||||
{
|
||||
if ($attr === 'mostSpecificSubdivision') {
|
||||
return $this->{$attr}();
|
||||
}
|
||||
return parent::__get($attr);
|
||||
}
|
||||
/**
|
||||
* @ignore
|
||||
*/
|
||||
public function __isset(string $attr) : bool
|
||||
{
|
||||
if ($attr === 'mostSpecificSubdivision') {
|
||||
// We always return a mostSpecificSubdivision, even if it is the
|
||||
// empty subdivision
|
||||
return \true;
|
||||
}
|
||||
return parent::__isset($attr);
|
||||
}
|
||||
private function mostSpecificSubdivision() : \Tassos\Vendor\GeoIp2\Record\Subdivision
|
||||
{
|
||||
return empty($this->subdivisions) ? new \Tassos\Vendor\GeoIp2\Record\Subdivision([], $this->locales) : \end($this->subdivisions);
|
||||
}
|
||||
}
|
||||
44
plugins/system/tgeoip/vendor/geoip2/geoip2/src/Model/ConnectionType.php
vendored
Normal file
44
plugins/system/tgeoip/vendor/geoip2/geoip2/src/Model/ConnectionType.php
vendored
Normal file
@ -0,0 +1,44 @@
|
||||
<?php
|
||||
|
||||
declare (strict_types=1);
|
||||
namespace Tassos\Vendor\GeoIp2\Model;
|
||||
|
||||
use Tassos\Vendor\GeoIp2\Util;
|
||||
/**
|
||||
* This class provides the GeoIP2 Connection-Type model.
|
||||
*
|
||||
* @property-read string|null $connectionType The connection type may take the
|
||||
* following values: "Dialup", "Cable/DSL", "Corporate", "Cellular".
|
||||
* Additional values may be added in the future.
|
||||
* @property-read string $ipAddress The IP address that the data in the model is
|
||||
* for.
|
||||
* @property-read string $network The network in CIDR notation associated with
|
||||
* the record. In particular, this is the largest network where all of the
|
||||
* fields besides $ipAddress have the same value.
|
||||
*/
|
||||
class ConnectionType extends AbstractModel
|
||||
{
|
||||
/**
|
||||
* @var string|null
|
||||
*/
|
||||
protected $connectionType;
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
protected $ipAddress;
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
protected $network;
|
||||
/**
|
||||
* @ignore
|
||||
*/
|
||||
public function __construct(array $raw)
|
||||
{
|
||||
parent::__construct($raw);
|
||||
$this->connectionType = $this->get('connection_type');
|
||||
$ipAddress = $this->get('ip_address');
|
||||
$this->ipAddress = $ipAddress;
|
||||
$this->network = Util::cidr($ipAddress, $this->get('prefix_len'));
|
||||
}
|
||||
}
|
||||
74
plugins/system/tgeoip/vendor/geoip2/geoip2/src/Model/Country.php
vendored
Normal file
74
plugins/system/tgeoip/vendor/geoip2/geoip2/src/Model/Country.php
vendored
Normal file
@ -0,0 +1,74 @@
|
||||
<?php
|
||||
|
||||
declare (strict_types=1);
|
||||
namespace Tassos\Vendor\GeoIp2\Model;
|
||||
|
||||
/**
|
||||
* Model class for the data returned by GeoIP2 Country web service and database.
|
||||
*
|
||||
* See https://dev.maxmind.com/geoip/docs/web-services?lang=en for more details.
|
||||
*
|
||||
* @property-read \GeoIp2\Record\Continent $continent Continent data for the
|
||||
* requested IP address.
|
||||
* @property-read \GeoIp2\Record\Country $country Country data for the requested
|
||||
* IP address. This object represents the country where MaxMind believes the
|
||||
* end user is located.
|
||||
* @property-read \GeoIp2\Record\MaxMind $maxmind Data related to your MaxMind
|
||||
* account.
|
||||
* @property-read \GeoIp2\Record\Country $registeredCountry Registered country
|
||||
* data for the requested IP address. This record represents the country
|
||||
* where the ISP has registered a given IP block and may differ from the
|
||||
* user's country.
|
||||
* @property-read \GeoIp2\Record\RepresentedCountry $representedCountry
|
||||
* Represented country data for the requested IP address. The represented
|
||||
* country is used for things like military bases. It is only present when
|
||||
* the represented country differs from the country.
|
||||
* @property-read \GeoIp2\Record\Traits $traits Data for the traits of the
|
||||
* requested IP address.
|
||||
* @property-read array $raw The raw data from the web service.
|
||||
*/
|
||||
class Country extends AbstractModel
|
||||
{
|
||||
/**
|
||||
* @var \GeoIp2\Record\Continent
|
||||
*/
|
||||
protected $continent;
|
||||
/**
|
||||
* @var \GeoIp2\Record\Country
|
||||
*/
|
||||
protected $country;
|
||||
/**
|
||||
* @var array<string>
|
||||
*/
|
||||
protected $locales;
|
||||
/**
|
||||
* @var \GeoIp2\Record\MaxMind
|
||||
*/
|
||||
protected $maxmind;
|
||||
/**
|
||||
* @var \GeoIp2\Record\Country
|
||||
*/
|
||||
protected $registeredCountry;
|
||||
/**
|
||||
* @var \GeoIp2\Record\RepresentedCountry
|
||||
*/
|
||||
protected $representedCountry;
|
||||
/**
|
||||
* @var \GeoIp2\Record\Traits
|
||||
*/
|
||||
protected $traits;
|
||||
/**
|
||||
* @ignore
|
||||
*/
|
||||
public function __construct(array $raw, array $locales = ['en'])
|
||||
{
|
||||
parent::__construct($raw);
|
||||
$this->continent = new \Tassos\Vendor\GeoIp2\Record\Continent($this->get('continent'), $locales);
|
||||
$this->country = new \Tassos\Vendor\GeoIp2\Record\Country($this->get('country'), $locales);
|
||||
$this->maxmind = new \Tassos\Vendor\GeoIp2\Record\MaxMind($this->get('maxmind'));
|
||||
$this->registeredCountry = new \Tassos\Vendor\GeoIp2\Record\Country($this->get('registered_country'), $locales);
|
||||
$this->representedCountry = new \Tassos\Vendor\GeoIp2\Record\RepresentedCountry($this->get('represented_country'), $locales);
|
||||
$this->traits = new \Tassos\Vendor\GeoIp2\Record\Traits($this->get('traits'));
|
||||
$this->locales = $locales;
|
||||
}
|
||||
}
|
||||
44
plugins/system/tgeoip/vendor/geoip2/geoip2/src/Model/Domain.php
vendored
Normal file
44
plugins/system/tgeoip/vendor/geoip2/geoip2/src/Model/Domain.php
vendored
Normal file
@ -0,0 +1,44 @@
|
||||
<?php
|
||||
|
||||
declare (strict_types=1);
|
||||
namespace Tassos\Vendor\GeoIp2\Model;
|
||||
|
||||
use Tassos\Vendor\GeoIp2\Util;
|
||||
/**
|
||||
* This class provides the GeoIP2 Domain model.
|
||||
*
|
||||
* @property-read string|null $domain The second level domain associated with the
|
||||
* IP address. This will be something like "example.com" or
|
||||
* "example.co.uk", not "foo.example.com".
|
||||
* @property-read string $ipAddress The IP address that the data in the model is
|
||||
* for.
|
||||
* @property-read string $network The network in CIDR notation associated with
|
||||
* the record. In particular, this is the largest network where all of the
|
||||
* fields besides $ipAddress have the same value.
|
||||
*/
|
||||
class Domain extends AbstractModel
|
||||
{
|
||||
/**
|
||||
* @var string|null
|
||||
*/
|
||||
protected $domain;
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
protected $ipAddress;
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
protected $network;
|
||||
/**
|
||||
* @ignore
|
||||
*/
|
||||
public function __construct(array $raw)
|
||||
{
|
||||
parent::__construct($raw);
|
||||
$this->domain = $this->get('domain');
|
||||
$ipAddress = $this->get('ip_address');
|
||||
$this->ipAddress = $ipAddress;
|
||||
$this->network = Util::cidr($ipAddress, $this->get('prefix_len'));
|
||||
}
|
||||
}
|
||||
14
plugins/system/tgeoip/vendor/geoip2/geoip2/src/Model/Enterprise.php
vendored
Normal file
14
plugins/system/tgeoip/vendor/geoip2/geoip2/src/Model/Enterprise.php
vendored
Normal file
@ -0,0 +1,14 @@
|
||||
<?php
|
||||
|
||||
declare (strict_types=1);
|
||||
namespace Tassos\Vendor\GeoIp2\Model;
|
||||
|
||||
/**
|
||||
* Model class for the data returned by GeoIP2 Enterprise database lookups.
|
||||
*
|
||||
* See https://dev.maxmind.com/geoip/docs/web-services?lang=en for more
|
||||
* details.
|
||||
*/
|
||||
class Enterprise extends City
|
||||
{
|
||||
}
|
||||
14
plugins/system/tgeoip/vendor/geoip2/geoip2/src/Model/Insights.php
vendored
Normal file
14
plugins/system/tgeoip/vendor/geoip2/geoip2/src/Model/Insights.php
vendored
Normal file
@ -0,0 +1,14 @@
|
||||
<?php
|
||||
|
||||
declare (strict_types=1);
|
||||
namespace Tassos\Vendor\GeoIp2\Model;
|
||||
|
||||
/**
|
||||
* Model class for the data returned by GeoIP2 Insights web service.
|
||||
*
|
||||
* See https://dev.maxmind.com/geoip/docs/web-services?lang=en for
|
||||
* more details.
|
||||
*/
|
||||
class Insights extends City
|
||||
{
|
||||
}
|
||||
81
plugins/system/tgeoip/vendor/geoip2/geoip2/src/Model/Isp.php
vendored
Normal file
81
plugins/system/tgeoip/vendor/geoip2/geoip2/src/Model/Isp.php
vendored
Normal file
@ -0,0 +1,81 @@
|
||||
<?php
|
||||
|
||||
declare (strict_types=1);
|
||||
namespace Tassos\Vendor\GeoIp2\Model;
|
||||
|
||||
use Tassos\Vendor\GeoIp2\Util;
|
||||
/**
|
||||
* This class provides the GeoIP2 ISP model.
|
||||
*
|
||||
* @property-read int|null $autonomousSystemNumber The autonomous system number
|
||||
* associated with the IP address.
|
||||
* @property-read string|null $autonomousSystemOrganization The organization
|
||||
* associated with the registered autonomous system number for the IP
|
||||
* address.
|
||||
* @property-read string|null $isp The name of the ISP associated with the IP
|
||||
* address.
|
||||
* @property-read string|null $mobileCountryCode The [mobile country code
|
||||
* (MCC)](https://en.wikipedia.org/wiki/Mobile_country_code) associated with
|
||||
* the IP address and ISP.
|
||||
* @property-read string|null $mobileNetworkCode The [mobile network code
|
||||
* (MNC)](https://en.wikipedia.org/wiki/Mobile_country_code) associated with
|
||||
* the IP address and ISP.
|
||||
* @property-read string|null $organization The name of the organization associated
|
||||
* with the IP address.
|
||||
* @property-read string $ipAddress The IP address that the data in the model is
|
||||
* for.
|
||||
* @property-read string $network The network in CIDR notation associated with
|
||||
* the record. In particular, this is the largest network where all of the
|
||||
* fields besides $ipAddress have the same value.
|
||||
*/
|
||||
class Isp extends AbstractModel
|
||||
{
|
||||
/**
|
||||
* @var int|null
|
||||
*/
|
||||
protected $autonomousSystemNumber;
|
||||
/**
|
||||
* @var string|null
|
||||
*/
|
||||
protected $autonomousSystemOrganization;
|
||||
/**
|
||||
* @var string|null
|
||||
*/
|
||||
protected $isp;
|
||||
/**
|
||||
* @var string|null
|
||||
*/
|
||||
protected $mobileCountryCode;
|
||||
/**
|
||||
* @var string|null
|
||||
*/
|
||||
protected $mobileNetworkCode;
|
||||
/**
|
||||
* @var string|null
|
||||
*/
|
||||
protected $organization;
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
protected $ipAddress;
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
protected $network;
|
||||
/**
|
||||
* @ignore
|
||||
*/
|
||||
public function __construct(array $raw)
|
||||
{
|
||||
parent::__construct($raw);
|
||||
$this->autonomousSystemNumber = $this->get('autonomous_system_number');
|
||||
$this->autonomousSystemOrganization = $this->get('autonomous_system_organization');
|
||||
$this->isp = $this->get('isp');
|
||||
$this->mobileCountryCode = $this->get('mobile_country_code');
|
||||
$this->mobileNetworkCode = $this->get('mobile_network_code');
|
||||
$this->organization = $this->get('organization');
|
||||
$ipAddress = $this->get('ip_address');
|
||||
$this->ipAddress = $ipAddress;
|
||||
$this->network = Util::cidr($ipAddress, $this->get('prefix_len'));
|
||||
}
|
||||
}
|
||||
20
plugins/system/tgeoip/vendor/geoip2/geoip2/src/ProviderInterface.php
vendored
Normal file
20
plugins/system/tgeoip/vendor/geoip2/geoip2/src/ProviderInterface.php
vendored
Normal file
@ -0,0 +1,20 @@
|
||||
<?php
|
||||
|
||||
declare (strict_types=1);
|
||||
namespace Tassos\Vendor\GeoIp2;
|
||||
|
||||
interface ProviderInterface
|
||||
{
|
||||
/**
|
||||
* @param string $ipAddress an IPv4 or IPv6 address to lookup
|
||||
*
|
||||
* @return \GeoIp2\Model\Country a Country model for the requested IP address
|
||||
*/
|
||||
public function country(string $ipAddress) : Model\Country;
|
||||
/**
|
||||
* @param string $ipAddress an IPv4 or IPv6 address to lookup
|
||||
*
|
||||
* @return \GeoIp2\Model\City a City model for the requested IP address
|
||||
*/
|
||||
public function city(string $ipAddress) : Model\City;
|
||||
}
|
||||
57
plugins/system/tgeoip/vendor/geoip2/geoip2/src/Record/AbstractPlaceRecord.php
vendored
Normal file
57
plugins/system/tgeoip/vendor/geoip2/geoip2/src/Record/AbstractPlaceRecord.php
vendored
Normal file
@ -0,0 +1,57 @@
|
||||
<?php
|
||||
|
||||
declare (strict_types=1);
|
||||
namespace Tassos\Vendor\GeoIp2\Record;
|
||||
|
||||
abstract class AbstractPlaceRecord extends AbstractRecord
|
||||
{
|
||||
/**
|
||||
* @var array<string>
|
||||
*/
|
||||
private $locales;
|
||||
/**
|
||||
* @ignore
|
||||
*/
|
||||
public function __construct(?array $record, array $locales = ['en'])
|
||||
{
|
||||
$this->locales = $locales;
|
||||
parent::__construct($record);
|
||||
}
|
||||
/**
|
||||
* @ignore
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
public function __get(string $attr)
|
||||
{
|
||||
if ($attr === 'name') {
|
||||
return $this->name();
|
||||
}
|
||||
return parent::__get($attr);
|
||||
}
|
||||
/**
|
||||
* @ignore
|
||||
*/
|
||||
public function __isset(string $attr) : bool
|
||||
{
|
||||
if ($attr === 'name') {
|
||||
return $this->firstSetNameLocale() !== null;
|
||||
}
|
||||
return parent::__isset($attr);
|
||||
}
|
||||
private function name() : ?string
|
||||
{
|
||||
$locale = $this->firstSetNameLocale();
|
||||
// @phpstan-ignore-next-line
|
||||
return $locale === null ? null : $this->names[$locale];
|
||||
}
|
||||
private function firstSetNameLocale() : ?string
|
||||
{
|
||||
foreach ($this->locales as $locale) {
|
||||
if (isset($this->names[$locale])) {
|
||||
return $locale;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
56
plugins/system/tgeoip/vendor/geoip2/geoip2/src/Record/AbstractRecord.php
vendored
Normal file
56
plugins/system/tgeoip/vendor/geoip2/geoip2/src/Record/AbstractRecord.php
vendored
Normal file
@ -0,0 +1,56 @@
|
||||
<?php
|
||||
|
||||
declare (strict_types=1);
|
||||
namespace Tassos\Vendor\GeoIp2\Record;
|
||||
|
||||
abstract class AbstractRecord implements \JsonSerializable
|
||||
{
|
||||
/**
|
||||
* @var array<string, mixed>
|
||||
*/
|
||||
private $record;
|
||||
/**
|
||||
* @ignore
|
||||
*/
|
||||
public function __construct(?array $record)
|
||||
{
|
||||
$this->record = isset($record) ? $record : [];
|
||||
}
|
||||
/**
|
||||
* @ignore
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
public function __get(string $attr)
|
||||
{
|
||||
// XXX - kind of ugly but greatly reduces boilerplate code
|
||||
$key = $this->attributeToKey($attr);
|
||||
if ($this->__isset($attr)) {
|
||||
return $this->record[$key];
|
||||
}
|
||||
if ($this->validAttribute($attr)) {
|
||||
if (\preg_match('/^is_/', $key)) {
|
||||
return \false;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
throw new \RuntimeException("Unknown attribute: {$attr}");
|
||||
}
|
||||
public function __isset(string $attr) : bool
|
||||
{
|
||||
return $this->validAttribute($attr) && isset($this->record[$this->attributeToKey($attr)]);
|
||||
}
|
||||
private function attributeToKey(string $attr) : string
|
||||
{
|
||||
return \strtolower(\preg_replace('/([A-Z])/', '_\1', $attr));
|
||||
}
|
||||
private function validAttribute(string $attr) : bool
|
||||
{
|
||||
// @phpstan-ignore-next-line
|
||||
return \in_array($attr, $this->validAttributes, \true);
|
||||
}
|
||||
public function jsonSerialize() : ?array
|
||||
{
|
||||
return $this->record;
|
||||
}
|
||||
}
|
||||
32
plugins/system/tgeoip/vendor/geoip2/geoip2/src/Record/City.php
vendored
Normal file
32
plugins/system/tgeoip/vendor/geoip2/geoip2/src/Record/City.php
vendored
Normal file
@ -0,0 +1,32 @@
|
||||
<?php
|
||||
|
||||
declare (strict_types=1);
|
||||
namespace Tassos\Vendor\GeoIp2\Record;
|
||||
|
||||
/**
|
||||
* City-level data associated with an IP address.
|
||||
*
|
||||
* This record is returned by all location services and databases besides
|
||||
* Country.
|
||||
*
|
||||
* @property-read int|null $confidence A value from 0-100 indicating MaxMind's
|
||||
* confidence that the city is correct. This attribute is only available
|
||||
* from the Insights service and the GeoIP2 Enterprise database.
|
||||
* @property-read int|null $geonameId The GeoName ID for the city. This attribute
|
||||
* is returned by all location services and databases.
|
||||
* @property-read string|null $name The name of the city based on the locales list
|
||||
* passed to the constructor. This attribute is returned by all location
|
||||
* services and databases.
|
||||
* @property-read array|null $names An array map where the keys are locale codes
|
||||
* and the values are names. This attribute is returned by all location
|
||||
* services and databases.
|
||||
*/
|
||||
class City extends AbstractPlaceRecord
|
||||
{
|
||||
/**
|
||||
* @ignore
|
||||
*
|
||||
* @var array<string>
|
||||
*/
|
||||
protected $validAttributes = ['confidence', 'geonameId', 'names'];
|
||||
}
|
||||
31
plugins/system/tgeoip/vendor/geoip2/geoip2/src/Record/Continent.php
vendored
Normal file
31
plugins/system/tgeoip/vendor/geoip2/geoip2/src/Record/Continent.php
vendored
Normal file
@ -0,0 +1,31 @@
|
||||
<?php
|
||||
|
||||
declare (strict_types=1);
|
||||
namespace Tassos\Vendor\GeoIp2\Record;
|
||||
|
||||
/**
|
||||
* Contains data for the continent record associated with an IP address.
|
||||
*
|
||||
* This record is returned by all location services and databases.
|
||||
*
|
||||
* @property-read string|null $code A two character continent code like "NA" (North
|
||||
* America) or "OC" (Oceania). This attribute is returned by all location
|
||||
* services and databases.
|
||||
* @property-read int|null $geonameId The GeoName ID for the continent. This
|
||||
* attribute is returned by all location services and databases.
|
||||
* @property-read string|null $name Returns the name of the continent based on the
|
||||
* locales list passed to the constructor. This attribute is returned by all location
|
||||
* services and databases.
|
||||
* @property-read array|null $names An array map where the keys are locale codes
|
||||
* and the values are names. This attribute is returned by all location
|
||||
* services and databases.
|
||||
*/
|
||||
class Continent extends AbstractPlaceRecord
|
||||
{
|
||||
/**
|
||||
* @ignore
|
||||
*
|
||||
* @var array<string>
|
||||
*/
|
||||
protected $validAttributes = ['code', 'geonameId', 'names'];
|
||||
}
|
||||
37
plugins/system/tgeoip/vendor/geoip2/geoip2/src/Record/Country.php
vendored
Normal file
37
plugins/system/tgeoip/vendor/geoip2/geoip2/src/Record/Country.php
vendored
Normal file
@ -0,0 +1,37 @@
|
||||
<?php
|
||||
|
||||
declare (strict_types=1);
|
||||
namespace Tassos\Vendor\GeoIp2\Record;
|
||||
|
||||
/**
|
||||
* Contains data for the country record associated with an IP address.
|
||||
*
|
||||
* This record is returned by all location services and databases.
|
||||
*
|
||||
* @property-read int|null $confidence A value from 0-100 indicating MaxMind's
|
||||
* confidence that the country is correct. This attribute is only available
|
||||
* from the Insights service and the GeoIP2 Enterprise database.
|
||||
* @property-read int|null $geonameId The GeoName ID for the country. This
|
||||
* attribute is returned by all location services and databases.
|
||||
* @property-read bool $isInEuropeanUnion This is true if the country is a
|
||||
* member state of the European Union. This attribute is returned by all
|
||||
* location services and databases.
|
||||
* @property-read string|null $isoCode The two-character ISO 3166-1 alpha code
|
||||
* for the country. See https://en.wikipedia.org/wiki/ISO_3166-1. This
|
||||
* attribute is returned by all location services and databases.
|
||||
* @property-read string|null $name The name of the country based on the locales
|
||||
* list passed to the constructor. This attribute is returned by all location
|
||||
* services and databases.
|
||||
* @property-read array|null $names An array map where the keys are locale codes
|
||||
* and the values are names. This attribute is returned by all location
|
||||
* services and databases.
|
||||
*/
|
||||
class Country extends AbstractPlaceRecord
|
||||
{
|
||||
/**
|
||||
* @ignore
|
||||
*
|
||||
* @var array<string>
|
||||
*/
|
||||
protected $validAttributes = ['confidence', 'geonameId', 'isInEuropeanUnion', 'isoCode', 'names'];
|
||||
}
|
||||
45
plugins/system/tgeoip/vendor/geoip2/geoip2/src/Record/Location.php
vendored
Normal file
45
plugins/system/tgeoip/vendor/geoip2/geoip2/src/Record/Location.php
vendored
Normal file
@ -0,0 +1,45 @@
|
||||
<?php
|
||||
|
||||
declare (strict_types=1);
|
||||
namespace Tassos\Vendor\GeoIp2\Record;
|
||||
|
||||
/**
|
||||
* Contains data for the location record associated with an IP address.
|
||||
*
|
||||
* This record is returned by all location services and databases besides
|
||||
* Country.
|
||||
*
|
||||
* @property-read int|null $averageIncome The average income in US dollars
|
||||
* associated with the requested IP address. This attribute is only available
|
||||
* from the Insights service.
|
||||
* @property-read int|null $accuracyRadius The approximate accuracy radius in
|
||||
* kilometers around the latitude and longitude for the IP address. This is
|
||||
* the radius where we have a 67% confidence that the device using the IP
|
||||
* address resides within the circle centered at the latitude and longitude
|
||||
* with the provided radius.
|
||||
* @property-read float|null $latitude The approximate latitude of the location
|
||||
* associated with the IP address. This value is not precise and should not be
|
||||
* used to identify a particular address or household.
|
||||
* @property-read float|null $longitude The approximate longitude of the location
|
||||
* associated with the IP address. This value is not precise and should not be
|
||||
* used to identify a particular address or household.
|
||||
* @property-read int|null $populationDensity The estimated population per square
|
||||
* kilometer associated with the IP address. This attribute is only available
|
||||
* from the Insights service.
|
||||
* @property-read int|null $metroCode The metro code of the location if the location
|
||||
* is in the US. MaxMind returns the same metro codes as the
|
||||
* Google AdWords API. See
|
||||
* https://developers.google.com/adwords/api/docs/appendix/cities-DMAregions.
|
||||
* @property-read string|null $timeZone The time zone associated with location, as
|
||||
* specified by the IANA Time Zone Database, e.g., "America/New_York". See
|
||||
* https://www.iana.org/time-zones.
|
||||
*/
|
||||
class Location extends AbstractRecord
|
||||
{
|
||||
/**
|
||||
* @ignore
|
||||
*
|
||||
* @var array<string>
|
||||
*/
|
||||
protected $validAttributes = ['averageIncome', 'accuracyRadius', 'latitude', 'longitude', 'metroCode', 'populationDensity', 'postalCode', 'postalConfidence', 'timeZone'];
|
||||
}
|
||||
22
plugins/system/tgeoip/vendor/geoip2/geoip2/src/Record/MaxMind.php
vendored
Normal file
22
plugins/system/tgeoip/vendor/geoip2/geoip2/src/Record/MaxMind.php
vendored
Normal file
@ -0,0 +1,22 @@
|
||||
<?php
|
||||
|
||||
declare (strict_types=1);
|
||||
namespace Tassos\Vendor\GeoIp2\Record;
|
||||
|
||||
/**
|
||||
* Contains data about your account.
|
||||
*
|
||||
* This record is returned by all location services and databases.
|
||||
*
|
||||
* @property-read int|null $queriesRemaining The number of remaining queries you
|
||||
* have for the service you are calling.
|
||||
*/
|
||||
class MaxMind extends AbstractRecord
|
||||
{
|
||||
/**
|
||||
* @ignore
|
||||
*
|
||||
* @var array<string>
|
||||
*/
|
||||
protected $validAttributes = ['queriesRemaining'];
|
||||
}
|
||||
29
plugins/system/tgeoip/vendor/geoip2/geoip2/src/Record/Postal.php
vendored
Normal file
29
plugins/system/tgeoip/vendor/geoip2/geoip2/src/Record/Postal.php
vendored
Normal file
@ -0,0 +1,29 @@
|
||||
<?php
|
||||
|
||||
declare (strict_types=1);
|
||||
namespace Tassos\Vendor\GeoIp2\Record;
|
||||
|
||||
/**
|
||||
* Contains data for the postal record associated with an IP address.
|
||||
*
|
||||
* This record is returned by all location databases and services besides
|
||||
* Country.
|
||||
*
|
||||
* @property-read string|null $code The postal code of the location. Postal codes
|
||||
* are not available for all countries. In some countries, this will only
|
||||
* contain part of the postal code. This attribute is returned by all location
|
||||
* databases and services besides Country.
|
||||
* @property-read int|null $confidence A value from 0-100 indicating MaxMind's
|
||||
* confidence that the postal code is correct. This attribute is only
|
||||
* available from the Insights service and the GeoIP2 Enterprise
|
||||
* database.
|
||||
*/
|
||||
class Postal extends AbstractRecord
|
||||
{
|
||||
/**
|
||||
* @ignore
|
||||
*
|
||||
* @var array<string>
|
||||
*/
|
||||
protected $validAttributes = ['code', 'confidence'];
|
||||
}
|
||||
25
plugins/system/tgeoip/vendor/geoip2/geoip2/src/Record/RepresentedCountry.php
vendored
Normal file
25
plugins/system/tgeoip/vendor/geoip2/geoip2/src/Record/RepresentedCountry.php
vendored
Normal file
@ -0,0 +1,25 @@
|
||||
<?php
|
||||
|
||||
declare (strict_types=1);
|
||||
namespace Tassos\Vendor\GeoIp2\Record;
|
||||
|
||||
/**
|
||||
* Contains data for the represented country associated with an IP address.
|
||||
*
|
||||
* This class contains the country-level data associated with an IP address
|
||||
* for the IP's represented country. The represented country is the country
|
||||
* represented by something like a military base.
|
||||
*
|
||||
* @property-read string|null $type A string indicating the type of entity that is
|
||||
* representing the country. Currently we only return <code>military</code>
|
||||
* but this could expand to include other types in the future.
|
||||
*/
|
||||
class RepresentedCountry extends Country
|
||||
{
|
||||
/**
|
||||
* @ignore
|
||||
*
|
||||
* @var array<string>
|
||||
*/
|
||||
protected $validAttributes = ['confidence', 'geonameId', 'isInEuropeanUnion', 'isoCode', 'names', 'type'];
|
||||
}
|
||||
38
plugins/system/tgeoip/vendor/geoip2/geoip2/src/Record/Subdivision.php
vendored
Normal file
38
plugins/system/tgeoip/vendor/geoip2/geoip2/src/Record/Subdivision.php
vendored
Normal file
@ -0,0 +1,38 @@
|
||||
<?php
|
||||
|
||||
declare (strict_types=1);
|
||||
namespace Tassos\Vendor\GeoIp2\Record;
|
||||
|
||||
/**
|
||||
* Contains data for the subdivisions associated with an IP address.
|
||||
*
|
||||
* This record is returned by all location databases and services besides
|
||||
* Country.
|
||||
*
|
||||
* @property-read int|null $confidence This is a value from 0-100 indicating
|
||||
* MaxMind's confidence that the subdivision is correct. This attribute is
|
||||
* only available from the Insights service and the GeoIP2 Enterprise
|
||||
* database.
|
||||
* @property-read int|null $geonameId This is a GeoName ID for the subdivision.
|
||||
* This attribute is returned by all location databases and services besides
|
||||
* Country.
|
||||
* @property-read string|null $isoCode This is a string up to three characters long
|
||||
* contain the subdivision portion of the ISO 3166-2 code. See
|
||||
* https://en.wikipedia.org/wiki/ISO_3166-2. This attribute is returned by all
|
||||
* location databases and services except Country.
|
||||
* @property-read string|null $name The name of the subdivision based on the
|
||||
* locales list passed to the constructor. This attribute is returned by all
|
||||
* location databases and services besides Country.
|
||||
* @property-read array|null $names An array map where the keys are locale codes
|
||||
* and the values are names. This attribute is returned by all location
|
||||
* databases and services besides Country.
|
||||
*/
|
||||
class Subdivision extends AbstractPlaceRecord
|
||||
{
|
||||
/**
|
||||
* @ignore
|
||||
*
|
||||
* @var array<string>
|
||||
*/
|
||||
protected $validAttributes = ['confidence', 'geonameId', 'isoCode', 'names'];
|
||||
}
|
||||
131
plugins/system/tgeoip/vendor/geoip2/geoip2/src/Record/Traits.php
vendored
Normal file
131
plugins/system/tgeoip/vendor/geoip2/geoip2/src/Record/Traits.php
vendored
Normal file
@ -0,0 +1,131 @@
|
||||
<?php
|
||||
|
||||
declare (strict_types=1);
|
||||
namespace Tassos\Vendor\GeoIp2\Record;
|
||||
|
||||
use Tassos\Vendor\GeoIp2\Util;
|
||||
/**
|
||||
* Contains data for the traits record associated with an IP address.
|
||||
*
|
||||
* This record is returned by all location services and databases.
|
||||
*
|
||||
* @property-read int|null $autonomousSystemNumber The autonomous system number
|
||||
* associated with the IP address. See
|
||||
* https://en.wikipedia.org/wiki/Autonomous_system_(Internet%29. This attribute
|
||||
* is only available from the City Plus and Insights web services and the
|
||||
* GeoIP2 Enterprise database.
|
||||
* @property-read string|null $autonomousSystemOrganization The organization
|
||||
* associated with the registered autonomous system number for the IP address.
|
||||
* See https://en.wikipedia.org/wiki/Autonomous_system_(Internet%29. This
|
||||
* attribute is only available from the City Plus and Insights web services and
|
||||
* the GeoIP2 Enterprise database.
|
||||
* @property-read string|null $connectionType The connection type may take the
|
||||
* following values: "Dialup", "Cable/DSL", "Corporate", "Cellular".
|
||||
* Additional values may be added in the future. This attribute is only
|
||||
* available in the GeoIP2 Enterprise database.
|
||||
* @property-read string|null $domain The second level domain associated with the
|
||||
* IP address. This will be something like "example.com" or "example.co.uk",
|
||||
* not "foo.example.com". This attribute is only available from the
|
||||
* City Plus and Insights web services and the GeoIP2 Enterprise
|
||||
* database.
|
||||
* @property-read string $ipAddress The IP address that the data in the model
|
||||
* is for. If you performed a "me" lookup against the web service, this
|
||||
* will be the externally routable IP address for the system the code is
|
||||
* running on. If the system is behind a NAT, this may differ from the IP
|
||||
* address locally assigned to it. This attribute is returned by all end
|
||||
* points.
|
||||
* @property-read bool $isAnonymous This is true if the IP address belongs to
|
||||
* any sort of anonymous network. This property is only available from GeoIP2
|
||||
* Insights.
|
||||
* @property-read bool $isAnonymousProxy *Deprecated.* Please see our GeoIP2
|
||||
* Anonymous IP database
|
||||
* (https://www.maxmind.com/en/geoip2-anonymous-ip-database) to determine
|
||||
* whether the IP address is used by an anonymizing service.
|
||||
* @property-read bool $isAnonymousVpn This is true if the IP address is
|
||||
* registered to an anonymous VPN provider. If a VPN provider does not register
|
||||
* subnets under names associated with them, we will likely only flag their IP
|
||||
* ranges using the isHostingProvider property. This property is only available
|
||||
* from GeoIP2 Insights.
|
||||
* @property-read bool $isHostingProvider This is true if the IP address belongs
|
||||
* to a hosting or VPN provider (see description of isAnonymousVpn property).
|
||||
* This property is only available from GeoIP2 Insights.
|
||||
* @property-read bool $isLegitimateProxy This attribute is true if MaxMind
|
||||
* believes this IP address to be a legitimate proxy, such as an internal
|
||||
* VPN used by a corporation. This attribute is only available in the GeoIP2
|
||||
* Enterprise database.
|
||||
* @property-read bool $isPublicProxy This is true if the IP address belongs to
|
||||
* a public proxy. This property is only available from GeoIP2 Insights.
|
||||
* @property-read bool $isResidentialProxy This is true if the IP address is
|
||||
* on a suspected anonymizing network and belongs to a residential ISP. This
|
||||
* property is only available from GeoIP2 Insights.
|
||||
* @property-read bool $isSatelliteProvider *Deprecated.* Due to the
|
||||
* increased coverage by mobile carriers, very few satellite providers now
|
||||
* serve multiple countries. As a result, the output does not provide
|
||||
* sufficiently relevant data for us to maintain it.
|
||||
* @property-read bool $isTorExitNode This is true if the IP address is a Tor
|
||||
* exit node. This property is only available from GeoIP2 Insights.
|
||||
* @property-read string|null $isp The name of the ISP associated with the IP
|
||||
* address. This attribute is only available from the City Plus and Insights
|
||||
* web services and the GeoIP2 Enterprise database.
|
||||
* @property-read string $network The network in CIDR notation associated with
|
||||
* the record. In particular, this is the largest network where all of the
|
||||
* fields besides $ipAddress have the same value.
|
||||
* @property-read string|null $organization The name of the organization
|
||||
* associated with the IP address. This attribute is only available from the
|
||||
* City Plus and Insights web services and the GeoIP2 Enterprise database.
|
||||
* @property-read string|null $mobileCountryCode The [mobile country code
|
||||
* (MCC)](https://en.wikipedia.org/wiki/Mobile_country_code) associated with
|
||||
* the IP address and ISP. This property is available from the City Plus and
|
||||
* Insights web services and the GeoIP2 Enterprise database.
|
||||
* @property-read string|null $mobileNetworkCode The [mobile network code
|
||||
* (MNC)](https://en.wikipedia.org/wiki/Mobile_country_code) associated with
|
||||
* the IP address and ISP. This property is available from the City Plus and
|
||||
* Insights web services and the GeoIP2 Enterprise database.
|
||||
* @property-read float|null $staticIpScore An indicator of how static or
|
||||
* dynamic an IP address is. This property is only available from GeoIP2
|
||||
* Insights.
|
||||
* @property-read int|null $userCount The estimated number of users sharing
|
||||
* the IP/network during the past 24 hours. For IPv4, the count is for the
|
||||
* individual IP. For IPv6, the count is for the /64 network. This property is
|
||||
* only available from GeoIP2 Insights.
|
||||
* @property-read string|null $userType <p>The user type associated with the IP
|
||||
* address. This can be one of the following values:</p>
|
||||
* <ul>
|
||||
* <li>business
|
||||
* <li>cafe
|
||||
* <li>cellular
|
||||
* <li>college
|
||||
* <li>consumer_privacy_network
|
||||
* <li>content_delivery_network
|
||||
* <li>dialup
|
||||
* <li>government
|
||||
* <li>hosting
|
||||
* <li>library
|
||||
* <li>military
|
||||
* <li>residential
|
||||
* <li>router
|
||||
* <li>school
|
||||
* <li>search_engine_spider
|
||||
* <li>traveler
|
||||
* </ul>
|
||||
* <p>
|
||||
* This attribute is only available from the Insights web service and the
|
||||
* GeoIP2 Enterprise database.
|
||||
* </p>
|
||||
*/
|
||||
class Traits extends AbstractRecord
|
||||
{
|
||||
/**
|
||||
* @ignore
|
||||
*
|
||||
* @var array<string>
|
||||
*/
|
||||
protected $validAttributes = ['autonomousSystemNumber', 'autonomousSystemOrganization', 'connectionType', 'domain', 'ipAddress', 'isAnonymous', 'isAnonymousProxy', 'isAnonymousVpn', 'isHostingProvider', 'isLegitimateProxy', 'isp', 'isPublicProxy', 'isResidentialProxy', 'isSatelliteProvider', 'isTorExitNode', 'mobileCountryCode', 'mobileNetworkCode', 'network', 'organization', 'staticIpScore', 'userCount', 'userType'];
|
||||
public function __construct(?array $record)
|
||||
{
|
||||
if (!isset($record['network']) && isset($record['ip_address'], $record['prefix_len'])) {
|
||||
$record['network'] = Util::cidr($record['ip_address'], $record['prefix_len']);
|
||||
}
|
||||
parent::__construct($record);
|
||||
}
|
||||
}
|
||||
32
plugins/system/tgeoip/vendor/geoip2/geoip2/src/Util.php
vendored
Normal file
32
plugins/system/tgeoip/vendor/geoip2/geoip2/src/Util.php
vendored
Normal file
@ -0,0 +1,32 @@
|
||||
<?php
|
||||
|
||||
declare (strict_types=1);
|
||||
namespace Tassos\Vendor\GeoIp2;
|
||||
|
||||
class Util
|
||||
{
|
||||
/**
|
||||
* This returns the network in CIDR notation for the given IP and prefix
|
||||
* length. This is for internal use only.
|
||||
*
|
||||
* @internal
|
||||
* @ignore
|
||||
*/
|
||||
public static function cidr(string $ipAddress, int $prefixLen) : string
|
||||
{
|
||||
$ipBytes = \inet_pton($ipAddress);
|
||||
$networkBytes = \str_repeat("\x00", \strlen($ipBytes));
|
||||
$curPrefix = $prefixLen;
|
||||
for ($i = 0; $i < \strlen($ipBytes) && $curPrefix > 0; $i++) {
|
||||
$b = $ipBytes[$i];
|
||||
if ($curPrefix < 8) {
|
||||
$shiftN = 8 - $curPrefix;
|
||||
$b = \chr(0xff & \ord($b) >> $shiftN << $shiftN);
|
||||
}
|
||||
$networkBytes[$i] = $b;
|
||||
$curPrefix -= 8;
|
||||
}
|
||||
$network = \inet_ntop($networkBytes);
|
||||
return "{$network}/{$prefixLen}";
|
||||
}
|
||||
}
|
||||
207
plugins/system/tgeoip/vendor/geoip2/geoip2/src/WebService/Client.php
vendored
Normal file
207
plugins/system/tgeoip/vendor/geoip2/geoip2/src/WebService/Client.php
vendored
Normal file
@ -0,0 +1,207 @@
|
||||
<?php
|
||||
|
||||
declare (strict_types=1);
|
||||
namespace Tassos\Vendor\GeoIp2\WebService;
|
||||
|
||||
use Tassos\Vendor\GeoIp2\Exception\AddressNotFoundException;
|
||||
use Tassos\Vendor\GeoIp2\Exception\AuthenticationException;
|
||||
use Tassos\Vendor\GeoIp2\Exception\GeoIp2Exception;
|
||||
use Tassos\Vendor\GeoIp2\Exception\HttpException;
|
||||
use Tassos\Vendor\GeoIp2\Exception\InvalidRequestException;
|
||||
use Tassos\Vendor\GeoIp2\Exception\OutOfQueriesException;
|
||||
use Tassos\Vendor\GeoIp2\Model\City;
|
||||
use Tassos\Vendor\GeoIp2\Model\Country;
|
||||
use Tassos\Vendor\GeoIp2\Model\Insights;
|
||||
use Tassos\Vendor\GeoIp2\ProviderInterface;
|
||||
use Tassos\Vendor\MaxMind\WebService\Client as WsClient;
|
||||
/**
|
||||
* This class provides a client API for all the GeoIP2 web services.
|
||||
* The services are Country, City Plus, and Insights. Each service returns
|
||||
* a different set of data about an IP address, with Country returning the
|
||||
* least data and Insights the most.
|
||||
*
|
||||
* Each web service is represented by a different model class, and these model
|
||||
* classes in turn contain multiple record classes. The record classes have
|
||||
* attributes which contain data about the IP address.
|
||||
*
|
||||
* If the web service does not return a particular piece of data for an IP
|
||||
* address, the associated attribute is not populated.
|
||||
*
|
||||
* The web service may not return any information for an entire record, in
|
||||
* which case all of the attributes for that record class will be empty.
|
||||
*
|
||||
* ## Usage ##
|
||||
*
|
||||
* The basic API for this class is the same for all of the web service end
|
||||
* points. First you create a web service object with your MaxMind `$accountId`
|
||||
* and `$licenseKey`, then you call the method corresponding to a specific end
|
||||
* point, passing it the IP address you want to look up.
|
||||
*
|
||||
* If the request succeeds, the method call will return a model class for
|
||||
* the service you called. This model in turn contains multiple record
|
||||
* classes, each of which represents part of the data returned by the web
|
||||
* service.
|
||||
*
|
||||
* If the request fails, the client class throws an exception.
|
||||
*/
|
||||
class Client implements ProviderInterface
|
||||
{
|
||||
/**
|
||||
* @var array<string>
|
||||
*/
|
||||
private $locales;
|
||||
/**
|
||||
* @var WsClient
|
||||
*/
|
||||
private $client;
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
private static $basePath = '/geoip/v2.1';
|
||||
public const VERSION = 'v2.13.0';
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* @param int $accountId your MaxMind account ID
|
||||
* @param string $licenseKey your MaxMind license key
|
||||
* @param array $locales list of locale codes to use in name property
|
||||
* from most preferred to least preferred
|
||||
* @param array $options array of options. Valid options include:
|
||||
* * `host` - The host to use when querying the web
|
||||
* service. To query the GeoLite2 web service
|
||||
* instead of the GeoIP2 web service, set the
|
||||
* host to `geolite.info`.
|
||||
* * `timeout` - Timeout in seconds.
|
||||
* * `connectTimeout` - Initial connection timeout in seconds.
|
||||
* * `proxy` - The HTTP proxy to use. May include a schema, port,
|
||||
* username, and password, e.g.,
|
||||
* `http://username:password@127.0.0.1:10`.
|
||||
*/
|
||||
public function __construct(int $accountId, string $licenseKey, array $locales = ['en'], array $options = [])
|
||||
{
|
||||
$this->locales = $locales;
|
||||
// This is for backwards compatibility. Do not remove except for a
|
||||
// major version bump.
|
||||
// @phpstan-ignore-next-line
|
||||
if (\is_string($options)) {
|
||||
$options = ['host' => $options];
|
||||
}
|
||||
if (!isset($options['host'])) {
|
||||
$options['host'] = 'geoip.maxmind.com';
|
||||
}
|
||||
$options['userAgent'] = $this->userAgent();
|
||||
$this->client = new WsClient($accountId, $licenseKey, $options);
|
||||
}
|
||||
private function userAgent() : string
|
||||
{
|
||||
return 'GeoIP2-API/' . self::VERSION;
|
||||
}
|
||||
/**
|
||||
* This method calls the City Plus service.
|
||||
*
|
||||
* @param string $ipAddress IPv4 or IPv6 address as a string. If no
|
||||
* address is provided, the address that the web service is called
|
||||
* from will be used.
|
||||
*
|
||||
* @throws \GeoIp2\Exception\AddressNotFoundException if the address you
|
||||
* provided is not in our database (e.g., a private address).
|
||||
* @throws \GeoIp2\Exception\AuthenticationException if there is a problem
|
||||
* with the account ID or license key that you provided
|
||||
* @throws \GeoIp2\Exception\OutOfQueriesException if your account is out
|
||||
* of queries
|
||||
* @throws \GeoIp2\Exception\InvalidRequestException} if your request was received by the web service but is
|
||||
* invalid for some other reason. This may indicate an issue
|
||||
* with this API. Please report the error to MaxMind.
|
||||
* @throws \GeoIp2\Exception\HttpException if an unexpected HTTP error code or message was returned.
|
||||
* This could indicate a problem with the connection between
|
||||
* your server and the web service or that the web service
|
||||
* returned an invalid document or 500 error code
|
||||
* @throws \GeoIp2\Exception\GeoIp2Exception This serves as the parent
|
||||
* class to the above exceptions. It will be thrown directly
|
||||
* if a 200 status code is returned but the body is invalid.
|
||||
*/
|
||||
public function city(string $ipAddress = 'me') : City
|
||||
{
|
||||
// @phpstan-ignore-next-line
|
||||
return $this->responseFor('city', City::class, $ipAddress);
|
||||
}
|
||||
/**
|
||||
* This method calls the Country service.
|
||||
*
|
||||
* @param string $ipAddress IPv4 or IPv6 address as a string. If no
|
||||
* address is provided, the address that the web service is called
|
||||
* from will be used.
|
||||
*
|
||||
* @throws \GeoIp2\Exception\AddressNotFoundException if the address you provided is not in our database (e.g.,
|
||||
* a private address).
|
||||
* @throws \GeoIp2\Exception\AuthenticationException if there is a problem
|
||||
* with the account ID or license key that you provided
|
||||
* @throws \GeoIp2\Exception\OutOfQueriesException if your account is out of queries
|
||||
* @throws \GeoIp2\Exception\InvalidRequestException} if your request was received by the web service but is
|
||||
* invalid for some other reason. This may indicate an
|
||||
* issue with this API. Please report the error to MaxMind.
|
||||
* @throws \GeoIp2\Exception\HttpException if an unexpected HTTP error
|
||||
* code or message was returned. This could indicate a problem
|
||||
* with the connection between your server and the web service
|
||||
* or that the web service returned an invalid document or 500
|
||||
* error code.
|
||||
* @throws \GeoIp2\Exception\GeoIp2Exception This serves as the parent class to the above exceptions. It
|
||||
* will be thrown directly if a 200 status code is returned but
|
||||
* the body is invalid.
|
||||
*/
|
||||
public function country(string $ipAddress = 'me') : Country
|
||||
{
|
||||
return $this->responseFor('country', Country::class, $ipAddress);
|
||||
}
|
||||
/**
|
||||
* This method calls the Insights service. Insights is only supported by
|
||||
* the GeoIP2 web service. The GeoLite2 web service does not support it.
|
||||
*
|
||||
* @param string $ipAddress IPv4 or IPv6 address as a string. If no
|
||||
* address is provided, the address that the web service is called
|
||||
* from will be used.
|
||||
*
|
||||
* @throws \GeoIp2\Exception\AddressNotFoundException if the address you
|
||||
* provided is not in our database (e.g., a private address).
|
||||
* @throws \GeoIp2\Exception\AuthenticationException if there is a problem
|
||||
* with the account ID or license key that you provided
|
||||
* @throws \GeoIp2\Exception\OutOfQueriesException if your account is out
|
||||
* of queries
|
||||
* @throws \GeoIp2\Exception\InvalidRequestException} if your request was received by the web service but is
|
||||
* invalid for some other reason. This may indicate an
|
||||
* issue with this API. Please report the error to MaxMind.
|
||||
* @throws \GeoIp2\Exception\HttpException if an unexpected HTTP error code or message was returned.
|
||||
* This could indicate a problem with the connection between
|
||||
* your server and the web service or that the web service
|
||||
* returned an invalid document or 500 error code
|
||||
* @throws \GeoIp2\Exception\GeoIp2Exception This serves as the parent
|
||||
* class to the above exceptions. It will be thrown directly
|
||||
* if a 200 status code is returned but the body is invalid.
|
||||
*/
|
||||
public function insights(string $ipAddress = 'me') : Insights
|
||||
{
|
||||
// @phpstan-ignore-next-line
|
||||
return $this->responseFor('insights', Insights::class, $ipAddress);
|
||||
}
|
||||
private function responseFor(string $endpoint, string $class, string $ipAddress) : Country
|
||||
{
|
||||
$path = \implode('/', [self::$basePath, $endpoint, $ipAddress]);
|
||||
try {
|
||||
$service = (new \ReflectionClass($class))->getShortName();
|
||||
$body = $this->client->get('GeoIP2 ' . $service, $path);
|
||||
} catch (\Tassos\Vendor\MaxMind\Exception\IpAddressNotFoundException $ex) {
|
||||
throw new AddressNotFoundException($ex->getMessage(), $ex->getStatusCode(), $ex);
|
||||
} catch (\Tassos\Vendor\MaxMind\Exception\AuthenticationException $ex) {
|
||||
throw new AuthenticationException($ex->getMessage(), $ex->getStatusCode(), $ex);
|
||||
} catch (\Tassos\Vendor\MaxMind\Exception\InsufficientFundsException $ex) {
|
||||
throw new OutOfQueriesException($ex->getMessage(), $ex->getStatusCode(), $ex);
|
||||
} catch (\Tassos\Vendor\MaxMind\Exception\InvalidRequestException $ex) {
|
||||
throw new InvalidRequestException($ex->getMessage(), $ex->getErrorCode(), $ex->getStatusCode(), $ex->getUri(), $ex);
|
||||
} catch (\Tassos\Vendor\MaxMind\Exception\HttpException $ex) {
|
||||
throw new HttpException($ex->getMessage(), $ex->getStatusCode(), $ex->getUri(), $ex);
|
||||
} catch (\Tassos\Vendor\MaxMind\Exception\WebServiceException $ex) {
|
||||
throw new GeoIp2Exception($ex->getMessage(), $ex->getCode(), $ex);
|
||||
}
|
||||
return new $class($body, $this->locales);
|
||||
}
|
||||
}
|
||||
42
plugins/system/tgeoip/vendor/maxmind-db/reader/autoload.php
vendored
Normal file
42
plugins/system/tgeoip/vendor/maxmind-db/reader/autoload.php
vendored
Normal file
@ -0,0 +1,42 @@
|
||||
<?php
|
||||
|
||||
declare (strict_types=1);
|
||||
namespace Tassos\Vendor;
|
||||
|
||||
/**
|
||||
* PSR-4 autoloader implementation for the MaxMind\DB namespace.
|
||||
* First we define the 'mmdb_autoload' function, and then we register
|
||||
* it with 'spl_autoload_register' so that PHP knows to use it.
|
||||
*
|
||||
* @param mixed $class
|
||||
*/
|
||||
/**
|
||||
* Automatically include the file that defines <code>class</code>.
|
||||
*
|
||||
* @param string $class
|
||||
* the name of the class to load
|
||||
*/
|
||||
function mmdb_autoload($class) : void
|
||||
{
|
||||
/*
|
||||
* A project-specific mapping between the namespaces and where
|
||||
* they're located. By convention, we include the trailing
|
||||
* slashes. The one-element array here simply makes things easy
|
||||
* to extend in the future if (for example) the test classes
|
||||
* begin to use one another.
|
||||
*/
|
||||
$namespace_map = ['MaxMind\\Db\\' => __DIR__ . '/src/MaxMind/Db/'];
|
||||
foreach ($namespace_map as $prefix => $dir) {
|
||||
// First swap out the namespace prefix with a directory...
|
||||
$path = \str_replace($prefix, $dir, $class);
|
||||
// replace the namespace separator with a directory separator...
|
||||
$path = \str_replace('\\', '/', $path);
|
||||
// and finally, add the PHP file extension to the result.
|
||||
$path = $path . '.php';
|
||||
// $path should now contain the path to a PHP file defining $class
|
||||
if (\file_exists($path)) {
|
||||
include $path;
|
||||
}
|
||||
}
|
||||
}
|
||||
\spl_autoload_register('mmdb_autoload');
|
||||
40
plugins/system/tgeoip/vendor/maxmind-db/reader/ext/config.m4
vendored
Normal file
40
plugins/system/tgeoip/vendor/maxmind-db/reader/ext/config.m4
vendored
Normal file
@ -0,0 +1,40 @@
|
||||
PHP_ARG_WITH(maxminddb,
|
||||
[Whether to enable the MaxMind DB Reader extension],
|
||||
[ --with-maxminddb Enable MaxMind DB Reader extension support])
|
||||
|
||||
PHP_ARG_ENABLE(maxminddb-debug, for MaxMind DB debug support,
|
||||
[ --enable-maxminddb-debug Enable enable MaxMind DB deubg support], no, no)
|
||||
|
||||
if test $PHP_MAXMINDDB != "no"; then
|
||||
|
||||
AC_PATH_PROG(PKG_CONFIG, pkg-config, no)
|
||||
|
||||
AC_MSG_CHECKING(for libmaxminddb)
|
||||
if test -x "$PKG_CONFIG" && $PKG_CONFIG --exists libmaxminddb; then
|
||||
dnl retrieve build options from pkg-config
|
||||
if $PKG_CONFIG libmaxminddb --atleast-version 1.0.0; then
|
||||
LIBMAXMINDDB_INC=`$PKG_CONFIG libmaxminddb --cflags`
|
||||
LIBMAXMINDDB_LIB=`$PKG_CONFIG libmaxminddb --libs`
|
||||
LIBMAXMINDDB_VER=`$PKG_CONFIG libmaxminddb --modversion`
|
||||
AC_MSG_RESULT(found version $LIBMAXMINDDB_VER)
|
||||
else
|
||||
AC_MSG_ERROR(system libmaxminddb must be upgraded to version >= 1.0.0)
|
||||
fi
|
||||
PHP_EVAL_LIBLINE($LIBMAXMINDDB_LIB, MAXMINDDB_SHARED_LIBADD)
|
||||
PHP_EVAL_INCLINE($LIBMAXMINDDB_INC)
|
||||
else
|
||||
AC_MSG_RESULT(pkg-config information missing)
|
||||
AC_MSG_WARN(will use libmaxmxinddb from compiler default path)
|
||||
|
||||
PHP_CHECK_LIBRARY(maxminddb, MMDB_open)
|
||||
PHP_ADD_LIBRARY(maxminddb, 1, MAXMINDDB_SHARED_LIBADD)
|
||||
fi
|
||||
|
||||
if test $PHP_MAXMINDDB_DEBUG != "no"; then
|
||||
CFLAGS="$CFLAGS -Wall -Wextra -Wno-unused-parameter -Wno-missing-field-initializers -Werror"
|
||||
fi
|
||||
|
||||
PHP_SUBST(MAXMINDDB_SHARED_LIBADD)
|
||||
|
||||
PHP_NEW_EXTENSION(maxminddb, maxminddb.c, $ext_shared)
|
||||
fi
|
||||
10
plugins/system/tgeoip/vendor/maxmind-db/reader/ext/config.w32
vendored
Normal file
10
plugins/system/tgeoip/vendor/maxmind-db/reader/ext/config.w32
vendored
Normal file
@ -0,0 +1,10 @@
|
||||
ARG_WITH("maxminddb", "Enable MaxMind DB Reader extension support", "no");
|
||||
|
||||
if (PHP_MAXMINDDB == "yes") {
|
||||
if (CHECK_HEADER_ADD_INCLUDE("maxminddb.h", "CFLAGS_MAXMINDDB", PHP_MAXMINDDB + ";" + PHP_PHP_BUILD + "\\include\\maxminddb") &&
|
||||
CHECK_LIB("libmaxminddb.lib", "maxminddb", PHP_MAXMINDDB)) {
|
||||
EXTENSION("maxminddb", "maxminddb.c");
|
||||
} else {
|
||||
WARNING('Could not find maxminddb.h or libmaxminddb.lib; skipping');
|
||||
}
|
||||
}
|
||||
811
plugins/system/tgeoip/vendor/maxmind-db/reader/ext/maxminddb.c
vendored
Normal file
811
plugins/system/tgeoip/vendor/maxmind-db/reader/ext/maxminddb.c
vendored
Normal file
@ -0,0 +1,811 @@
|
||||
/* MaxMind, Inc., licenses this file to you under the Apache License, Version
|
||||
* 2.0 (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
* License for the specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
|
||||
#include "php_maxminddb.h"
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include "config.h"
|
||||
#endif
|
||||
|
||||
#include <php.h>
|
||||
#include <zend.h>
|
||||
|
||||
#include "Zend/zend_exceptions.h"
|
||||
#include "Zend/zend_types.h"
|
||||
#include "ext/spl/spl_exceptions.h"
|
||||
#include "ext/standard/info.h"
|
||||
#include <maxminddb.h>
|
||||
|
||||
#ifdef ZTS
|
||||
#include <TSRM.h>
|
||||
#endif
|
||||
|
||||
#define __STDC_FORMAT_MACROS
|
||||
#include <inttypes.h>
|
||||
|
||||
#define PHP_MAXMINDDB_NS ZEND_NS_NAME("MaxMind", "Db")
|
||||
#define PHP_MAXMINDDB_READER_NS ZEND_NS_NAME(PHP_MAXMINDDB_NS, "Reader")
|
||||
#define PHP_MAXMINDDB_METADATA_NS \
|
||||
ZEND_NS_NAME(PHP_MAXMINDDB_READER_NS, "Metadata")
|
||||
#define PHP_MAXMINDDB_READER_EX_NS \
|
||||
ZEND_NS_NAME(PHP_MAXMINDDB_READER_NS, "InvalidDatabaseException")
|
||||
|
||||
#define Z_MAXMINDDB_P(zv) php_maxminddb_fetch_object(Z_OBJ_P(zv))
|
||||
typedef size_t strsize_t;
|
||||
typedef zend_object free_obj_t;
|
||||
|
||||
/* For PHP 8 compatibility */
|
||||
#if PHP_VERSION_ID < 80000
|
||||
|
||||
#define PROP_OBJ(zv) (zv)
|
||||
|
||||
#else
|
||||
|
||||
#define PROP_OBJ(zv) Z_OBJ_P(zv)
|
||||
|
||||
#define TSRMLS_C
|
||||
#define TSRMLS_CC
|
||||
#define TSRMLS_DC
|
||||
|
||||
/* End PHP 8 compatibility */
|
||||
#endif
|
||||
|
||||
#ifndef ZEND_ACC_CTOR
|
||||
#define ZEND_ACC_CTOR 0
|
||||
#endif
|
||||
|
||||
/* IS_MIXED was added in 2020 */
|
||||
#ifndef IS_MIXED
|
||||
#define IS_MIXED IS_UNDEF
|
||||
#endif
|
||||
|
||||
/* ZEND_THIS was added in 7.4 */
|
||||
#ifndef ZEND_THIS
|
||||
#define ZEND_THIS (&EX(This))
|
||||
#endif
|
||||
|
||||
typedef struct _maxminddb_obj {
|
||||
MMDB_s *mmdb;
|
||||
zend_object std;
|
||||
} maxminddb_obj;
|
||||
|
||||
PHP_FUNCTION(maxminddb);
|
||||
|
||||
static int
|
||||
get_record(INTERNAL_FUNCTION_PARAMETERS, zval *record, int *prefix_len);
|
||||
static const MMDB_entry_data_list_s *
|
||||
handle_entry_data_list(const MMDB_entry_data_list_s *entry_data_list,
|
||||
zval *z_value TSRMLS_DC);
|
||||
static const MMDB_entry_data_list_s *
|
||||
handle_array(const MMDB_entry_data_list_s *entry_data_list,
|
||||
zval *z_value TSRMLS_DC);
|
||||
static const MMDB_entry_data_list_s *
|
||||
handle_map(const MMDB_entry_data_list_s *entry_data_list,
|
||||
zval *z_value TSRMLS_DC);
|
||||
static void handle_uint128(const MMDB_entry_data_list_s *entry_data_list,
|
||||
zval *z_value TSRMLS_DC);
|
||||
static void handle_uint64(const MMDB_entry_data_list_s *entry_data_list,
|
||||
zval *z_value TSRMLS_DC);
|
||||
static void handle_uint32(const MMDB_entry_data_list_s *entry_data_list,
|
||||
zval *z_value TSRMLS_DC);
|
||||
|
||||
#define CHECK_ALLOCATED(val) \
|
||||
if (!val) { \
|
||||
zend_error(E_ERROR, "Out of memory"); \
|
||||
return; \
|
||||
}
|
||||
|
||||
static zend_object_handlers maxminddb_obj_handlers;
|
||||
static zend_class_entry *maxminddb_ce, *maxminddb_exception_ce, *metadata_ce;
|
||||
|
||||
static inline maxminddb_obj *
|
||||
php_maxminddb_fetch_object(zend_object *obj TSRMLS_DC) {
|
||||
return (maxminddb_obj *)((char *)(obj)-XtOffsetOf(maxminddb_obj, std));
|
||||
}
|
||||
|
||||
ZEND_BEGIN_ARG_INFO_EX(arginfo_maxminddbreader_construct, 0, 0, 1)
|
||||
ZEND_ARG_TYPE_INFO(0, db_file, IS_STRING, 0)
|
||||
ZEND_END_ARG_INFO()
|
||||
|
||||
PHP_METHOD(MaxMind_Db_Reader, __construct) {
|
||||
char *db_file = NULL;
|
||||
strsize_t name_len;
|
||||
zval *_this_zval = NULL;
|
||||
|
||||
if (zend_parse_method_parameters(ZEND_NUM_ARGS() TSRMLS_CC,
|
||||
getThis(),
|
||||
"Os",
|
||||
&_this_zval,
|
||||
maxminddb_ce,
|
||||
&db_file,
|
||||
&name_len) == FAILURE) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (0 != php_check_open_basedir(db_file TSRMLS_CC) ||
|
||||
0 != access(db_file, R_OK)) {
|
||||
zend_throw_exception_ex(
|
||||
spl_ce_InvalidArgumentException,
|
||||
0 TSRMLS_CC,
|
||||
"The file \"%s\" does not exist or is not readable.",
|
||||
db_file);
|
||||
return;
|
||||
}
|
||||
|
||||
MMDB_s *mmdb = (MMDB_s *)ecalloc(1, sizeof(MMDB_s));
|
||||
uint16_t status = MMDB_open(db_file, MMDB_MODE_MMAP, mmdb);
|
||||
|
||||
if (MMDB_SUCCESS != status) {
|
||||
zend_throw_exception_ex(
|
||||
maxminddb_exception_ce,
|
||||
0 TSRMLS_CC,
|
||||
"Error opening database file (%s). Is this a valid "
|
||||
"MaxMind DB file?",
|
||||
db_file);
|
||||
efree(mmdb);
|
||||
return;
|
||||
}
|
||||
|
||||
maxminddb_obj *mmdb_obj = Z_MAXMINDDB_P(ZEND_THIS);
|
||||
mmdb_obj->mmdb = mmdb;
|
||||
}
|
||||
|
||||
ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(
|
||||
arginfo_maxminddbreader_get, 0, 1, IS_MIXED, 1)
|
||||
ZEND_ARG_TYPE_INFO(0, ip_address, IS_STRING, 0)
|
||||
ZEND_END_ARG_INFO()
|
||||
|
||||
PHP_METHOD(MaxMind_Db_Reader, get) {
|
||||
int prefix_len = 0;
|
||||
get_record(INTERNAL_FUNCTION_PARAM_PASSTHRU, return_value, &prefix_len);
|
||||
}
|
||||
|
||||
ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(
|
||||
arginfo_maxminddbreader_getWithPrefixLen, 0, 1, IS_ARRAY, 1)
|
||||
ZEND_ARG_TYPE_INFO(0, ip_address, IS_STRING, 0)
|
||||
ZEND_END_ARG_INFO()
|
||||
|
||||
PHP_METHOD(MaxMind_Db_Reader, getWithPrefixLen) {
|
||||
zval record, z_prefix_len;
|
||||
|
||||
int prefix_len = 0;
|
||||
if (get_record(INTERNAL_FUNCTION_PARAM_PASSTHRU, &record, &prefix_len) ==
|
||||
FAILURE) {
|
||||
return;
|
||||
}
|
||||
|
||||
array_init(return_value);
|
||||
add_next_index_zval(return_value, &record);
|
||||
|
||||
ZVAL_LONG(&z_prefix_len, prefix_len);
|
||||
add_next_index_zval(return_value, &z_prefix_len);
|
||||
}
|
||||
|
||||
static int
|
||||
get_record(INTERNAL_FUNCTION_PARAMETERS, zval *record, int *prefix_len) {
|
||||
char *ip_address = NULL;
|
||||
strsize_t name_len;
|
||||
zval *this_zval = NULL;
|
||||
|
||||
if (zend_parse_method_parameters(ZEND_NUM_ARGS() TSRMLS_CC,
|
||||
getThis(),
|
||||
"Os",
|
||||
&this_zval,
|
||||
maxminddb_ce,
|
||||
&ip_address,
|
||||
&name_len) == FAILURE) {
|
||||
return FAILURE;
|
||||
}
|
||||
|
||||
const maxminddb_obj *mmdb_obj = (maxminddb_obj *)Z_MAXMINDDB_P(ZEND_THIS);
|
||||
|
||||
MMDB_s *mmdb = mmdb_obj->mmdb;
|
||||
|
||||
if (NULL == mmdb) {
|
||||
zend_throw_exception_ex(spl_ce_BadMethodCallException,
|
||||
0 TSRMLS_CC,
|
||||
"Attempt to read from a closed MaxMind DB.");
|
||||
return FAILURE;
|
||||
}
|
||||
|
||||
struct addrinfo hints = {
|
||||
.ai_family = AF_UNSPEC,
|
||||
.ai_flags = AI_NUMERICHOST,
|
||||
/* We set ai_socktype so that we only get one result back */
|
||||
.ai_socktype = SOCK_STREAM};
|
||||
|
||||
struct addrinfo *addresses = NULL;
|
||||
int gai_status = getaddrinfo(ip_address, NULL, &hints, &addresses);
|
||||
if (gai_status) {
|
||||
zend_throw_exception_ex(spl_ce_InvalidArgumentException,
|
||||
0 TSRMLS_CC,
|
||||
"The value \"%s\" is not a valid IP address.",
|
||||
ip_address);
|
||||
return FAILURE;
|
||||
}
|
||||
if (!addresses || !addresses->ai_addr) {
|
||||
zend_throw_exception_ex(
|
||||
spl_ce_InvalidArgumentException,
|
||||
0 TSRMLS_CC,
|
||||
"getaddrinfo was successful but failed to set the addrinfo");
|
||||
return FAILURE;
|
||||
}
|
||||
|
||||
int sa_family = addresses->ai_addr->sa_family;
|
||||
|
||||
int mmdb_error = MMDB_SUCCESS;
|
||||
MMDB_lookup_result_s result =
|
||||
MMDB_lookup_sockaddr(mmdb, addresses->ai_addr, &mmdb_error);
|
||||
|
||||
freeaddrinfo(addresses);
|
||||
|
||||
if (MMDB_SUCCESS != mmdb_error) {
|
||||
zend_class_entry *ex;
|
||||
if (MMDB_IPV6_LOOKUP_IN_IPV4_DATABASE_ERROR == mmdb_error) {
|
||||
ex = spl_ce_InvalidArgumentException;
|
||||
} else {
|
||||
ex = maxminddb_exception_ce;
|
||||
}
|
||||
zend_throw_exception_ex(ex,
|
||||
0 TSRMLS_CC,
|
||||
"Error looking up %s. %s",
|
||||
ip_address,
|
||||
MMDB_strerror(mmdb_error));
|
||||
return FAILURE;
|
||||
}
|
||||
|
||||
*prefix_len = result.netmask;
|
||||
|
||||
if (sa_family == AF_INET && mmdb->metadata.ip_version == 6) {
|
||||
/* We return the prefix length given the IPv4 address. If there is
|
||||
no IPv4 subtree, we return a prefix length of 0. */
|
||||
*prefix_len = *prefix_len >= 96 ? *prefix_len - 96 : 0;
|
||||
}
|
||||
|
||||
if (!result.found_entry) {
|
||||
ZVAL_NULL(record);
|
||||
return SUCCESS;
|
||||
}
|
||||
|
||||
MMDB_entry_data_list_s *entry_data_list = NULL;
|
||||
int status = MMDB_get_entry_data_list(&result.entry, &entry_data_list);
|
||||
|
||||
if (MMDB_SUCCESS != status) {
|
||||
zend_throw_exception_ex(maxminddb_exception_ce,
|
||||
0 TSRMLS_CC,
|
||||
"Error while looking up data for %s. %s",
|
||||
ip_address,
|
||||
MMDB_strerror(status));
|
||||
MMDB_free_entry_data_list(entry_data_list);
|
||||
return FAILURE;
|
||||
} else if (NULL == entry_data_list) {
|
||||
zend_throw_exception_ex(
|
||||
maxminddb_exception_ce,
|
||||
0 TSRMLS_CC,
|
||||
"Error while looking up data for %s. Your database may "
|
||||
"be corrupt or you have found a bug in libmaxminddb.",
|
||||
ip_address);
|
||||
return FAILURE;
|
||||
}
|
||||
|
||||
const MMDB_entry_data_list_s *rv =
|
||||
handle_entry_data_list(entry_data_list, record TSRMLS_CC);
|
||||
if (rv == NULL) {
|
||||
/* We should have already thrown the exception in handle_entry_data_list
|
||||
*/
|
||||
return FAILURE;
|
||||
}
|
||||
MMDB_free_entry_data_list(entry_data_list);
|
||||
return SUCCESS;
|
||||
}
|
||||
|
||||
ZEND_BEGIN_ARG_INFO_EX(arginfo_maxminddbreader_void, 0, 0, 0)
|
||||
ZEND_END_ARG_INFO()
|
||||
|
||||
PHP_METHOD(MaxMind_Db_Reader, metadata) {
|
||||
zval *this_zval = NULL;
|
||||
|
||||
if (zend_parse_method_parameters(ZEND_NUM_ARGS() TSRMLS_CC,
|
||||
getThis(),
|
||||
"O",
|
||||
&this_zval,
|
||||
maxminddb_ce) == FAILURE) {
|
||||
return;
|
||||
}
|
||||
|
||||
const maxminddb_obj *const mmdb_obj =
|
||||
(maxminddb_obj *)Z_MAXMINDDB_P(this_zval);
|
||||
|
||||
if (NULL == mmdb_obj->mmdb) {
|
||||
zend_throw_exception_ex(spl_ce_BadMethodCallException,
|
||||
0 TSRMLS_CC,
|
||||
"Attempt to read from a closed MaxMind DB.");
|
||||
return;
|
||||
}
|
||||
|
||||
object_init_ex(return_value, metadata_ce);
|
||||
|
||||
MMDB_entry_data_list_s *entry_data_list;
|
||||
MMDB_get_metadata_as_entry_data_list(mmdb_obj->mmdb, &entry_data_list);
|
||||
|
||||
zval metadata_array;
|
||||
const MMDB_entry_data_list_s *rv =
|
||||
handle_entry_data_list(entry_data_list, &metadata_array TSRMLS_CC);
|
||||
if (rv == NULL) {
|
||||
return;
|
||||
}
|
||||
MMDB_free_entry_data_list(entry_data_list);
|
||||
zend_call_method_with_1_params(PROP_OBJ(return_value),
|
||||
metadata_ce,
|
||||
&metadata_ce->constructor,
|
||||
ZEND_CONSTRUCTOR_FUNC_NAME,
|
||||
NULL,
|
||||
&metadata_array);
|
||||
zval_ptr_dtor(&metadata_array);
|
||||
}
|
||||
|
||||
PHP_METHOD(MaxMind_Db_Reader, close) {
|
||||
zval *this_zval = NULL;
|
||||
|
||||
if (zend_parse_method_parameters(ZEND_NUM_ARGS() TSRMLS_CC,
|
||||
getThis(),
|
||||
"O",
|
||||
&this_zval,
|
||||
maxminddb_ce) == FAILURE) {
|
||||
return;
|
||||
}
|
||||
|
||||
maxminddb_obj *mmdb_obj = (maxminddb_obj *)Z_MAXMINDDB_P(this_zval);
|
||||
|
||||
if (NULL == mmdb_obj->mmdb) {
|
||||
zend_throw_exception_ex(spl_ce_BadMethodCallException,
|
||||
0 TSRMLS_CC,
|
||||
"Attempt to close a closed MaxMind DB.");
|
||||
return;
|
||||
}
|
||||
MMDB_close(mmdb_obj->mmdb);
|
||||
efree(mmdb_obj->mmdb);
|
||||
mmdb_obj->mmdb = NULL;
|
||||
}
|
||||
|
||||
static const MMDB_entry_data_list_s *
|
||||
handle_entry_data_list(const MMDB_entry_data_list_s *entry_data_list,
|
||||
zval *z_value TSRMLS_DC) {
|
||||
switch (entry_data_list->entry_data.type) {
|
||||
case MMDB_DATA_TYPE_MAP:
|
||||
return handle_map(entry_data_list, z_value TSRMLS_CC);
|
||||
case MMDB_DATA_TYPE_ARRAY:
|
||||
return handle_array(entry_data_list, z_value TSRMLS_CC);
|
||||
case MMDB_DATA_TYPE_UTF8_STRING:
|
||||
ZVAL_STRINGL(z_value,
|
||||
(char *)entry_data_list->entry_data.utf8_string,
|
||||
entry_data_list->entry_data.data_size);
|
||||
break;
|
||||
case MMDB_DATA_TYPE_BYTES:
|
||||
ZVAL_STRINGL(z_value,
|
||||
(char *)entry_data_list->entry_data.bytes,
|
||||
entry_data_list->entry_data.data_size);
|
||||
break;
|
||||
case MMDB_DATA_TYPE_DOUBLE:
|
||||
ZVAL_DOUBLE(z_value, entry_data_list->entry_data.double_value);
|
||||
break;
|
||||
case MMDB_DATA_TYPE_FLOAT:
|
||||
ZVAL_DOUBLE(z_value, entry_data_list->entry_data.float_value);
|
||||
break;
|
||||
case MMDB_DATA_TYPE_UINT16:
|
||||
ZVAL_LONG(z_value, entry_data_list->entry_data.uint16);
|
||||
break;
|
||||
case MMDB_DATA_TYPE_UINT32:
|
||||
handle_uint32(entry_data_list, z_value TSRMLS_CC);
|
||||
break;
|
||||
case MMDB_DATA_TYPE_BOOLEAN:
|
||||
ZVAL_BOOL(z_value, entry_data_list->entry_data.boolean);
|
||||
break;
|
||||
case MMDB_DATA_TYPE_UINT64:
|
||||
handle_uint64(entry_data_list, z_value TSRMLS_CC);
|
||||
break;
|
||||
case MMDB_DATA_TYPE_UINT128:
|
||||
handle_uint128(entry_data_list, z_value TSRMLS_CC);
|
||||
break;
|
||||
case MMDB_DATA_TYPE_INT32:
|
||||
ZVAL_LONG(z_value, entry_data_list->entry_data.int32);
|
||||
break;
|
||||
default:
|
||||
zend_throw_exception_ex(maxminddb_exception_ce,
|
||||
0 TSRMLS_CC,
|
||||
"Invalid data type arguments: %d",
|
||||
entry_data_list->entry_data.type);
|
||||
return NULL;
|
||||
}
|
||||
return entry_data_list;
|
||||
}
|
||||
|
||||
static const MMDB_entry_data_list_s *
|
||||
handle_map(const MMDB_entry_data_list_s *entry_data_list,
|
||||
zval *z_value TSRMLS_DC) {
|
||||
array_init(z_value);
|
||||
const uint32_t map_size = entry_data_list->entry_data.data_size;
|
||||
|
||||
uint32_t i;
|
||||
for (i = 0; i < map_size && entry_data_list; i++) {
|
||||
entry_data_list = entry_data_list->next;
|
||||
|
||||
char *key = estrndup((char *)entry_data_list->entry_data.utf8_string,
|
||||
entry_data_list->entry_data.data_size);
|
||||
if (NULL == key) {
|
||||
zend_throw_exception_ex(maxminddb_exception_ce,
|
||||
0 TSRMLS_CC,
|
||||
"Invalid data type arguments");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
entry_data_list = entry_data_list->next;
|
||||
zval new_value;
|
||||
entry_data_list =
|
||||
handle_entry_data_list(entry_data_list, &new_value TSRMLS_CC);
|
||||
if (entry_data_list != NULL) {
|
||||
add_assoc_zval(z_value, key, &new_value);
|
||||
}
|
||||
efree(key);
|
||||
}
|
||||
return entry_data_list;
|
||||
}
|
||||
|
||||
static const MMDB_entry_data_list_s *
|
||||
handle_array(const MMDB_entry_data_list_s *entry_data_list,
|
||||
zval *z_value TSRMLS_DC) {
|
||||
const uint32_t size = entry_data_list->entry_data.data_size;
|
||||
|
||||
array_init(z_value);
|
||||
|
||||
uint32_t i;
|
||||
for (i = 0; i < size && entry_data_list; i++) {
|
||||
entry_data_list = entry_data_list->next;
|
||||
zval new_value;
|
||||
entry_data_list =
|
||||
handle_entry_data_list(entry_data_list, &new_value TSRMLS_CC);
|
||||
if (entry_data_list != NULL) {
|
||||
add_next_index_zval(z_value, &new_value);
|
||||
}
|
||||
}
|
||||
return entry_data_list;
|
||||
}
|
||||
|
||||
static void handle_uint128(const MMDB_entry_data_list_s *entry_data_list,
|
||||
zval *z_value TSRMLS_DC) {
|
||||
uint64_t high = 0;
|
||||
uint64_t low = 0;
|
||||
#if MMDB_UINT128_IS_BYTE_ARRAY
|
||||
int i;
|
||||
for (i = 0; i < 8; i++) {
|
||||
high = (high << 8) | entry_data_list->entry_data.uint128[i];
|
||||
}
|
||||
|
||||
for (i = 8; i < 16; i++) {
|
||||
low = (low << 8) | entry_data_list->entry_data.uint128[i];
|
||||
}
|
||||
#else
|
||||
high = entry_data_list->entry_data.uint128 >> 64;
|
||||
low = (uint64_t)entry_data_list->entry_data.uint128;
|
||||
#endif
|
||||
|
||||
char *num_str;
|
||||
spprintf(&num_str, 0, "0x%016" PRIX64 "%016" PRIX64, high, low);
|
||||
CHECK_ALLOCATED(num_str);
|
||||
|
||||
ZVAL_STRING(z_value, num_str);
|
||||
efree(num_str);
|
||||
}
|
||||
|
||||
static void handle_uint32(const MMDB_entry_data_list_s *entry_data_list,
|
||||
zval *z_value TSRMLS_DC) {
|
||||
uint32_t val = entry_data_list->entry_data.uint32;
|
||||
|
||||
#if LONG_MAX >= UINT32_MAX
|
||||
ZVAL_LONG(z_value, val);
|
||||
return;
|
||||
#else
|
||||
if (val <= LONG_MAX) {
|
||||
ZVAL_LONG(z_value, val);
|
||||
return;
|
||||
}
|
||||
|
||||
char *int_str;
|
||||
spprintf(&int_str, 0, "%" PRIu32, val);
|
||||
CHECK_ALLOCATED(int_str);
|
||||
|
||||
ZVAL_STRING(z_value, int_str);
|
||||
efree(int_str);
|
||||
#endif
|
||||
}
|
||||
|
||||
static void handle_uint64(const MMDB_entry_data_list_s *entry_data_list,
|
||||
zval *z_value TSRMLS_DC) {
|
||||
uint64_t val = entry_data_list->entry_data.uint64;
|
||||
|
||||
#if LONG_MAX >= UINT64_MAX
|
||||
ZVAL_LONG(z_value, val);
|
||||
return;
|
||||
#else
|
||||
if (val <= LONG_MAX) {
|
||||
ZVAL_LONG(z_value, val);
|
||||
return;
|
||||
}
|
||||
|
||||
char *int_str;
|
||||
spprintf(&int_str, 0, "%" PRIu64, val);
|
||||
CHECK_ALLOCATED(int_str);
|
||||
|
||||
ZVAL_STRING(z_value, int_str);
|
||||
efree(int_str);
|
||||
#endif
|
||||
}
|
||||
|
||||
static void maxminddb_free_storage(free_obj_t *object TSRMLS_DC) {
|
||||
maxminddb_obj *obj =
|
||||
php_maxminddb_fetch_object((zend_object *)object TSRMLS_CC);
|
||||
if (obj->mmdb != NULL) {
|
||||
MMDB_close(obj->mmdb);
|
||||
efree(obj->mmdb);
|
||||
}
|
||||
|
||||
zend_object_std_dtor(&obj->std TSRMLS_CC);
|
||||
}
|
||||
|
||||
static zend_object *maxminddb_create_handler(zend_class_entry *type TSRMLS_DC) {
|
||||
maxminddb_obj *obj = (maxminddb_obj *)ecalloc(1, sizeof(maxminddb_obj));
|
||||
zend_object_std_init(&obj->std, type TSRMLS_CC);
|
||||
object_properties_init(&(obj->std), type);
|
||||
|
||||
obj->std.handlers = &maxminddb_obj_handlers;
|
||||
|
||||
return &obj->std;
|
||||
}
|
||||
|
||||
/* clang-format off */
|
||||
static zend_function_entry maxminddb_methods[] = {
|
||||
PHP_ME(MaxMind_Db_Reader, __construct, arginfo_maxminddbreader_construct,
|
||||
ZEND_ACC_PUBLIC | ZEND_ACC_CTOR)
|
||||
PHP_ME(MaxMind_Db_Reader, close, arginfo_maxminddbreader_void, ZEND_ACC_PUBLIC)
|
||||
PHP_ME(MaxMind_Db_Reader, get, arginfo_maxminddbreader_get, ZEND_ACC_PUBLIC)
|
||||
PHP_ME(MaxMind_Db_Reader, getWithPrefixLen, arginfo_maxminddbreader_getWithPrefixLen, ZEND_ACC_PUBLIC)
|
||||
PHP_ME(MaxMind_Db_Reader, metadata, arginfo_maxminddbreader_void, ZEND_ACC_PUBLIC)
|
||||
{ NULL, NULL, NULL }
|
||||
};
|
||||
/* clang-format on */
|
||||
|
||||
ZEND_BEGIN_ARG_INFO_EX(arginfo_metadata_construct, 0, 0, 1)
|
||||
ZEND_ARG_TYPE_INFO(0, metadata, IS_ARRAY, 0)
|
||||
ZEND_END_ARG_INFO()
|
||||
|
||||
PHP_METHOD(MaxMind_Db_Reader_Metadata, __construct) {
|
||||
zval *object = NULL;
|
||||
zval *metadata_array = NULL;
|
||||
zend_long node_count = 0;
|
||||
zend_long record_size = 0;
|
||||
|
||||
if (zend_parse_method_parameters(ZEND_NUM_ARGS() TSRMLS_CC,
|
||||
getThis(),
|
||||
"Oa",
|
||||
&object,
|
||||
metadata_ce,
|
||||
&metadata_array) == FAILURE) {
|
||||
return;
|
||||
}
|
||||
|
||||
zval *tmp = NULL;
|
||||
if ((tmp = zend_hash_str_find(HASH_OF(metadata_array),
|
||||
"binary_format_major_version",
|
||||
sizeof("binary_format_major_version") - 1))) {
|
||||
zend_update_property(metadata_ce,
|
||||
PROP_OBJ(object),
|
||||
"binaryFormatMajorVersion",
|
||||
sizeof("binaryFormatMajorVersion") - 1,
|
||||
tmp);
|
||||
}
|
||||
|
||||
if ((tmp = zend_hash_str_find(HASH_OF(metadata_array),
|
||||
"binary_format_minor_version",
|
||||
sizeof("binary_format_minor_version") - 1))) {
|
||||
zend_update_property(metadata_ce,
|
||||
PROP_OBJ(object),
|
||||
"binaryFormatMinorVersion",
|
||||
sizeof("binaryFormatMinorVersion") - 1,
|
||||
tmp);
|
||||
}
|
||||
|
||||
if ((tmp = zend_hash_str_find(HASH_OF(metadata_array),
|
||||
"build_epoch",
|
||||
sizeof("build_epoch") - 1))) {
|
||||
zend_update_property(metadata_ce,
|
||||
PROP_OBJ(object),
|
||||
"buildEpoch",
|
||||
sizeof("buildEpoch") - 1,
|
||||
tmp);
|
||||
}
|
||||
|
||||
if ((tmp = zend_hash_str_find(HASH_OF(metadata_array),
|
||||
"database_type",
|
||||
sizeof("database_type") - 1))) {
|
||||
zend_update_property(metadata_ce,
|
||||
PROP_OBJ(object),
|
||||
"databaseType",
|
||||
sizeof("databaseType") - 1,
|
||||
tmp);
|
||||
}
|
||||
|
||||
if ((tmp = zend_hash_str_find(HASH_OF(metadata_array),
|
||||
"description",
|
||||
sizeof("description") - 1))) {
|
||||
zend_update_property(metadata_ce,
|
||||
PROP_OBJ(object),
|
||||
"description",
|
||||
sizeof("description") - 1,
|
||||
tmp);
|
||||
}
|
||||
|
||||
if ((tmp = zend_hash_str_find(HASH_OF(metadata_array),
|
||||
"ip_version",
|
||||
sizeof("ip_version") - 1))) {
|
||||
zend_update_property(metadata_ce,
|
||||
PROP_OBJ(object),
|
||||
"ipVersion",
|
||||
sizeof("ipVersion") - 1,
|
||||
tmp);
|
||||
}
|
||||
|
||||
if ((tmp = zend_hash_str_find(
|
||||
HASH_OF(metadata_array), "languages", sizeof("languages") - 1))) {
|
||||
zend_update_property(metadata_ce,
|
||||
PROP_OBJ(object),
|
||||
"languages",
|
||||
sizeof("languages") - 1,
|
||||
tmp);
|
||||
}
|
||||
|
||||
if ((tmp = zend_hash_str_find(HASH_OF(metadata_array),
|
||||
"record_size",
|
||||
sizeof("record_size") - 1))) {
|
||||
zend_update_property(metadata_ce,
|
||||
PROP_OBJ(object),
|
||||
"recordSize",
|
||||
sizeof("recordSize") - 1,
|
||||
tmp);
|
||||
if (Z_TYPE_P(tmp) == IS_LONG) {
|
||||
record_size = Z_LVAL_P(tmp);
|
||||
}
|
||||
}
|
||||
|
||||
if (record_size != 0) {
|
||||
zend_update_property_long(metadata_ce,
|
||||
PROP_OBJ(object),
|
||||
"nodeByteSize",
|
||||
sizeof("nodeByteSize") - 1,
|
||||
record_size / 4);
|
||||
}
|
||||
|
||||
if ((tmp = zend_hash_str_find(HASH_OF(metadata_array),
|
||||
"node_count",
|
||||
sizeof("node_count") - 1))) {
|
||||
zend_update_property(metadata_ce,
|
||||
PROP_OBJ(object),
|
||||
"nodeCount",
|
||||
sizeof("nodeCount") - 1,
|
||||
tmp);
|
||||
if (Z_TYPE_P(tmp) == IS_LONG) {
|
||||
node_count = Z_LVAL_P(tmp);
|
||||
}
|
||||
}
|
||||
|
||||
if (record_size != 0) {
|
||||
zend_update_property_long(metadata_ce,
|
||||
PROP_OBJ(object),
|
||||
"searchTreeSize",
|
||||
sizeof("searchTreeSize") - 1,
|
||||
record_size * node_count / 4);
|
||||
}
|
||||
}
|
||||
|
||||
// clang-format off
|
||||
static zend_function_entry metadata_methods[] = {
|
||||
PHP_ME(MaxMind_Db_Reader_Metadata, __construct, arginfo_metadata_construct, ZEND_ACC_PUBLIC | ZEND_ACC_CTOR)
|
||||
{NULL, NULL, NULL}
|
||||
};
|
||||
// clang-format on
|
||||
|
||||
PHP_MINIT_FUNCTION(maxminddb) {
|
||||
zend_class_entry ce;
|
||||
|
||||
INIT_CLASS_ENTRY(ce, PHP_MAXMINDDB_READER_EX_NS, NULL);
|
||||
maxminddb_exception_ce =
|
||||
zend_register_internal_class_ex(&ce, zend_ce_exception);
|
||||
|
||||
INIT_CLASS_ENTRY(ce, PHP_MAXMINDDB_READER_NS, maxminddb_methods);
|
||||
maxminddb_ce = zend_register_internal_class(&ce TSRMLS_CC);
|
||||
maxminddb_ce->create_object = maxminddb_create_handler;
|
||||
|
||||
INIT_CLASS_ENTRY(ce, PHP_MAXMINDDB_METADATA_NS, metadata_methods);
|
||||
metadata_ce = zend_register_internal_class(&ce TSRMLS_CC);
|
||||
zend_declare_property_null(metadata_ce,
|
||||
"binaryFormatMajorVersion",
|
||||
sizeof("binaryFormatMajorVersion") - 1,
|
||||
ZEND_ACC_PUBLIC);
|
||||
zend_declare_property_null(metadata_ce,
|
||||
"binaryFormatMinorVersion",
|
||||
sizeof("binaryFormatMinorVersion") - 1,
|
||||
ZEND_ACC_PUBLIC);
|
||||
zend_declare_property_null(
|
||||
metadata_ce, "buildEpoch", sizeof("buildEpoch") - 1, ZEND_ACC_PUBLIC);
|
||||
zend_declare_property_null(metadata_ce,
|
||||
"databaseType",
|
||||
sizeof("databaseType") - 1,
|
||||
ZEND_ACC_PUBLIC);
|
||||
zend_declare_property_null(
|
||||
metadata_ce, "description", sizeof("description") - 1, ZEND_ACC_PUBLIC);
|
||||
zend_declare_property_null(
|
||||
metadata_ce, "ipVersion", sizeof("ipVersion") - 1, ZEND_ACC_PUBLIC);
|
||||
zend_declare_property_null(
|
||||
metadata_ce, "languages", sizeof("languages") - 1, ZEND_ACC_PUBLIC);
|
||||
zend_declare_property_null(metadata_ce,
|
||||
"nodeByteSize",
|
||||
sizeof("nodeByteSize") - 1,
|
||||
ZEND_ACC_PUBLIC);
|
||||
zend_declare_property_null(
|
||||
metadata_ce, "nodeCount", sizeof("nodeCount") - 1, ZEND_ACC_PUBLIC);
|
||||
zend_declare_property_null(
|
||||
metadata_ce, "recordSize", sizeof("recordSize") - 1, ZEND_ACC_PUBLIC);
|
||||
zend_declare_property_null(metadata_ce,
|
||||
"searchTreeSize",
|
||||
sizeof("searchTreeSize") - 1,
|
||||
ZEND_ACC_PUBLIC);
|
||||
|
||||
memcpy(&maxminddb_obj_handlers,
|
||||
zend_get_std_object_handlers(),
|
||||
sizeof(zend_object_handlers));
|
||||
maxminddb_obj_handlers.clone_obj = NULL;
|
||||
maxminddb_obj_handlers.offset = XtOffsetOf(maxminddb_obj, std);
|
||||
maxminddb_obj_handlers.free_obj = maxminddb_free_storage;
|
||||
zend_declare_class_constant_string(maxminddb_ce,
|
||||
"MMDB_LIB_VERSION",
|
||||
sizeof("MMDB_LIB_VERSION") - 1,
|
||||
MMDB_lib_version() TSRMLS_CC);
|
||||
|
||||
return SUCCESS;
|
||||
}
|
||||
|
||||
static PHP_MINFO_FUNCTION(maxminddb) {
|
||||
php_info_print_table_start();
|
||||
|
||||
php_info_print_table_row(2, "MaxMind DB Reader", "enabled");
|
||||
php_info_print_table_row(
|
||||
2, "maxminddb extension version", PHP_MAXMINDDB_VERSION);
|
||||
php_info_print_table_row(
|
||||
2, "libmaxminddb library version", MMDB_lib_version());
|
||||
|
||||
php_info_print_table_end();
|
||||
}
|
||||
|
||||
zend_module_entry maxminddb_module_entry = {STANDARD_MODULE_HEADER,
|
||||
PHP_MAXMINDDB_EXTNAME,
|
||||
NULL,
|
||||
PHP_MINIT(maxminddb),
|
||||
NULL,
|
||||
NULL,
|
||||
NULL,
|
||||
PHP_MINFO(maxminddb),
|
||||
PHP_MAXMINDDB_VERSION,
|
||||
STANDARD_MODULE_PROPERTIES};
|
||||
|
||||
#ifdef COMPILE_DL_MAXMINDDB
|
||||
ZEND_GET_MODULE(maxminddb)
|
||||
#endif
|
||||
24
plugins/system/tgeoip/vendor/maxmind-db/reader/ext/php_maxminddb.h
vendored
Normal file
24
plugins/system/tgeoip/vendor/maxmind-db/reader/ext/php_maxminddb.h
vendored
Normal file
@ -0,0 +1,24 @@
|
||||
/* MaxMind, Inc., licenses this file to you under the Apache License, Version
|
||||
* 2.0 (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
* License for the specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
|
||||
#include <zend_interfaces.h>
|
||||
|
||||
#ifndef PHP_MAXMINDDB_H
|
||||
#define PHP_MAXMINDDB_H 1
|
||||
#define PHP_MAXMINDDB_VERSION "1.10.1"
|
||||
#define PHP_MAXMINDDB_EXTNAME "maxminddb"
|
||||
|
||||
extern zend_module_entry maxminddb_module_entry;
|
||||
#define phpext_maxminddb_ptr &maxminddb_module_entry
|
||||
|
||||
#endif
|
||||
63
plugins/system/tgeoip/vendor/maxmind-db/reader/package.xml
vendored
Normal file
63
plugins/system/tgeoip/vendor/maxmind-db/reader/package.xml
vendored
Normal file
@ -0,0 +1,63 @@
|
||||
<?xml version="1.0"?>
|
||||
<package version="2.0" xmlns="http://pear.php.net/dtd/package-2.0"
|
||||
xmlns:tasks="http://pear.php.net/dtd/tasks-1.0"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://pear.php.net/dtd/tasks-1.0 http://pear.php.net/dtd/tasks-1.0.xsd http://pear.php.net/dtd/package-2.0 http://pear.php.net/dtd/package-2.0.xsd">
|
||||
|
||||
<name>maxminddb</name>
|
||||
<channel>pecl.php.net</channel>
|
||||
<summary>Reader for the MaxMind DB file format</summary>
|
||||
<description>This is the PHP extension for reading MaxMind DB files. MaxMind DB is a binary file format that stores data indexed by IP address subnets (IPv4 or IPv6).</description>
|
||||
<lead>
|
||||
<name>Greg Oschwald</name>
|
||||
<user>oschwald</user>
|
||||
<email>goschwald@maxmind.com</email>
|
||||
<active>yes</active>
|
||||
</lead>
|
||||
<date>2021-04-14</date>
|
||||
<version>
|
||||
<release>1.10.1</release>
|
||||
<api>1.10.1</api>
|
||||
</version>
|
||||
<stability>
|
||||
<release>stable</release>
|
||||
<api>stable</api>
|
||||
</stability>
|
||||
<license uri="https://github.com/maxmind/MaxMind-DB-Reader-php/blob/main/LICENSE">Apache License 2.0</license>
|
||||
<notes>* Fix a `TypeError` exception in the pure PHP reader when using large
|
||||
databases on 32-bit PHP builds with the `bcmath` extension. Reported
|
||||
by dodo1708. GitHub #124.</notes>
|
||||
<contents>
|
||||
<dir name="/">
|
||||
<file role="doc" name="LICENSE"/>
|
||||
<file role="doc" name="CHANGELOG.md"/>
|
||||
<file role="doc" name="README.md"/>
|
||||
|
||||
<dir name="ext">
|
||||
<file role="src" name="config.m4"/>
|
||||
<file role="src" name="config.w32"/>
|
||||
|
||||
<file role="src" name="maxminddb.c"/>
|
||||
<file role="src" name="php_maxminddb.h"/>
|
||||
|
||||
<dir name="tests">
|
||||
<file role="test" name="001-load.phpt"/>
|
||||
<file role="test" name="002-final.phpt"/>
|
||||
<file role="test" name="003-open-basedir.phpt"/>
|
||||
</dir>
|
||||
</dir>
|
||||
</dir>
|
||||
</contents>
|
||||
<dependencies>
|
||||
<required>
|
||||
<php>
|
||||
<min>7.2.0</min>
|
||||
</php>
|
||||
<pearinstaller>
|
||||
<min>1.10.0</min>
|
||||
</pearinstaller>
|
||||
</required>
|
||||
</dependencies>
|
||||
<providesextension>maxminddb</providesextension>
|
||||
<extsrcrelease />
|
||||
</package>
|
||||
287
plugins/system/tgeoip/vendor/maxmind-db/reader/src/MaxMind/Db/Reader.php
vendored
Normal file
287
plugins/system/tgeoip/vendor/maxmind-db/reader/src/MaxMind/Db/Reader.php
vendored
Normal file
@ -0,0 +1,287 @@
|
||||
<?php
|
||||
|
||||
declare (strict_types=1);
|
||||
namespace Tassos\Vendor\MaxMind\Db;
|
||||
|
||||
use ArgumentCountError;
|
||||
use BadMethodCallException;
|
||||
use Exception;
|
||||
use InvalidArgumentException;
|
||||
use Tassos\Vendor\MaxMind\Db\Reader\Decoder;
|
||||
use Tassos\Vendor\MaxMind\Db\Reader\InvalidDatabaseException;
|
||||
use Tassos\Vendor\MaxMind\Db\Reader\Metadata;
|
||||
use Tassos\Vendor\MaxMind\Db\Reader\Util;
|
||||
use UnexpectedValueException;
|
||||
/**
|
||||
* Instances of this class provide a reader for the MaxMind DB format. IP
|
||||
* addresses can be looked up using the get method.
|
||||
*/
|
||||
class Reader
|
||||
{
|
||||
/**
|
||||
* @var int
|
||||
*/
|
||||
private static $DATA_SECTION_SEPARATOR_SIZE = 16;
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
private static $METADATA_START_MARKER = "\xab\xcd\xefMaxMind.com";
|
||||
/**
|
||||
* @var int
|
||||
*/
|
||||
private static $METADATA_START_MARKER_LENGTH = 14;
|
||||
/**
|
||||
* @var int
|
||||
*/
|
||||
private static $METADATA_MAX_SIZE = 131072;
|
||||
// 128 * 1024 = 128KiB
|
||||
/**
|
||||
* @var Decoder
|
||||
*/
|
||||
private $decoder;
|
||||
/**
|
||||
* @var resource
|
||||
*/
|
||||
private $fileHandle;
|
||||
/**
|
||||
* @var int
|
||||
*/
|
||||
private $fileSize;
|
||||
/**
|
||||
* @var int
|
||||
*/
|
||||
private $ipV4Start;
|
||||
/**
|
||||
* @var Metadata
|
||||
*/
|
||||
private $metadata;
|
||||
/**
|
||||
* Constructs a Reader for the MaxMind DB format. The file passed to it must
|
||||
* be a valid MaxMind DB file such as a GeoIp2 database file.
|
||||
*
|
||||
* @param string $database
|
||||
* the MaxMind DB file to use
|
||||
*
|
||||
* @throws InvalidArgumentException for invalid database path or unknown arguments
|
||||
* @throws InvalidDatabaseException
|
||||
* if the database is invalid or there is an error reading
|
||||
* from it
|
||||
*/
|
||||
public function __construct(string $database)
|
||||
{
|
||||
if (\func_num_args() !== 1) {
|
||||
throw new ArgumentCountError(\sprintf('%s() expects exactly 1 parameter, %d given', __METHOD__, \func_num_args()));
|
||||
}
|
||||
$fileHandle = @\fopen($database, 'rb');
|
||||
if ($fileHandle === \false) {
|
||||
throw new InvalidArgumentException("The file \"{$database}\" does not exist or is not readable.");
|
||||
}
|
||||
$this->fileHandle = $fileHandle;
|
||||
$fileSize = @\filesize($database);
|
||||
if ($fileSize === \false) {
|
||||
throw new UnexpectedValueException("Error determining the size of \"{$database}\".");
|
||||
}
|
||||
$this->fileSize = $fileSize;
|
||||
$start = $this->findMetadataStart($database);
|
||||
$metadataDecoder = new Decoder($this->fileHandle, $start);
|
||||
[$metadataArray] = $metadataDecoder->decode($start);
|
||||
$this->metadata = new Metadata($metadataArray);
|
||||
$this->decoder = new Decoder($this->fileHandle, $this->metadata->searchTreeSize + self::$DATA_SECTION_SEPARATOR_SIZE);
|
||||
$this->ipV4Start = $this->ipV4StartNode();
|
||||
}
|
||||
/**
|
||||
* Retrieves the record for the IP address.
|
||||
*
|
||||
* @param string $ipAddress
|
||||
* the IP address to look up
|
||||
*
|
||||
* @throws BadMethodCallException if this method is called on a closed database
|
||||
* @throws InvalidArgumentException if something other than a single IP address is passed to the method
|
||||
* @throws InvalidDatabaseException
|
||||
* if the database is invalid or there is an error reading
|
||||
* from it
|
||||
*
|
||||
* @return mixed the record for the IP address
|
||||
*/
|
||||
public function get(string $ipAddress)
|
||||
{
|
||||
if (\func_num_args() !== 1) {
|
||||
throw new ArgumentCountError(\sprintf('%s() expects exactly 1 parameter, %d given', __METHOD__, \func_num_args()));
|
||||
}
|
||||
[$record] = $this->getWithPrefixLen($ipAddress);
|
||||
return $record;
|
||||
}
|
||||
/**
|
||||
* Retrieves the record for the IP address and its associated network prefix length.
|
||||
*
|
||||
* @param string $ipAddress
|
||||
* the IP address to look up
|
||||
*
|
||||
* @throws BadMethodCallException if this method is called on a closed database
|
||||
* @throws InvalidArgumentException if something other than a single IP address is passed to the method
|
||||
* @throws InvalidDatabaseException
|
||||
* if the database is invalid or there is an error reading
|
||||
* from it
|
||||
*
|
||||
* @return array an array where the first element is the record and the
|
||||
* second the network prefix length for the record
|
||||
*/
|
||||
public function getWithPrefixLen(string $ipAddress) : array
|
||||
{
|
||||
if (\func_num_args() !== 1) {
|
||||
throw new ArgumentCountError(\sprintf('%s() expects exactly 1 parameter, %d given', __METHOD__, \func_num_args()));
|
||||
}
|
||||
if (!\is_resource($this->fileHandle)) {
|
||||
throw new BadMethodCallException('Attempt to read from a closed MaxMind DB.');
|
||||
}
|
||||
[$pointer, $prefixLen] = $this->findAddressInTree($ipAddress);
|
||||
if ($pointer === 0) {
|
||||
return [null, $prefixLen];
|
||||
}
|
||||
return [$this->resolveDataPointer($pointer), $prefixLen];
|
||||
}
|
||||
private function findAddressInTree(string $ipAddress) : array
|
||||
{
|
||||
$packedAddr = @\inet_pton($ipAddress);
|
||||
if ($packedAddr === \false) {
|
||||
throw new InvalidArgumentException("The value \"{$ipAddress}\" is not a valid IP address.");
|
||||
}
|
||||
$rawAddress = \unpack('C*', $packedAddr);
|
||||
$bitCount = \count($rawAddress) * 8;
|
||||
// The first node of the tree is always node 0, at the beginning of the
|
||||
// value
|
||||
$node = 0;
|
||||
$metadata = $this->metadata;
|
||||
// Check if we are looking up an IPv4 address in an IPv6 tree. If this
|
||||
// is the case, we can skip over the first 96 nodes.
|
||||
if ($metadata->ipVersion === 6) {
|
||||
if ($bitCount === 32) {
|
||||
$node = $this->ipV4Start;
|
||||
}
|
||||
} elseif ($metadata->ipVersion === 4 && $bitCount === 128) {
|
||||
throw new InvalidArgumentException("Error looking up {$ipAddress}. You attempted to look up an" . ' IPv6 address in an IPv4-only database.');
|
||||
}
|
||||
$nodeCount = $metadata->nodeCount;
|
||||
for ($i = 0; $i < $bitCount && $node < $nodeCount; ++$i) {
|
||||
$tempBit = 0xff & $rawAddress[($i >> 3) + 1];
|
||||
$bit = 1 & $tempBit >> 7 - $i % 8;
|
||||
$node = $this->readNode($node, $bit);
|
||||
}
|
||||
if ($node === $nodeCount) {
|
||||
// Record is empty
|
||||
return [0, $i];
|
||||
}
|
||||
if ($node > $nodeCount) {
|
||||
// Record is a data pointer
|
||||
return [$node, $i];
|
||||
}
|
||||
throw new InvalidDatabaseException('Invalid or corrupt database. Maximum search depth reached without finding a leaf node');
|
||||
}
|
||||
private function ipV4StartNode() : int
|
||||
{
|
||||
// If we have an IPv4 database, the start node is the first node
|
||||
if ($this->metadata->ipVersion === 4) {
|
||||
return 0;
|
||||
}
|
||||
$node = 0;
|
||||
for ($i = 0; $i < 96 && $node < $this->metadata->nodeCount; ++$i) {
|
||||
$node = $this->readNode($node, 0);
|
||||
}
|
||||
return $node;
|
||||
}
|
||||
private function readNode(int $nodeNumber, int $index) : int
|
||||
{
|
||||
$baseOffset = $nodeNumber * $this->metadata->nodeByteSize;
|
||||
switch ($this->metadata->recordSize) {
|
||||
case 24:
|
||||
$bytes = Util::read($this->fileHandle, $baseOffset + $index * 3, 3);
|
||||
[, $node] = \unpack('N', "\x00" . $bytes);
|
||||
return $node;
|
||||
case 28:
|
||||
$bytes = Util::read($this->fileHandle, $baseOffset + 3 * $index, 4);
|
||||
if ($index === 0) {
|
||||
$middle = (0xf0 & \ord($bytes[3])) >> 4;
|
||||
} else {
|
||||
$middle = 0xf & \ord($bytes[0]);
|
||||
}
|
||||
[, $node] = \unpack('N', \chr($middle) . \substr($bytes, $index, 3));
|
||||
return $node;
|
||||
case 32:
|
||||
$bytes = Util::read($this->fileHandle, $baseOffset + $index * 4, 4);
|
||||
[, $node] = \unpack('N', $bytes);
|
||||
return $node;
|
||||
default:
|
||||
throw new InvalidDatabaseException('Unknown record size: ' . $this->metadata->recordSize);
|
||||
}
|
||||
}
|
||||
/**
|
||||
* @return mixed
|
||||
*/
|
||||
private function resolveDataPointer(int $pointer)
|
||||
{
|
||||
$resolved = $pointer - $this->metadata->nodeCount + $this->metadata->searchTreeSize;
|
||||
if ($resolved >= $this->fileSize) {
|
||||
throw new InvalidDatabaseException("The MaxMind DB file's search tree is corrupt");
|
||||
}
|
||||
[$data] = $this->decoder->decode($resolved);
|
||||
return $data;
|
||||
}
|
||||
/*
|
||||
* This is an extremely naive but reasonably readable implementation. There
|
||||
* are much faster algorithms (e.g., Boyer-Moore) for this if speed is ever
|
||||
* an issue, but I suspect it won't be.
|
||||
*/
|
||||
private function findMetadataStart(string $filename) : int
|
||||
{
|
||||
$handle = $this->fileHandle;
|
||||
$fstat = \fstat($handle);
|
||||
$fileSize = $fstat['size'];
|
||||
$marker = self::$METADATA_START_MARKER;
|
||||
$markerLength = self::$METADATA_START_MARKER_LENGTH;
|
||||
$minStart = $fileSize - \min(self::$METADATA_MAX_SIZE, $fileSize);
|
||||
for ($offset = $fileSize - $markerLength; $offset >= $minStart; --$offset) {
|
||||
if (\fseek($handle, $offset) !== 0) {
|
||||
break;
|
||||
}
|
||||
$value = \fread($handle, $markerLength);
|
||||
if ($value === $marker) {
|
||||
return $offset + $markerLength;
|
||||
}
|
||||
}
|
||||
throw new InvalidDatabaseException("Error opening database file ({$filename}). " . 'Is this a valid MaxMind DB file?');
|
||||
}
|
||||
/**
|
||||
* @throws InvalidArgumentException if arguments are passed to the method
|
||||
* @throws BadMethodCallException if the database has been closed
|
||||
*
|
||||
* @return Metadata object for the database
|
||||
*/
|
||||
public function metadata() : Metadata
|
||||
{
|
||||
if (\func_num_args()) {
|
||||
throw new ArgumentCountError(\sprintf('%s() expects exactly 0 parameters, %d given', __METHOD__, \func_num_args()));
|
||||
}
|
||||
// Not technically required, but this makes it consistent with
|
||||
// C extension and it allows us to change our implementation later.
|
||||
if (!\is_resource($this->fileHandle)) {
|
||||
throw new BadMethodCallException('Attempt to read from a closed MaxMind DB.');
|
||||
}
|
||||
return clone $this->metadata;
|
||||
}
|
||||
/**
|
||||
* Closes the MaxMind DB and returns resources to the system.
|
||||
*
|
||||
* @throws Exception
|
||||
* if an I/O error occurs
|
||||
*/
|
||||
public function close() : void
|
||||
{
|
||||
if (\func_num_args()) {
|
||||
throw new ArgumentCountError(\sprintf('%s() expects exactly 0 parameters, %d given', __METHOD__, \func_num_args()));
|
||||
}
|
||||
if (!\is_resource($this->fileHandle)) {
|
||||
throw new BadMethodCallException('Attempt to close a closed MaxMind DB.');
|
||||
}
|
||||
\fclose($this->fileHandle);
|
||||
}
|
||||
}
|
||||
275
plugins/system/tgeoip/vendor/maxmind-db/reader/src/MaxMind/Db/Reader/Decoder.php
vendored
Normal file
275
plugins/system/tgeoip/vendor/maxmind-db/reader/src/MaxMind/Db/Reader/Decoder.php
vendored
Normal file
@ -0,0 +1,275 @@
|
||||
<?php
|
||||
|
||||
declare (strict_types=1);
|
||||
namespace Tassos\Vendor\MaxMind\Db\Reader;
|
||||
|
||||
// @codingStandardsIgnoreLine
|
||||
use RuntimeException;
|
||||
class Decoder
|
||||
{
|
||||
/**
|
||||
* @var resource
|
||||
*/
|
||||
private $fileStream;
|
||||
/**
|
||||
* @var int
|
||||
*/
|
||||
private $pointerBase;
|
||||
/**
|
||||
* @var float
|
||||
*/
|
||||
private $pointerBaseByteSize;
|
||||
/**
|
||||
* This is only used for unit testing.
|
||||
*
|
||||
* @var bool
|
||||
*/
|
||||
private $pointerTestHack;
|
||||
/**
|
||||
* @var bool
|
||||
*/
|
||||
private $switchByteOrder;
|
||||
private const _EXTENDED = 0;
|
||||
private const _POINTER = 1;
|
||||
private const _UTF8_STRING = 2;
|
||||
private const _DOUBLE = 3;
|
||||
private const _BYTES = 4;
|
||||
private const _UINT16 = 5;
|
||||
private const _UINT32 = 6;
|
||||
private const _MAP = 7;
|
||||
private const _INT32 = 8;
|
||||
private const _UINT64 = 9;
|
||||
private const _UINT128 = 10;
|
||||
private const _ARRAY = 11;
|
||||
private const _CONTAINER = 12;
|
||||
private const _END_MARKER = 13;
|
||||
private const _BOOLEAN = 14;
|
||||
private const _FLOAT = 15;
|
||||
/**
|
||||
* @param resource $fileStream
|
||||
*/
|
||||
public function __construct($fileStream, int $pointerBase = 0, bool $pointerTestHack = \false)
|
||||
{
|
||||
$this->fileStream = $fileStream;
|
||||
$this->pointerBase = $pointerBase;
|
||||
$this->pointerBaseByteSize = $pointerBase > 0 ? \log($pointerBase, 2) / 8 : 0;
|
||||
$this->pointerTestHack = $pointerTestHack;
|
||||
$this->switchByteOrder = $this->isPlatformLittleEndian();
|
||||
}
|
||||
public function decode(int $offset) : array
|
||||
{
|
||||
$ctrlByte = \ord(Util::read($this->fileStream, $offset, 1));
|
||||
++$offset;
|
||||
$type = $ctrlByte >> 5;
|
||||
// Pointers are a special case, we don't read the next $size bytes, we
|
||||
// use the size to determine the length of the pointer and then follow
|
||||
// it.
|
||||
if ($type === self::_POINTER) {
|
||||
[$pointer, $offset] = $this->decodePointer($ctrlByte, $offset);
|
||||
// for unit testing
|
||||
if ($this->pointerTestHack) {
|
||||
return [$pointer];
|
||||
}
|
||||
[$result] = $this->decode($pointer);
|
||||
return [$result, $offset];
|
||||
}
|
||||
if ($type === self::_EXTENDED) {
|
||||
$nextByte = \ord(Util::read($this->fileStream, $offset, 1));
|
||||
$type = $nextByte + 7;
|
||||
if ($type < 8) {
|
||||
throw new InvalidDatabaseException('Something went horribly wrong in the decoder. An extended type ' . 'resolved to a type number < 8 (' . $type . ')');
|
||||
}
|
||||
++$offset;
|
||||
}
|
||||
[$size, $offset] = $this->sizeFromCtrlByte($ctrlByte, $offset);
|
||||
return $this->decodeByType($type, $offset, $size);
|
||||
}
|
||||
private function decodeByType(int $type, int $offset, int $size) : array
|
||||
{
|
||||
switch ($type) {
|
||||
case self::_MAP:
|
||||
return $this->decodeMap($size, $offset);
|
||||
case self::_ARRAY:
|
||||
return $this->decodeArray($size, $offset);
|
||||
case self::_BOOLEAN:
|
||||
return [$this->decodeBoolean($size), $offset];
|
||||
}
|
||||
$newOffset = $offset + $size;
|
||||
$bytes = Util::read($this->fileStream, $offset, $size);
|
||||
switch ($type) {
|
||||
case self::_BYTES:
|
||||
case self::_UTF8_STRING:
|
||||
return [$bytes, $newOffset];
|
||||
case self::_DOUBLE:
|
||||
$this->verifySize(8, $size);
|
||||
return [$this->decodeDouble($bytes), $newOffset];
|
||||
case self::_FLOAT:
|
||||
$this->verifySize(4, $size);
|
||||
return [$this->decodeFloat($bytes), $newOffset];
|
||||
case self::_INT32:
|
||||
return [$this->decodeInt32($bytes, $size), $newOffset];
|
||||
case self::_UINT16:
|
||||
case self::_UINT32:
|
||||
case self::_UINT64:
|
||||
case self::_UINT128:
|
||||
return [$this->decodeUint($bytes, $size), $newOffset];
|
||||
default:
|
||||
throw new InvalidDatabaseException('Unknown or unexpected type: ' . $type);
|
||||
}
|
||||
}
|
||||
private function verifySize(int $expected, int $actual) : void
|
||||
{
|
||||
if ($expected !== $actual) {
|
||||
throw new InvalidDatabaseException("The MaxMind DB file's data section contains bad data (unknown data type or corrupt data)");
|
||||
}
|
||||
}
|
||||
private function decodeArray(int $size, int $offset) : array
|
||||
{
|
||||
$array = [];
|
||||
for ($i = 0; $i < $size; ++$i) {
|
||||
[$value, $offset] = $this->decode($offset);
|
||||
$array[] = $value;
|
||||
}
|
||||
return [$array, $offset];
|
||||
}
|
||||
private function decodeBoolean(int $size) : bool
|
||||
{
|
||||
return $size !== 0;
|
||||
}
|
||||
private function decodeDouble(string $bytes) : float
|
||||
{
|
||||
// This assumes IEEE 754 doubles, but most (all?) modern platforms
|
||||
// use them.
|
||||
[, $double] = \unpack('E', $bytes);
|
||||
return $double;
|
||||
}
|
||||
private function decodeFloat(string $bytes) : float
|
||||
{
|
||||
// This assumes IEEE 754 floats, but most (all?) modern platforms
|
||||
// use them.
|
||||
[, $float] = \unpack('G', $bytes);
|
||||
return $float;
|
||||
}
|
||||
private function decodeInt32(string $bytes, int $size) : int
|
||||
{
|
||||
switch ($size) {
|
||||
case 0:
|
||||
return 0;
|
||||
case 1:
|
||||
case 2:
|
||||
case 3:
|
||||
$bytes = \str_pad($bytes, 4, "\x00", \STR_PAD_LEFT);
|
||||
break;
|
||||
case 4:
|
||||
break;
|
||||
default:
|
||||
throw new InvalidDatabaseException("The MaxMind DB file's data section contains bad data (unknown data type or corrupt data)");
|
||||
}
|
||||
[, $int] = \unpack('l', $this->maybeSwitchByteOrder($bytes));
|
||||
return $int;
|
||||
}
|
||||
private function decodeMap(int $size, int $offset) : array
|
||||
{
|
||||
$map = [];
|
||||
for ($i = 0; $i < $size; ++$i) {
|
||||
[$key, $offset] = $this->decode($offset);
|
||||
[$value, $offset] = $this->decode($offset);
|
||||
$map[$key] = $value;
|
||||
}
|
||||
return [$map, $offset];
|
||||
}
|
||||
private function decodePointer(int $ctrlByte, int $offset) : array
|
||||
{
|
||||
$pointerSize = ($ctrlByte >> 3 & 0x3) + 1;
|
||||
$buffer = Util::read($this->fileStream, $offset, $pointerSize);
|
||||
$offset = $offset + $pointerSize;
|
||||
switch ($pointerSize) {
|
||||
case 1:
|
||||
$packed = \chr($ctrlByte & 0x7) . $buffer;
|
||||
[, $pointer] = \unpack('n', $packed);
|
||||
$pointer += $this->pointerBase;
|
||||
break;
|
||||
case 2:
|
||||
$packed = "\x00" . \chr($ctrlByte & 0x7) . $buffer;
|
||||
[, $pointer] = \unpack('N', $packed);
|
||||
$pointer += $this->pointerBase + 2048;
|
||||
break;
|
||||
case 3:
|
||||
$packed = \chr($ctrlByte & 0x7) . $buffer;
|
||||
// It is safe to use 'N' here, even on 32 bit machines as the
|
||||
// first bit is 0.
|
||||
[, $pointer] = \unpack('N', $packed);
|
||||
$pointer += $this->pointerBase + 526336;
|
||||
break;
|
||||
case 4:
|
||||
// We cannot use unpack here as we might overflow on 32 bit
|
||||
// machines
|
||||
$pointerOffset = $this->decodeUint($buffer, $pointerSize);
|
||||
$pointerBase = $this->pointerBase;
|
||||
if (\PHP_INT_MAX - $pointerBase >= $pointerOffset) {
|
||||
$pointer = $pointerOffset + $pointerBase;
|
||||
} else {
|
||||
throw new RuntimeException('The database offset is too large to be represented on your platform.');
|
||||
}
|
||||
break;
|
||||
default:
|
||||
throw new InvalidDatabaseException('Unexpected pointer size ' . $pointerSize);
|
||||
}
|
||||
return [$pointer, $offset];
|
||||
}
|
||||
// @phpstan-ignore-next-line
|
||||
private function decodeUint(string $bytes, int $byteLength)
|
||||
{
|
||||
if ($byteLength === 0) {
|
||||
return 0;
|
||||
}
|
||||
$integer = 0;
|
||||
// PHP integers are signed. PHP_INT_SIZE - 1 is the number of
|
||||
// complete bytes that can be converted to an integer. However,
|
||||
// we can convert another byte if the leading bit is zero.
|
||||
$useRealInts = $byteLength <= \PHP_INT_SIZE - 1 || $byteLength === \PHP_INT_SIZE && (\ord($bytes[0]) & 0x80) === 0;
|
||||
for ($i = 0; $i < $byteLength; ++$i) {
|
||||
$part = \ord($bytes[$i]);
|
||||
// We only use gmp or bcmath if the final value is too big
|
||||
if ($useRealInts) {
|
||||
$integer = ($integer << 8) + $part;
|
||||
} elseif (\extension_loaded('gmp')) {
|
||||
$integer = \gmp_strval(\gmp_add(\gmp_mul((string) $integer, '256'), $part));
|
||||
} elseif (\extension_loaded('bcmath')) {
|
||||
$integer = \bcadd(\bcmul((string) $integer, '256'), (string) $part);
|
||||
} else {
|
||||
throw new RuntimeException('The gmp or bcmath extension must be installed to read this database.');
|
||||
}
|
||||
}
|
||||
return $integer;
|
||||
}
|
||||
private function sizeFromCtrlByte(int $ctrlByte, int $offset) : array
|
||||
{
|
||||
$size = $ctrlByte & 0x1f;
|
||||
if ($size < 29) {
|
||||
return [$size, $offset];
|
||||
}
|
||||
$bytesToRead = $size - 28;
|
||||
$bytes = Util::read($this->fileStream, $offset, $bytesToRead);
|
||||
if ($size === 29) {
|
||||
$size = 29 + \ord($bytes);
|
||||
} elseif ($size === 30) {
|
||||
[, $adjust] = \unpack('n', $bytes);
|
||||
$size = 285 + $adjust;
|
||||
} else {
|
||||
[, $adjust] = \unpack('N', "\x00" . $bytes);
|
||||
$size = $adjust + 65821;
|
||||
}
|
||||
return [$size, $offset + $bytesToRead];
|
||||
}
|
||||
private function maybeSwitchByteOrder(string $bytes) : string
|
||||
{
|
||||
return $this->switchByteOrder ? \strrev($bytes) : $bytes;
|
||||
}
|
||||
private function isPlatformLittleEndian() : bool
|
||||
{
|
||||
$testint = 0xff;
|
||||
$packed = \pack('S', $testint);
|
||||
return $testint === \current(\unpack('v', $packed));
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,12 @@
|
||||
<?php
|
||||
|
||||
declare (strict_types=1);
|
||||
namespace Tassos\Vendor\MaxMind\Db\Reader;
|
||||
|
||||
use Exception;
|
||||
/**
|
||||
* This class should be thrown when unexpected data is found in the database.
|
||||
*/
|
||||
class InvalidDatabaseException extends Exception
|
||||
{
|
||||
}
|
||||
104
plugins/system/tgeoip/vendor/maxmind-db/reader/src/MaxMind/Db/Reader/Metadata.php
vendored
Normal file
104
plugins/system/tgeoip/vendor/maxmind-db/reader/src/MaxMind/Db/Reader/Metadata.php
vendored
Normal file
@ -0,0 +1,104 @@
|
||||
<?php
|
||||
|
||||
declare (strict_types=1);
|
||||
namespace Tassos\Vendor\MaxMind\Db\Reader;
|
||||
|
||||
use ArgumentCountError;
|
||||
/**
|
||||
* This class provides the metadata for the MaxMind DB file.
|
||||
*/
|
||||
class Metadata
|
||||
{
|
||||
/**
|
||||
* This is an unsigned 16-bit integer indicating the major version number
|
||||
* for the database's binary format.
|
||||
*
|
||||
* @var int
|
||||
*/
|
||||
public $binaryFormatMajorVersion;
|
||||
/**
|
||||
* This is an unsigned 16-bit integer indicating the minor version number
|
||||
* for the database's binary format.
|
||||
*
|
||||
* @var int
|
||||
*/
|
||||
public $binaryFormatMinorVersion;
|
||||
/**
|
||||
* This is an unsigned 64-bit integer that contains the database build
|
||||
* timestamp as a Unix epoch value.
|
||||
*
|
||||
* @var int
|
||||
*/
|
||||
public $buildEpoch;
|
||||
/**
|
||||
* This is a string that indicates the structure of each data record
|
||||
* associated with an IP address. The actual definition of these
|
||||
* structures is left up to the database creator.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
public $databaseType;
|
||||
/**
|
||||
* This key will always point to a map (associative array). The keys of
|
||||
* that map will be language codes, and the values will be a description
|
||||
* in that language as a UTF-8 string. May be undefined for some
|
||||
* databases.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
public $description;
|
||||
/**
|
||||
* This is an unsigned 16-bit integer which is always 4 or 6. It indicates
|
||||
* whether the database contains IPv4 or IPv6 address data.
|
||||
*
|
||||
* @var int
|
||||
*/
|
||||
public $ipVersion;
|
||||
/**
|
||||
* An array of strings, each of which is a language code. A given record
|
||||
* may contain data items that have been localized to some or all of
|
||||
* these languages. This may be undefined.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
public $languages;
|
||||
/**
|
||||
* @var int
|
||||
*/
|
||||
public $nodeByteSize;
|
||||
/**
|
||||
* This is an unsigned 32-bit integer indicating the number of nodes in
|
||||
* the search tree.
|
||||
*
|
||||
* @var int
|
||||
*/
|
||||
public $nodeCount;
|
||||
/**
|
||||
* This is an unsigned 16-bit integer. It indicates the number of bits in a
|
||||
* record in the search tree. Note that each node consists of two records.
|
||||
*
|
||||
* @var int
|
||||
*/
|
||||
public $recordSize;
|
||||
/**
|
||||
* @var int
|
||||
*/
|
||||
public $searchTreeSize;
|
||||
public function __construct(array $metadata)
|
||||
{
|
||||
if (\func_num_args() !== 1) {
|
||||
throw new ArgumentCountError(\sprintf('%s() expects exactly 1 parameter, %d given', __METHOD__, \func_num_args()));
|
||||
}
|
||||
$this->binaryFormatMajorVersion = $metadata['binary_format_major_version'];
|
||||
$this->binaryFormatMinorVersion = $metadata['binary_format_minor_version'];
|
||||
$this->buildEpoch = $metadata['build_epoch'];
|
||||
$this->databaseType = $metadata['database_type'];
|
||||
$this->languages = $metadata['languages'];
|
||||
$this->description = $metadata['description'];
|
||||
$this->ipVersion = $metadata['ip_version'];
|
||||
$this->nodeCount = $metadata['node_count'];
|
||||
$this->recordSize = $metadata['record_size'];
|
||||
$this->nodeByteSize = $this->recordSize / 4;
|
||||
$this->searchTreeSize = $this->nodeCount * $this->nodeByteSize;
|
||||
}
|
||||
}
|
||||
27
plugins/system/tgeoip/vendor/maxmind-db/reader/src/MaxMind/Db/Reader/Util.php
vendored
Normal file
27
plugins/system/tgeoip/vendor/maxmind-db/reader/src/MaxMind/Db/Reader/Util.php
vendored
Normal file
@ -0,0 +1,27 @@
|
||||
<?php
|
||||
|
||||
declare (strict_types=1);
|
||||
namespace Tassos\Vendor\MaxMind\Db\Reader;
|
||||
|
||||
class Util
|
||||
{
|
||||
/**
|
||||
* @param resource $stream
|
||||
*/
|
||||
public static function read($stream, int $offset, int $numberOfBytes) : string
|
||||
{
|
||||
if ($numberOfBytes === 0) {
|
||||
return '';
|
||||
}
|
||||
if (\fseek($stream, $offset) === 0) {
|
||||
$value = \fread($stream, $numberOfBytes);
|
||||
// We check that the number of bytes read is equal to the number
|
||||
// asked for. We use ftell as getting the length of $value is
|
||||
// much slower.
|
||||
if ($value !== \false && \ftell($stream) - $offset === $numberOfBytes) {
|
||||
return $value;
|
||||
}
|
||||
}
|
||||
throw new InvalidDatabaseException('The MaxMind DB file contains bad data');
|
||||
}
|
||||
}
|
||||
56
plugins/system/tgeoip/vendor/maxmind/web-service-common/dev-bin/release.sh
vendored
Normal file
56
plugins/system/tgeoip/vendor/maxmind/web-service-common/dev-bin/release.sh
vendored
Normal file
@ -0,0 +1,56 @@
|
||||
#!/bin/bash
|
||||
|
||||
set -eu -o pipefail
|
||||
|
||||
|
||||
changelog=$(cat CHANGELOG.md)
|
||||
|
||||
regex='
|
||||
([0-9]+\.[0-9]+\.[0-9]+) \(([0-9]{4}-[0-9]{2}-[0-9]{2})\)
|
||||
-*
|
||||
|
||||
((.|
|
||||
)*)
|
||||
'
|
||||
|
||||
if [[ ! $changelog =~ $regex ]]; then
|
||||
echo "Could not find date line in change log!"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
version="${BASH_REMATCH[1]}"
|
||||
date="${BASH_REMATCH[2]}"
|
||||
notes="$(echo "${BASH_REMATCH[3]}" | sed -n -E '/^[0-9]+\.[0-9]+\.[0-9]+/,$!p')"
|
||||
|
||||
if [[ "$date" != $(date +"%Y-%m-%d") ]]; then
|
||||
echo "$date is not today!"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
tag="v$version"
|
||||
|
||||
if [ -n "$(git status --porcelain)" ]; then
|
||||
echo ". is not clean." >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
php composer.phar self-update
|
||||
php composer.phar update
|
||||
|
||||
./vendor/bin/phpunit
|
||||
|
||||
echo "Release notes for $tag:"
|
||||
echo "$notes"
|
||||
|
||||
read -e -p "Commit changes and push to origin? " should_push
|
||||
|
||||
if [ "$should_push" != "y" ]; then
|
||||
echo "Aborting"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
git push
|
||||
|
||||
gh release create --target "$(git branch --show-current)" -t "$version" -n "$notes" "$tag"
|
||||
|
||||
git push --tags
|
||||
7
plugins/system/tgeoip/vendor/maxmind/web-service-common/phpstan.neon
vendored
Normal file
7
plugins/system/tgeoip/vendor/maxmind/web-service-common/phpstan.neon
vendored
Normal file
@ -0,0 +1,7 @@
|
||||
parameters:
|
||||
level: 6
|
||||
paths:
|
||||
- src
|
||||
- tests
|
||||
checkMissingIterableValueType: false
|
||||
|
||||
@ -0,0 +1,11 @@
|
||||
<?php
|
||||
|
||||
declare (strict_types=1);
|
||||
namespace Tassos\Vendor\MaxMind\Exception;
|
||||
|
||||
/**
|
||||
* This class represents an error authenticating.
|
||||
*/
|
||||
class AuthenticationException extends InvalidRequestException
|
||||
{
|
||||
}
|
||||
36
plugins/system/tgeoip/vendor/maxmind/web-service-common/src/Exception/HttpException.php
vendored
Normal file
36
plugins/system/tgeoip/vendor/maxmind/web-service-common/src/Exception/HttpException.php
vendored
Normal file
@ -0,0 +1,36 @@
|
||||
<?php
|
||||
|
||||
declare (strict_types=1);
|
||||
namespace Tassos\Vendor\MaxMind\Exception;
|
||||
|
||||
/**
|
||||
* This class represents an HTTP transport error.
|
||||
*/
|
||||
class HttpException extends WebServiceException
|
||||
{
|
||||
/**
|
||||
* The URI queried.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
private $uri;
|
||||
/**
|
||||
* @param string $message a message describing the error
|
||||
* @param int $httpStatus the HTTP status code of the response
|
||||
* @param string $uri the URI used in the request
|
||||
* @param \Exception $previous the previous exception, if any
|
||||
*/
|
||||
public function __construct(string $message, int $httpStatus, string $uri, \Exception $previous = null)
|
||||
{
|
||||
$this->uri = $uri;
|
||||
parent::__construct($message, $httpStatus, $previous);
|
||||
}
|
||||
public function getUri() : string
|
||||
{
|
||||
return $this->uri;
|
||||
}
|
||||
public function getStatusCode() : int
|
||||
{
|
||||
return $this->getCode();
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,11 @@
|
||||
<?php
|
||||
|
||||
declare (strict_types=1);
|
||||
namespace Tassos\Vendor\MaxMind\Exception;
|
||||
|
||||
/**
|
||||
* Thrown when the account is out of credits.
|
||||
*/
|
||||
class InsufficientFundsException extends InvalidRequestException
|
||||
{
|
||||
}
|
||||
13
plugins/system/tgeoip/vendor/maxmind/web-service-common/src/Exception/InvalidInputException.php
vendored
Normal file
13
plugins/system/tgeoip/vendor/maxmind/web-service-common/src/Exception/InvalidInputException.php
vendored
Normal file
@ -0,0 +1,13 @@
|
||||
<?php
|
||||
|
||||
declare (strict_types=1);
|
||||
namespace Tassos\Vendor\MaxMind\Exception;
|
||||
|
||||
/**
|
||||
* This class represents an error in creating the request to be sent to the
|
||||
* web service. For example, if the array cannot be encoded as JSON or if there
|
||||
* is a missing or invalid field.
|
||||
*/
|
||||
class InvalidInputException extends WebServiceException
|
||||
{
|
||||
}
|
||||
@ -0,0 +1,33 @@
|
||||
<?php
|
||||
|
||||
declare (strict_types=1);
|
||||
namespace Tassos\Vendor\MaxMind\Exception;
|
||||
|
||||
/**
|
||||
* Thrown when a MaxMind web service returns an error relating to the request.
|
||||
*/
|
||||
class InvalidRequestException extends HttpException
|
||||
{
|
||||
/**
|
||||
* The code returned by the MaxMind web service.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
private $error;
|
||||
/**
|
||||
* @param string $message the exception message
|
||||
* @param string $error the error code returned by the MaxMind web service
|
||||
* @param int $httpStatus the HTTP status code of the response
|
||||
* @param string $uri the URI queries
|
||||
* @param \Exception $previous the previous exception, if any
|
||||
*/
|
||||
public function __construct(string $message, string $error, int $httpStatus, string $uri, \Exception $previous = null)
|
||||
{
|
||||
$this->error = $error;
|
||||
parent::__construct($message, $httpStatus, $uri, $previous);
|
||||
}
|
||||
public function getErrorCode() : string
|
||||
{
|
||||
return $this->error;
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,8 @@
|
||||
<?php
|
||||
|
||||
declare (strict_types=1);
|
||||
namespace Tassos\Vendor\MaxMind\Exception;
|
||||
|
||||
class IpAddressNotFoundException extends InvalidRequestException
|
||||
{
|
||||
}
|
||||
@ -0,0 +1,11 @@
|
||||
<?php
|
||||
|
||||
declare (strict_types=1);
|
||||
namespace Tassos\Vendor\MaxMind\Exception;
|
||||
|
||||
/**
|
||||
* This exception is thrown when the service requires permission to access.
|
||||
*/
|
||||
class PermissionRequiredException extends InvalidRequestException
|
||||
{
|
||||
}
|
||||
11
plugins/system/tgeoip/vendor/maxmind/web-service-common/src/Exception/WebServiceException.php
vendored
Normal file
11
plugins/system/tgeoip/vendor/maxmind/web-service-common/src/Exception/WebServiceException.php
vendored
Normal file
@ -0,0 +1,11 @@
|
||||
<?php
|
||||
|
||||
declare (strict_types=1);
|
||||
namespace Tassos\Vendor\MaxMind\Exception;
|
||||
|
||||
/**
|
||||
* This class represents a generic web service error.
|
||||
*/
|
||||
class WebServiceException extends \Exception
|
||||
{
|
||||
}
|
||||
354
plugins/system/tgeoip/vendor/maxmind/web-service-common/src/WebService/Client.php
vendored
Normal file
354
plugins/system/tgeoip/vendor/maxmind/web-service-common/src/WebService/Client.php
vendored
Normal file
@ -0,0 +1,354 @@
|
||||
<?php
|
||||
|
||||
declare (strict_types=1);
|
||||
namespace Tassos\Vendor\MaxMind\WebService;
|
||||
|
||||
use Tassos\Vendor\Composer\CaBundle\CaBundle;
|
||||
use Tassos\Vendor\MaxMind\Exception\AuthenticationException;
|
||||
use Tassos\Vendor\MaxMind\Exception\HttpException;
|
||||
use Tassos\Vendor\MaxMind\Exception\InsufficientFundsException;
|
||||
use Tassos\Vendor\MaxMind\Exception\InvalidInputException;
|
||||
use Tassos\Vendor\MaxMind\Exception\InvalidRequestException;
|
||||
use Tassos\Vendor\MaxMind\Exception\IpAddressNotFoundException;
|
||||
use Tassos\Vendor\MaxMind\Exception\PermissionRequiredException;
|
||||
use Tassos\Vendor\MaxMind\Exception\WebServiceException;
|
||||
use Tassos\Vendor\MaxMind\WebService\Http\RequestFactory;
|
||||
/**
|
||||
* This class is not intended to be used directly by an end-user of a
|
||||
* MaxMind web service. Please use the appropriate client API for the service
|
||||
* that you are using.
|
||||
*
|
||||
* @internal
|
||||
*/
|
||||
class Client
|
||||
{
|
||||
public const VERSION = '0.2.0';
|
||||
/**
|
||||
* @var string|null
|
||||
*/
|
||||
private $caBundle;
|
||||
/**
|
||||
* @var float|null
|
||||
*/
|
||||
private $connectTimeout;
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
private $host = 'api.maxmind.com';
|
||||
/**
|
||||
* @var bool
|
||||
*/
|
||||
private $useHttps = \true;
|
||||
/**
|
||||
* @var RequestFactory
|
||||
*/
|
||||
private $httpRequestFactory;
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
private $licenseKey;
|
||||
/**
|
||||
* @var string|null
|
||||
*/
|
||||
private $proxy;
|
||||
/**
|
||||
* @var float|null
|
||||
*/
|
||||
private $timeout;
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
private $userAgentPrefix;
|
||||
/**
|
||||
* @var int
|
||||
*/
|
||||
private $accountId;
|
||||
/**
|
||||
* @param int $accountId your MaxMind account ID
|
||||
* @param string $licenseKey your MaxMind license key
|
||||
* @param array $options an array of options. Possible keys:
|
||||
* * `host` - The host to use when connecting to the web service.
|
||||
* * `useHttps` - A boolean flag for sending the request via https.(True by default)
|
||||
* * `userAgent` - The prefix of the User-Agent to use in the request.
|
||||
* * `caBundle` - The bundle of CA root certificates to use in the request.
|
||||
* * `connectTimeout` - The connect timeout to use for the request.
|
||||
* * `timeout` - The timeout to use for the request.
|
||||
* * `proxy` - The HTTP proxy to use. May include a schema, port,
|
||||
* username, and password, e.g., `http://username:password@127.0.0.1:10`.
|
||||
*/
|
||||
public function __construct(int $accountId, string $licenseKey, array $options = [])
|
||||
{
|
||||
$this->accountId = $accountId;
|
||||
$this->licenseKey = $licenseKey;
|
||||
$this->httpRequestFactory = isset($options['httpRequestFactory']) ? $options['httpRequestFactory'] : new RequestFactory();
|
||||
if (isset($options['host'])) {
|
||||
$this->host = $options['host'];
|
||||
}
|
||||
if (isset($options['useHttps'])) {
|
||||
$this->useHttps = $options['useHttps'];
|
||||
}
|
||||
if (isset($options['userAgent'])) {
|
||||
$this->userAgentPrefix = $options['userAgent'] . ' ';
|
||||
}
|
||||
$this->caBundle = isset($options['caBundle']) ? $this->caBundle = $options['caBundle'] : $this->getCaBundle();
|
||||
if (isset($options['connectTimeout'])) {
|
||||
$this->connectTimeout = $options['connectTimeout'];
|
||||
}
|
||||
if (isset($options['timeout'])) {
|
||||
$this->timeout = $options['timeout'];
|
||||
}
|
||||
if (isset($options['proxy'])) {
|
||||
$this->proxy = $options['proxy'];
|
||||
}
|
||||
}
|
||||
/**
|
||||
* @param string $service name of the service querying
|
||||
* @param string $path the URI path to use
|
||||
* @param array $input the data to be posted as JSON
|
||||
*
|
||||
* @throws InvalidInputException when the request has missing or invalid
|
||||
* data
|
||||
* @throws AuthenticationException when there is an issue authenticating the
|
||||
* request
|
||||
* @throws InsufficientFundsException when your account is out of funds
|
||||
* @throws InvalidRequestException when the request is invalid for some
|
||||
* other reason, e.g., invalid JSON in the POST.
|
||||
* @throws HttpException when an unexpected HTTP error occurs
|
||||
* @throws WebServiceException when some other error occurs. This also
|
||||
* serves as the base class for the above exceptions.
|
||||
*
|
||||
* @return array|null The decoded content of a successful response
|
||||
*/
|
||||
public function post(string $service, string $path, array $input) : ?array
|
||||
{
|
||||
$requestBody = \json_encode($input);
|
||||
if ($requestBody === \false) {
|
||||
throw new InvalidInputException('Error encoding input as JSON: ' . $this->jsonErrorDescription());
|
||||
}
|
||||
$request = $this->createRequest($path, ['Content-Type: application/json']);
|
||||
[$statusCode, $contentType, $responseBody] = $request->post($requestBody);
|
||||
return $this->handleResponse($statusCode, $contentType, $responseBody, $service, $path);
|
||||
}
|
||||
public function get(string $service, string $path) : ?array
|
||||
{
|
||||
$request = $this->createRequest($path);
|
||||
[$statusCode, $contentType, $responseBody] = $request->get();
|
||||
return $this->handleResponse($statusCode, $contentType, $responseBody, $service, $path);
|
||||
}
|
||||
private function userAgent() : string
|
||||
{
|
||||
$curlVersion = \curl_version();
|
||||
return $this->userAgentPrefix . 'MaxMind-WS-API/' . self::VERSION . ' PHP/' . \PHP_VERSION . ' curl/' . $curlVersion['version'];
|
||||
}
|
||||
private function createRequest(string $path, array $headers = []) : Http\Request
|
||||
{
|
||||
\array_push($headers, 'Authorization: Basic ' . \base64_encode($this->accountId . ':' . $this->licenseKey), 'Accept: application/json');
|
||||
return $this->httpRequestFactory->request($this->urlFor($path), ['caBundle' => $this->caBundle, 'connectTimeout' => $this->connectTimeout, 'headers' => $headers, 'proxy' => $this->proxy, 'timeout' => $this->timeout, 'userAgent' => $this->userAgent()]);
|
||||
}
|
||||
/**
|
||||
* @param int $statusCode the HTTP status code of the response
|
||||
* @param string|null $contentType the Content-Type of the response
|
||||
* @param string|null $responseBody the response body
|
||||
* @param string $service the name of the service
|
||||
* @param string $path the path used in the request
|
||||
*
|
||||
* @throws AuthenticationException when there is an issue authenticating the
|
||||
* request
|
||||
* @throws InsufficientFundsException when your account is out of funds
|
||||
* @throws InvalidRequestException when the request is invalid for some
|
||||
* other reason, e.g., invalid JSON in the POST.
|
||||
* @throws HttpException when an unexpected HTTP error occurs
|
||||
* @throws WebServiceException when some other error occurs. This also
|
||||
* serves as the base class for the above exceptions
|
||||
*
|
||||
* @return array|null The decoded content of a successful response
|
||||
*/
|
||||
private function handleResponse(int $statusCode, ?string $contentType, ?string $responseBody, string $service, string $path) : ?array
|
||||
{
|
||||
if ($statusCode >= 400 && $statusCode <= 499) {
|
||||
$this->handle4xx($statusCode, $contentType, $responseBody, $service, $path);
|
||||
} elseif ($statusCode >= 500) {
|
||||
$this->handle5xx($statusCode, $service, $path);
|
||||
} elseif ($statusCode !== 200 && $statusCode !== 204) {
|
||||
$this->handleUnexpectedStatus($statusCode, $service, $path);
|
||||
}
|
||||
return $this->handleSuccess($statusCode, $responseBody, $service);
|
||||
}
|
||||
/**
|
||||
* @return string describing the JSON error
|
||||
*/
|
||||
private function jsonErrorDescription() : string
|
||||
{
|
||||
$errno = \json_last_error();
|
||||
switch ($errno) {
|
||||
case \JSON_ERROR_DEPTH:
|
||||
return 'The maximum stack depth has been exceeded.';
|
||||
case \JSON_ERROR_STATE_MISMATCH:
|
||||
return 'Invalid or malformed JSON.';
|
||||
case \JSON_ERROR_CTRL_CHAR:
|
||||
return 'Control character error.';
|
||||
case \JSON_ERROR_SYNTAX:
|
||||
return 'Syntax error.';
|
||||
case \JSON_ERROR_UTF8:
|
||||
return 'Malformed UTF-8 characters.';
|
||||
default:
|
||||
return "Other JSON error ({$errno}).";
|
||||
}
|
||||
}
|
||||
/**
|
||||
* @param string $path the path to use in the URL
|
||||
*
|
||||
* @return string the constructed URL
|
||||
*/
|
||||
private function urlFor(string $path) : string
|
||||
{
|
||||
return ($this->useHttps ? 'https://' : 'http://') . $this->host . $path;
|
||||
}
|
||||
/**
|
||||
* @param int $statusCode the HTTP status code
|
||||
* @param string|null $contentType the response content-type
|
||||
* @param string|null $body the response body
|
||||
* @param string $service the service name
|
||||
* @param string $path the path used in the request
|
||||
*
|
||||
* @throws AuthenticationException
|
||||
* @throws HttpException
|
||||
* @throws InsufficientFundsException
|
||||
* @throws InvalidRequestException
|
||||
*/
|
||||
private function handle4xx(int $statusCode, ?string $contentType, ?string $body, string $service, string $path) : void
|
||||
{
|
||||
if ($body === null || $body === '') {
|
||||
throw new HttpException("Received a {$statusCode} error for {$service} with no body", $statusCode, $this->urlFor($path));
|
||||
}
|
||||
if ($contentType === null || !\strstr($contentType, 'json')) {
|
||||
throw new HttpException("Received a {$statusCode} error for {$service} with " . 'the following body: ' . $body, $statusCode, $this->urlFor($path));
|
||||
}
|
||||
$message = \json_decode($body, \true);
|
||||
if ($message === null) {
|
||||
throw new HttpException("Received a {$statusCode} error for {$service} but could " . 'not decode the response as JSON: ' . $this->jsonErrorDescription() . ' Body: ' . $body, $statusCode, $this->urlFor($path));
|
||||
}
|
||||
if (!isset($message['code']) || !isset($message['error'])) {
|
||||
throw new HttpException('Error response contains JSON but it does not ' . 'specify code or error keys: ' . $body, $statusCode, $this->urlFor($path));
|
||||
}
|
||||
$this->handleWebServiceError($message['error'], $message['code'], $statusCode, $path);
|
||||
}
|
||||
/**
|
||||
* @param string $message the error message from the web service
|
||||
* @param string $code the error code from the web service
|
||||
* @param int $statusCode the HTTP status code
|
||||
* @param string $path the path used in the request
|
||||
*
|
||||
* @throws AuthenticationException
|
||||
* @throws InvalidRequestException
|
||||
* @throws InsufficientFundsException
|
||||
*/
|
||||
private function handleWebServiceError(string $message, string $code, int $statusCode, string $path) : void
|
||||
{
|
||||
switch ($code) {
|
||||
case 'IP_ADDRESS_NOT_FOUND':
|
||||
case 'IP_ADDRESS_RESERVED':
|
||||
throw new IpAddressNotFoundException($message, $code, $statusCode, $this->urlFor($path));
|
||||
case 'ACCOUNT_ID_REQUIRED':
|
||||
case 'ACCOUNT_ID_UNKNOWN':
|
||||
case 'AUTHORIZATION_INVALID':
|
||||
case 'LICENSE_KEY_REQUIRED':
|
||||
case 'USER_ID_REQUIRED':
|
||||
case 'USER_ID_UNKNOWN':
|
||||
throw new AuthenticationException($message, $code, $statusCode, $this->urlFor($path));
|
||||
case 'OUT_OF_QUERIES':
|
||||
case 'INSUFFICIENT_FUNDS':
|
||||
throw new InsufficientFundsException($message, $code, $statusCode, $this->urlFor($path));
|
||||
case 'PERMISSION_REQUIRED':
|
||||
throw new PermissionRequiredException($message, $code, $statusCode, $this->urlFor($path));
|
||||
default:
|
||||
throw new InvalidRequestException($message, $code, $statusCode, $this->urlFor($path));
|
||||
}
|
||||
}
|
||||
/**
|
||||
* @param int $statusCode the HTTP status code
|
||||
* @param string $service the service name
|
||||
* @param string $path the URI path used in the request
|
||||
*
|
||||
* @throws HttpException
|
||||
*/
|
||||
private function handle5xx(int $statusCode, string $service, string $path) : void
|
||||
{
|
||||
throw new HttpException("Received a server error ({$statusCode}) for {$service}", $statusCode, $this->urlFor($path));
|
||||
}
|
||||
/**
|
||||
* @param int $statusCode the HTTP status code
|
||||
* @param string $service the service name
|
||||
* @param string $path the URI path used in the request
|
||||
*
|
||||
* @throws HttpException
|
||||
*/
|
||||
private function handleUnexpectedStatus(int $statusCode, string $service, string $path) : void
|
||||
{
|
||||
throw new HttpException('Received an unexpected HTTP status ' . "({$statusCode}) for {$service}", $statusCode, $this->urlFor($path));
|
||||
}
|
||||
/**
|
||||
* @param int $statusCode the HTTP status code
|
||||
* @param string|null $body the successful request body
|
||||
* @param string $service the service name
|
||||
*
|
||||
* @throws WebServiceException if a response body is included but not
|
||||
* expected, or is not expected but not
|
||||
* included, or is expected and included
|
||||
* but cannot be decoded as JSON
|
||||
*
|
||||
* @return array|null the decoded request body
|
||||
*/
|
||||
private function handleSuccess(int $statusCode, ?string $body, string $service) : ?array
|
||||
{
|
||||
// A 204 should have no response body
|
||||
if ($statusCode === 204) {
|
||||
if ($body !== null && $body !== '') {
|
||||
throw new WebServiceException("Received a 204 response for {$service} along with an " . "unexpected HTTP body: {$body}");
|
||||
}
|
||||
return null;
|
||||
}
|
||||
// A 200 should have a valid JSON body
|
||||
if ($body === null || $body === '') {
|
||||
throw new WebServiceException("Received a 200 response for {$service} but did not " . 'receive a HTTP body.');
|
||||
}
|
||||
$decodedContent = \json_decode($body, \true);
|
||||
if ($decodedContent === null) {
|
||||
throw new WebServiceException("Received a 200 response for {$service} but could " . 'not decode the response as JSON: ' . $this->jsonErrorDescription() . ' Body: ' . $body);
|
||||
}
|
||||
return $decodedContent;
|
||||
}
|
||||
private function getCaBundle() : ?string
|
||||
{
|
||||
$curlVersion = \curl_version();
|
||||
// On OS X, when the SSL version is "SecureTransport", the system's
|
||||
// keychain will be used.
|
||||
if ($curlVersion['ssl_version'] === 'SecureTransport') {
|
||||
return null;
|
||||
}
|
||||
$cert = CaBundle::getSystemCaRootBundlePath();
|
||||
// Check if the cert is inside a phar. If so, we need to copy the cert
|
||||
// to a temp file so that curl can see it.
|
||||
if (\substr($cert, 0, 7) === 'phar://') {
|
||||
$tempDir = \sys_get_temp_dir();
|
||||
$newCert = \tempnam($tempDir, 'geoip2-');
|
||||
if ($newCert === \false) {
|
||||
throw new \RuntimeException("Unable to create temporary file in {$tempDir}");
|
||||
}
|
||||
if (!\copy($cert, $newCert)) {
|
||||
throw new \RuntimeException("Could not copy {$cert} to {$newCert}: " . \var_export(\error_get_last(), \true));
|
||||
}
|
||||
// We use a shutdown function rather than the destructor as the
|
||||
// destructor isn't called on a fatal error such as an uncaught
|
||||
// exception.
|
||||
\register_shutdown_function(function () use($newCert) {
|
||||
\unlink($newCert);
|
||||
});
|
||||
$cert = $newCert;
|
||||
}
|
||||
if (!\file_exists($cert)) {
|
||||
throw new \RuntimeException("CA cert does not exist at {$cert}");
|
||||
}
|
||||
return $cert;
|
||||
}
|
||||
}
|
||||
108
plugins/system/tgeoip/vendor/maxmind/web-service-common/src/WebService/Http/CurlRequest.php
vendored
Normal file
108
plugins/system/tgeoip/vendor/maxmind/web-service-common/src/WebService/Http/CurlRequest.php
vendored
Normal file
@ -0,0 +1,108 @@
|
||||
<?php
|
||||
|
||||
declare (strict_types=1);
|
||||
namespace Tassos\Vendor\MaxMind\WebService\Http;
|
||||
|
||||
use Tassos\Vendor\MaxMind\Exception\HttpException;
|
||||
/**
|
||||
* This class is for internal use only. Semantic versioning does not not apply.
|
||||
*
|
||||
* @internal
|
||||
*/
|
||||
class CurlRequest implements Request
|
||||
{
|
||||
/**
|
||||
* @var \CurlHandle
|
||||
*/
|
||||
private $ch;
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
private $url;
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
private $options;
|
||||
public function __construct(string $url, array $options)
|
||||
{
|
||||
$this->url = $url;
|
||||
$this->options = $options;
|
||||
$this->ch = $options['curlHandle'];
|
||||
}
|
||||
/**
|
||||
* @throws HttpException
|
||||
*/
|
||||
public function post(string $body) : array
|
||||
{
|
||||
$curl = $this->createCurl();
|
||||
\curl_setopt($curl, \CURLOPT_POST, \true);
|
||||
\curl_setopt($curl, \CURLOPT_POSTFIELDS, $body);
|
||||
return $this->execute($curl);
|
||||
}
|
||||
public function get() : array
|
||||
{
|
||||
$curl = $this->createCurl();
|
||||
\curl_setopt($curl, \CURLOPT_HTTPGET, \true);
|
||||
return $this->execute($curl);
|
||||
}
|
||||
/**
|
||||
* @return \CurlHandle
|
||||
*/
|
||||
private function createCurl()
|
||||
{
|
||||
\curl_reset($this->ch);
|
||||
$opts = [];
|
||||
$opts[\CURLOPT_URL] = $this->url;
|
||||
if (!empty($this->options['caBundle'])) {
|
||||
$opts[\CURLOPT_CAINFO] = $this->options['caBundle'];
|
||||
}
|
||||
$opts[\CURLOPT_ENCODING] = '';
|
||||
$opts[\CURLOPT_SSL_VERIFYHOST] = 2;
|
||||
$opts[\CURLOPT_FOLLOWLOCATION] = \false;
|
||||
$opts[\CURLOPT_SSL_VERIFYPEER] = \true;
|
||||
$opts[\CURLOPT_RETURNTRANSFER] = \true;
|
||||
$opts[\CURLOPT_HTTPHEADER] = $this->options['headers'];
|
||||
$opts[\CURLOPT_USERAGENT] = $this->options['userAgent'];
|
||||
$opts[\CURLOPT_PROXY] = $this->options['proxy'];
|
||||
// The defined()s are here as the *_MS opts are not available on older
|
||||
// cURL versions
|
||||
$connectTimeout = $this->options['connectTimeout'];
|
||||
if (\defined('CURLOPT_CONNECTTIMEOUT_MS')) {
|
||||
$opts[\CURLOPT_CONNECTTIMEOUT_MS] = \ceil($connectTimeout * 1000);
|
||||
} else {
|
||||
$opts[\CURLOPT_CONNECTTIMEOUT] = \ceil($connectTimeout);
|
||||
}
|
||||
$timeout = $this->options['timeout'];
|
||||
if (\defined('CURLOPT_TIMEOUT_MS')) {
|
||||
$opts[\CURLOPT_TIMEOUT_MS] = \ceil($timeout * 1000);
|
||||
} else {
|
||||
$opts[\CURLOPT_TIMEOUT] = \ceil($timeout);
|
||||
}
|
||||
\curl_setopt_array($this->ch, $opts);
|
||||
return $this->ch;
|
||||
}
|
||||
/**
|
||||
* @param \CurlHandle $curl
|
||||
*
|
||||
* @throws HttpException
|
||||
*/
|
||||
private function execute($curl) : array
|
||||
{
|
||||
$body = \curl_exec($curl);
|
||||
if ($errno = \curl_errno($curl)) {
|
||||
$errorMessage = \curl_error($curl);
|
||||
throw new HttpException("cURL error ({$errno}): {$errorMessage}", 0, $this->url);
|
||||
}
|
||||
$statusCode = \curl_getinfo($curl, \CURLINFO_HTTP_CODE);
|
||||
$contentType = \curl_getinfo($curl, \CURLINFO_CONTENT_TYPE);
|
||||
return [
|
||||
$statusCode,
|
||||
// The PHP docs say "Content-Type: of the requested document. NULL
|
||||
// indicates server did not send valid Content-Type: header" for
|
||||
// CURLINFO_CONTENT_TYPE. However, it will return FALSE if no header
|
||||
// is set. To keep our types simple, we return null in this case.
|
||||
$contentType === \false ? null : $contentType,
|
||||
$body,
|
||||
];
|
||||
}
|
||||
}
|
||||
16
plugins/system/tgeoip/vendor/maxmind/web-service-common/src/WebService/Http/Request.php
vendored
Normal file
16
plugins/system/tgeoip/vendor/maxmind/web-service-common/src/WebService/Http/Request.php
vendored
Normal file
@ -0,0 +1,16 @@
|
||||
<?php
|
||||
|
||||
declare (strict_types=1);
|
||||
namespace Tassos\Vendor\MaxMind\WebService\Http;
|
||||
|
||||
/**
|
||||
* Interface Request.
|
||||
*
|
||||
* @internal
|
||||
*/
|
||||
interface Request
|
||||
{
|
||||
public function __construct(string $url, array $options);
|
||||
public function post(string $body) : array;
|
||||
public function get() : array;
|
||||
}
|
||||
42
plugins/system/tgeoip/vendor/maxmind/web-service-common/src/WebService/Http/RequestFactory.php
vendored
Normal file
42
plugins/system/tgeoip/vendor/maxmind/web-service-common/src/WebService/Http/RequestFactory.php
vendored
Normal file
@ -0,0 +1,42 @@
|
||||
<?php
|
||||
|
||||
declare (strict_types=1);
|
||||
namespace Tassos\Vendor\MaxMind\WebService\Http;
|
||||
|
||||
/**
|
||||
* Class RequestFactory.
|
||||
*
|
||||
* @internal
|
||||
*/
|
||||
class RequestFactory
|
||||
{
|
||||
/**
|
||||
* Keep the cURL resource here, so that if there are multiple API requests
|
||||
* done the connection is kept alive, SSL resumption can be used
|
||||
* etcetera.
|
||||
*
|
||||
* @var \CurlHandle|null
|
||||
*/
|
||||
private $ch;
|
||||
public function __destruct()
|
||||
{
|
||||
if (!empty($this->ch)) {
|
||||
\curl_close($this->ch);
|
||||
}
|
||||
}
|
||||
/**
|
||||
* @return \CurlHandle
|
||||
*/
|
||||
private function getCurlHandle()
|
||||
{
|
||||
if (empty($this->ch)) {
|
||||
$this->ch = \curl_init();
|
||||
}
|
||||
return $this->ch;
|
||||
}
|
||||
public function request(string $url, array $options) : Request
|
||||
{
|
||||
$options['curlHandle'] = $this->getCurlHandle();
|
||||
return new CurlRequest($url, $options);
|
||||
}
|
||||
}
|
||||
37
plugins/system/tgeoip/vendor/scoper-autoload.php
vendored
Normal file
37
plugins/system/tgeoip/vendor/scoper-autoload.php
vendored
Normal file
@ -0,0 +1,37 @@
|
||||
<?php
|
||||
|
||||
// scoper-autoload.php @generated by PhpScoper
|
||||
|
||||
// Backup the autoloaded Composer files
|
||||
if (isset($GLOBALS['__composer_autoload_files'])) {
|
||||
$existingComposerAutoloadFiles = $GLOBALS['__composer_autoload_files'];
|
||||
}
|
||||
|
||||
$loader = require_once __DIR__.'/autoload.php';
|
||||
// Ensure InstalledVersions is available
|
||||
$installedVersionsPath = __DIR__.'/composer/InstalledVersions.php';
|
||||
if (file_exists($installedVersionsPath)) require_once $installedVersionsPath;
|
||||
|
||||
// Restore the backup
|
||||
if (isset($existingComposerAutoloadFiles)) {
|
||||
$GLOBALS['__composer_autoload_files'] = $existingComposerAutoloadFiles;
|
||||
} else {
|
||||
unset($GLOBALS['__composer_autoload_files']);
|
||||
}
|
||||
|
||||
// Class aliases. For more information see:
|
||||
// https://github.com/humbug/php-scoper/blob/master/docs/further-reading.md#class-aliases
|
||||
if (!function_exists('humbug_phpscoper_expose_class')) {
|
||||
function humbug_phpscoper_expose_class(string $exposed, string $prefixed): void {
|
||||
if (!class_exists($exposed, false) && !interface_exists($exposed, false) && !trait_exists($exposed, false)) {
|
||||
spl_autoload_call($prefixed);
|
||||
}
|
||||
}
|
||||
}
|
||||
humbug_phpscoper_expose_class('ComposerAutoloaderInit087ac1c88c9dd7b872309175c7c60d7d', 'Tassos\Vendor\ComposerAutoloaderInit087ac1c88c9dd7b872309175c7c60d7d');
|
||||
|
||||
// Function aliases. For more information see:
|
||||
// https://github.com/humbug/php-scoper/blob/master/docs/further-reading.md#function-aliases
|
||||
if (!function_exists('mmdb_autoload')) { function mmdb_autoload() { return \Tassos\Vendor\mmdb_autoload(...func_get_args()); } }
|
||||
|
||||
return $loader;
|
||||
4
plugins/system/tgeoip/vendor/splitbrain/php-archive/apigen.neon
vendored
Normal file
4
plugins/system/tgeoip/vendor/splitbrain/php-archive/apigen.neon
vendored
Normal file
@ -0,0 +1,4 @@
|
||||
tree: Yes
|
||||
deprecated: Yes
|
||||
accessLevels: [public]
|
||||
todo: Yes
|
||||
63
plugins/system/tgeoip/vendor/splitbrain/php-archive/generate-api.sh
vendored
Normal file
63
plugins/system/tgeoip/vendor/splitbrain/php-archive/generate-api.sh
vendored
Normal file
@ -0,0 +1,63 @@
|
||||
#!/bin/sh
|
||||
|
||||
# where's the source files?
|
||||
SRC='src'
|
||||
|
||||
# for what branch to trigger
|
||||
BRANCH='master'
|
||||
|
||||
# github repo
|
||||
REPO='splitbrain/php-archive'
|
||||
|
||||
# ---- About -------------------------------------------------------
|
||||
#
|
||||
# This script use apigen to generate the documentation for the
|
||||
# repository configured above. When run locally, the documentation
|
||||
# will be placed in the 'docs' folder.
|
||||
# However this script can also be run from travis. This requires
|
||||
# the setup of a secret token as described at http://bit.ly/1MNbPn0
|
||||
#
|
||||
# Additional configuration can be done within an apigen.neon file
|
||||
#
|
||||
# ---- no modifications below ---------------------------------------
|
||||
|
||||
# when on travis, build outside of repository, otherwise locally
|
||||
if [ -z "$TRAVIS" ]; then
|
||||
DST='docs'
|
||||
else
|
||||
DST='../gh-pages'
|
||||
if [ "$TRAVIS_PHP_VERSION" != '7.2' ]; then exit; fi
|
||||
if [ "$TRAVIS_BRANCH" != "$BRANCH" ]; then exit; fi
|
||||
if [ "$TRAVIS_PULL_REQUEST" != 'false' ]; then exit; fi
|
||||
if [ -z "$GH_TOKEN" ]; then
|
||||
echo "GH_TOKEN not set! See: http://bit.ly/1MNbPn0"
|
||||
exit
|
||||
fi
|
||||
fi
|
||||
|
||||
# Get ApiGen.phar
|
||||
wget http://www.apigen.org/apigen.phar -O apigen.phar
|
||||
|
||||
# Generate SDK Docs
|
||||
php apigen.phar generate --template-theme="bootstrap" -s $SRC -d $DST
|
||||
|
||||
|
||||
### if we're not on travis, we're done
|
||||
if [ -z "$TRAVIS" ]; then exit; fi
|
||||
|
||||
# go to the generated docs
|
||||
cd $DST || exit
|
||||
|
||||
# Set identity
|
||||
git config --global user.email "travis@travis-ci.org"
|
||||
git config --global user.name "Travis"
|
||||
|
||||
# Add branch
|
||||
git init
|
||||
git remote add origin https://${GH_TOKEN}@github.com/${REPO}.git > /dev/null
|
||||
git checkout -B gh-pages
|
||||
|
||||
# Push generated files
|
||||
git add .
|
||||
git commit -m "Docs updated by Travis"
|
||||
git push origin gh-pages -fq > /dev/null
|
||||
21
plugins/system/tgeoip/vendor/splitbrain/php-archive/phpunit.xml
vendored
Normal file
21
plugins/system/tgeoip/vendor/splitbrain/php-archive/phpunit.xml
vendored
Normal file
@ -0,0 +1,21 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<phpunit backupGlobals="false"
|
||||
backupStaticAttributes="false"
|
||||
bootstrap="vendor/autoload.php"
|
||||
colors="true"
|
||||
convertErrorsToExceptions="true"
|
||||
convertNoticesToExceptions="true"
|
||||
convertWarningsToExceptions="true"
|
||||
processIsolation="false"
|
||||
stopOnFailure="false">
|
||||
<testsuites>
|
||||
<testsuite name="Test Suite">
|
||||
<directory suffix=".php">./tests/</directory>
|
||||
</testsuite>
|
||||
</testsuites>
|
||||
<filter>
|
||||
<whitelist processUncoveredFilesFromWhitelist="false">
|
||||
<directory suffix=".php">src</directory>
|
||||
</whitelist>
|
||||
</filter>
|
||||
</phpunit>
|
||||
122
plugins/system/tgeoip/vendor/splitbrain/php-archive/src/Archive.php
vendored
Normal file
122
plugins/system/tgeoip/vendor/splitbrain/php-archive/src/Archive.php
vendored
Normal file
@ -0,0 +1,122 @@
|
||||
<?php
|
||||
|
||||
namespace Tassos\Vendor\splitbrain\PHPArchive;
|
||||
|
||||
abstract class Archive
|
||||
{
|
||||
const COMPRESS_AUTO = -1;
|
||||
const COMPRESS_NONE = 0;
|
||||
const COMPRESS_GZIP = 1;
|
||||
const COMPRESS_BZIP = 2;
|
||||
/** @var callable */
|
||||
protected $callback;
|
||||
/**
|
||||
* Set the compression level and type
|
||||
*
|
||||
* @param int $level Compression level (0 to 9)
|
||||
* @param int $type Type of compression to use (use COMPRESS_* constants)
|
||||
* @throws ArchiveIllegalCompressionException
|
||||
*/
|
||||
public abstract function setCompression($level = 9, $type = Archive::COMPRESS_AUTO);
|
||||
/**
|
||||
* Open an existing archive file for reading
|
||||
*
|
||||
* @param string $file
|
||||
* @throws ArchiveIOException
|
||||
*/
|
||||
public abstract function open($file);
|
||||
/**
|
||||
* Read the contents of an archive
|
||||
*
|
||||
* This function lists the files stored in the archive, and returns an indexed array of FileInfo objects
|
||||
*
|
||||
* The archive is closed afer reading the contents, because rewinding is not possible in bzip2 streams.
|
||||
* Reopen the file with open() again if you want to do additional operations
|
||||
*
|
||||
* @return FileInfo[]
|
||||
*/
|
||||
public abstract function contents();
|
||||
/**
|
||||
* Extract an existing archive
|
||||
*
|
||||
* The $strip parameter allows you to strip a certain number of path components from the filenames
|
||||
* found in the archive file, similar to the --strip-components feature of GNU tar. This is triggered when
|
||||
* an integer is passed as $strip.
|
||||
* Alternatively a fixed string prefix may be passed in $strip. If the filename matches this prefix,
|
||||
* the prefix will be stripped. It is recommended to give prefixes with a trailing slash.
|
||||
*
|
||||
* By default this will extract all files found in the archive. You can restrict the output using the $include
|
||||
* and $exclude parameter. Both expect a full regular expression (including delimiters and modifiers). If
|
||||
* $include is set, only files that match this expression will be extracted. Files that match the $exclude
|
||||
* expression will never be extracted. Both parameters can be used in combination. Expressions are matched against
|
||||
* stripped filenames as described above.
|
||||
*
|
||||
* The archive is closed afterwards. Reopen the file with open() again if you want to do additional operations
|
||||
*
|
||||
* @param string $outdir the target directory for extracting
|
||||
* @param int|string $strip either the number of path components or a fixed prefix to strip
|
||||
* @param string $exclude a regular expression of files to exclude
|
||||
* @param string $include a regular expression of files to include
|
||||
* @throws ArchiveIOException
|
||||
* @return array
|
||||
*/
|
||||
public abstract function extract($outdir, $strip = '', $exclude = '', $include = '');
|
||||
/**
|
||||
* Create a new archive file
|
||||
*
|
||||
* If $file is empty, the archive file will be created in memory
|
||||
*
|
||||
* @param string $file
|
||||
*/
|
||||
public abstract function create($file = '');
|
||||
/**
|
||||
* Add a file to the current archive using an existing file in the filesystem
|
||||
*
|
||||
* @param string $file path to the original file
|
||||
* @param string|FileInfo $fileinfo either the name to us in archive (string) or a FileInfo oject with all meta data, empty to take from original
|
||||
* @throws ArchiveIOException
|
||||
*/
|
||||
public abstract function addFile($file, $fileinfo = '');
|
||||
/**
|
||||
* Add a file to the current archive using the given $data as content
|
||||
*
|
||||
* @param string|FileInfo $fileinfo either the name to us in archive (string) or a FileInfo oject with all meta data
|
||||
* @param string $data binary content of the file to add
|
||||
* @throws ArchiveIOException
|
||||
*/
|
||||
public abstract function addData($fileinfo, $data);
|
||||
/**
|
||||
* Close the archive, close all file handles
|
||||
*
|
||||
* After a call to this function no more data can be added to the archive, for
|
||||
* read access no reading is allowed anymore
|
||||
*/
|
||||
public abstract function close();
|
||||
/**
|
||||
* Returns the created in-memory archive data
|
||||
*
|
||||
* This implicitly calls close() on the Archive
|
||||
*/
|
||||
public abstract function getArchive();
|
||||
/**
|
||||
* Save the created in-memory archive data
|
||||
*
|
||||
* Note: It is more memory effective to specify the filename in the create() function and
|
||||
* let the library work on the new file directly.
|
||||
*
|
||||
* @param string $file
|
||||
*/
|
||||
public abstract function save($file);
|
||||
/**
|
||||
* Set a callback function to be called whenever a file is added or extracted.
|
||||
*
|
||||
* The callback is called with a FileInfo object as parameter. You can use this to show progress
|
||||
* info during an operation.
|
||||
*
|
||||
* @param callable $callback
|
||||
*/
|
||||
public function setCallback($callback)
|
||||
{
|
||||
$this->callback = $callback;
|
||||
}
|
||||
}
|
||||
10
plugins/system/tgeoip/vendor/splitbrain/php-archive/src/ArchiveCorruptedException.php
vendored
Normal file
10
plugins/system/tgeoip/vendor/splitbrain/php-archive/src/ArchiveCorruptedException.php
vendored
Normal file
@ -0,0 +1,10 @@
|
||||
<?php
|
||||
|
||||
namespace Tassos\Vendor\splitbrain\PHPArchive;
|
||||
|
||||
/**
|
||||
* The archive is unreadable
|
||||
*/
|
||||
class ArchiveCorruptedException extends \Exception
|
||||
{
|
||||
}
|
||||
10
plugins/system/tgeoip/vendor/splitbrain/php-archive/src/ArchiveIOException.php
vendored
Normal file
10
plugins/system/tgeoip/vendor/splitbrain/php-archive/src/ArchiveIOException.php
vendored
Normal file
@ -0,0 +1,10 @@
|
||||
<?php
|
||||
|
||||
namespace Tassos\Vendor\splitbrain\PHPArchive;
|
||||
|
||||
/**
|
||||
* Read/Write Errors
|
||||
*/
|
||||
class ArchiveIOException extends \Exception
|
||||
{
|
||||
}
|
||||
10
plugins/system/tgeoip/vendor/splitbrain/php-archive/src/ArchiveIllegalCompressionException.php
vendored
Normal file
10
plugins/system/tgeoip/vendor/splitbrain/php-archive/src/ArchiveIllegalCompressionException.php
vendored
Normal file
@ -0,0 +1,10 @@
|
||||
<?php
|
||||
|
||||
namespace Tassos\Vendor\splitbrain\PHPArchive;
|
||||
|
||||
/**
|
||||
* Bad or unsupported compression settings requested
|
||||
*/
|
||||
class ArchiveIllegalCompressionException extends \Exception
|
||||
{
|
||||
}
|
||||
323
plugins/system/tgeoip/vendor/splitbrain/php-archive/src/FileInfo.php
vendored
Normal file
323
plugins/system/tgeoip/vendor/splitbrain/php-archive/src/FileInfo.php
vendored
Normal file
@ -0,0 +1,323 @@
|
||||
<?php
|
||||
|
||||
namespace Tassos\Vendor\splitbrain\PHPArchive;
|
||||
|
||||
/**
|
||||
* Class FileInfo
|
||||
*
|
||||
* stores meta data about a file in an Archive
|
||||
*
|
||||
* @author Andreas Gohr <andi@splitbrain.org>
|
||||
* @package splitbrain\PHPArchive
|
||||
* @license MIT
|
||||
*/
|
||||
class FileInfo
|
||||
{
|
||||
protected $isdir = \false;
|
||||
protected $path = '';
|
||||
protected $size = 0;
|
||||
protected $csize = 0;
|
||||
protected $mtime = 0;
|
||||
protected $mode = 0664;
|
||||
protected $owner = '';
|
||||
protected $group = '';
|
||||
protected $uid = 0;
|
||||
protected $gid = 0;
|
||||
protected $comment = '';
|
||||
/**
|
||||
* initialize dynamic defaults
|
||||
*
|
||||
* @param string $path The path of the file, can also be set later through setPath()
|
||||
*/
|
||||
public function __construct($path = '')
|
||||
{
|
||||
$this->mtime = \time();
|
||||
$this->setPath($path);
|
||||
}
|
||||
/**
|
||||
* Handle calls to deprecated methods
|
||||
*
|
||||
* @param string $name
|
||||
* @param array $arguments
|
||||
* @return mixed
|
||||
*/
|
||||
public function __call($name, $arguments)
|
||||
{
|
||||
if ($name === 'match') {
|
||||
\trigger_error('FileInfo::match() is deprecated, use FileInfo::matchExpression() instead.', \E_USER_NOTICE);
|
||||
return \call_user_func_array([$this, $name], $arguments);
|
||||
}
|
||||
\trigger_error('Call to undefined method FileInfo::' . $name . '()', \E_USER_ERROR);
|
||||
return null;
|
||||
}
|
||||
/**
|
||||
* Factory to build FileInfo from existing file or directory
|
||||
*
|
||||
* @param string $path path to a file on the local file system
|
||||
* @param string $as optional path to use inside the archive
|
||||
* @throws FileInfoException
|
||||
* @return FileInfo
|
||||
*/
|
||||
public static function fromPath($path, $as = '')
|
||||
{
|
||||
\clearstatcache(\false, $path);
|
||||
if (!\file_exists($path)) {
|
||||
throw new FileInfoException("{$path} does not exist");
|
||||
}
|
||||
$stat = \stat($path);
|
||||
$file = new FileInfo();
|
||||
$file->setPath($path);
|
||||
$file->setIsdir(\is_dir($path));
|
||||
$file->setMode(\fileperms($path));
|
||||
$file->setOwner(\fileowner($path));
|
||||
$file->setGroup(\filegroup($path));
|
||||
$file->setSize(\filesize($path));
|
||||
$file->setUid($stat['uid']);
|
||||
$file->setGid($stat['gid']);
|
||||
$file->setMtime($stat['mtime']);
|
||||
if ($as) {
|
||||
$file->setPath($as);
|
||||
}
|
||||
return $file;
|
||||
}
|
||||
/**
|
||||
* @return int the filesize. always 0 for directories
|
||||
*/
|
||||
public function getSize()
|
||||
{
|
||||
if ($this->isdir) {
|
||||
return 0;
|
||||
}
|
||||
return $this->size;
|
||||
}
|
||||
/**
|
||||
* @param int $size
|
||||
*/
|
||||
public function setSize($size)
|
||||
{
|
||||
$this->size = $size;
|
||||
}
|
||||
/**
|
||||
* @return int
|
||||
*/
|
||||
public function getCompressedSize()
|
||||
{
|
||||
return $this->csize;
|
||||
}
|
||||
/**
|
||||
* @param int $csize
|
||||
*/
|
||||
public function setCompressedSize($csize)
|
||||
{
|
||||
$this->csize = $csize;
|
||||
}
|
||||
/**
|
||||
* @return int
|
||||
*/
|
||||
public function getMtime()
|
||||
{
|
||||
return $this->mtime;
|
||||
}
|
||||
/**
|
||||
* @param int $mtime
|
||||
*/
|
||||
public function setMtime($mtime)
|
||||
{
|
||||
$this->mtime = $mtime;
|
||||
}
|
||||
/**
|
||||
* @return int
|
||||
*/
|
||||
public function getGid()
|
||||
{
|
||||
return $this->gid;
|
||||
}
|
||||
/**
|
||||
* @param int $gid
|
||||
*/
|
||||
public function setGid($gid)
|
||||
{
|
||||
$this->gid = $gid;
|
||||
}
|
||||
/**
|
||||
* @return int
|
||||
*/
|
||||
public function getUid()
|
||||
{
|
||||
return $this->uid;
|
||||
}
|
||||
/**
|
||||
* @param int $uid
|
||||
*/
|
||||
public function setUid($uid)
|
||||
{
|
||||
$this->uid = $uid;
|
||||
}
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function getComment()
|
||||
{
|
||||
return $this->comment;
|
||||
}
|
||||
/**
|
||||
* @param string $comment
|
||||
*/
|
||||
public function setComment($comment)
|
||||
{
|
||||
$this->comment = $comment;
|
||||
}
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function getGroup()
|
||||
{
|
||||
return $this->group;
|
||||
}
|
||||
/**
|
||||
* @param string $group
|
||||
*/
|
||||
public function setGroup($group)
|
||||
{
|
||||
$this->group = $group;
|
||||
}
|
||||
/**
|
||||
* @return boolean
|
||||
*/
|
||||
public function getIsdir()
|
||||
{
|
||||
return $this->isdir;
|
||||
}
|
||||
/**
|
||||
* @param boolean $isdir
|
||||
*/
|
||||
public function setIsdir($isdir)
|
||||
{
|
||||
// default mode for directories
|
||||
if ($isdir && $this->mode === 0664) {
|
||||
$this->mode = 0775;
|
||||
}
|
||||
$this->isdir = $isdir;
|
||||
}
|
||||
/**
|
||||
* @return int
|
||||
*/
|
||||
public function getMode()
|
||||
{
|
||||
return $this->mode;
|
||||
}
|
||||
/**
|
||||
* @param int $mode
|
||||
*/
|
||||
public function setMode($mode)
|
||||
{
|
||||
$this->mode = $mode;
|
||||
}
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function getOwner()
|
||||
{
|
||||
return $this->owner;
|
||||
}
|
||||
/**
|
||||
* @param string $owner
|
||||
*/
|
||||
public function setOwner($owner)
|
||||
{
|
||||
$this->owner = $owner;
|
||||
}
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function getPath()
|
||||
{
|
||||
return $this->path;
|
||||
}
|
||||
/**
|
||||
* @param string $path
|
||||
*/
|
||||
public function setPath($path)
|
||||
{
|
||||
$this->path = $this->cleanPath($path);
|
||||
}
|
||||
/**
|
||||
* Cleans up a path and removes relative parts, also strips leading slashes
|
||||
*
|
||||
* @param string $path
|
||||
* @return string
|
||||
*/
|
||||
protected function cleanPath($path)
|
||||
{
|
||||
$path = \str_replace('\\', '/', $path);
|
||||
$path = \explode('/', $path);
|
||||
$newpath = array();
|
||||
foreach ($path as $p) {
|
||||
if ($p === '' || $p === '.') {
|
||||
continue;
|
||||
}
|
||||
if ($p === '..') {
|
||||
\array_pop($newpath);
|
||||
continue;
|
||||
}
|
||||
\array_push($newpath, $p);
|
||||
}
|
||||
return \trim(\implode('/', $newpath), '/');
|
||||
}
|
||||
/**
|
||||
* Strip given prefix or number of path segments from the filename
|
||||
*
|
||||
* The $strip parameter allows you to strip a certain number of path components from the filenames
|
||||
* found in the tar file, similar to the --strip-components feature of GNU tar. This is triggered when
|
||||
* an integer is passed as $strip.
|
||||
* Alternatively a fixed string prefix may be passed in $strip. If the filename matches this prefix,
|
||||
* the prefix will be stripped. It is recommended to give prefixes with a trailing slash.
|
||||
*
|
||||
* @param int|string $strip
|
||||
*/
|
||||
public function strip($strip)
|
||||
{
|
||||
$filename = $this->getPath();
|
||||
$striplen = \strlen($strip);
|
||||
if (\is_int($strip)) {
|
||||
// if $strip is an integer we strip this many path components
|
||||
$parts = \explode('/', $filename);
|
||||
if (!$this->getIsdir()) {
|
||||
$base = \array_pop($parts);
|
||||
// keep filename itself
|
||||
} else {
|
||||
$base = '';
|
||||
}
|
||||
$filename = \join('/', \array_slice($parts, $strip));
|
||||
if ($base) {
|
||||
$filename .= "/{$base}";
|
||||
}
|
||||
} else {
|
||||
// if strip is a string, we strip a prefix here
|
||||
if (\substr($filename, 0, $striplen) == $strip) {
|
||||
$filename = \substr($filename, $striplen);
|
||||
}
|
||||
}
|
||||
$this->setPath($filename);
|
||||
}
|
||||
/**
|
||||
* Does the file match the given include and exclude expressions?
|
||||
*
|
||||
* Exclude rules take precedence over include rules
|
||||
*
|
||||
* @param string $include Regular expression of files to include
|
||||
* @param string $exclude Regular expression of files to exclude
|
||||
* @return bool
|
||||
*/
|
||||
public function matchExpression($include = '', $exclude = '')
|
||||
{
|
||||
$extract = \true;
|
||||
if ($include && !\preg_match($include, $this->getPath())) {
|
||||
$extract = \false;
|
||||
}
|
||||
if ($exclude && \preg_match($exclude, $this->getPath())) {
|
||||
$extract = \false;
|
||||
}
|
||||
return $extract;
|
||||
}
|
||||
}
|
||||
10
plugins/system/tgeoip/vendor/splitbrain/php-archive/src/FileInfoException.php
vendored
Normal file
10
plugins/system/tgeoip/vendor/splitbrain/php-archive/src/FileInfoException.php
vendored
Normal file
@ -0,0 +1,10 @@
|
||||
<?php
|
||||
|
||||
namespace Tassos\Vendor\splitbrain\PHPArchive;
|
||||
|
||||
/**
|
||||
* File meta data problems
|
||||
*/
|
||||
class FileInfoException extends \Exception
|
||||
{
|
||||
}
|
||||
640
plugins/system/tgeoip/vendor/splitbrain/php-archive/src/Tar.php
vendored
Normal file
640
plugins/system/tgeoip/vendor/splitbrain/php-archive/src/Tar.php
vendored
Normal file
@ -0,0 +1,640 @@
|
||||
<?php
|
||||
|
||||
namespace Tassos\Vendor\splitbrain\PHPArchive;
|
||||
|
||||
/**
|
||||
* Class Tar
|
||||
*
|
||||
* Creates or extracts Tar archives. Supports gz and bzip compression
|
||||
*
|
||||
* Long pathnames (>100 chars) are supported in POSIX ustar and GNU longlink formats.
|
||||
*
|
||||
* @author Andreas Gohr <andi@splitbrain.org>
|
||||
* @package splitbrain\PHPArchive
|
||||
* @license MIT
|
||||
*/
|
||||
class Tar extends Archive
|
||||
{
|
||||
protected $file = '';
|
||||
protected $comptype = Archive::COMPRESS_AUTO;
|
||||
protected $complevel = 9;
|
||||
protected $fh;
|
||||
protected $memory = '';
|
||||
protected $closed = \true;
|
||||
protected $writeaccess = \false;
|
||||
/**
|
||||
* Sets the compression to use
|
||||
*
|
||||
* @param int $level Compression level (0 to 9)
|
||||
* @param int $type Type of compression to use (use COMPRESS_* constants)
|
||||
* @throws ArchiveIllegalCompressionException
|
||||
*/
|
||||
public function setCompression($level = 9, $type = Archive::COMPRESS_AUTO)
|
||||
{
|
||||
$this->compressioncheck($type);
|
||||
if ($level < -1 || $level > 9) {
|
||||
throw new ArchiveIllegalCompressionException('Compression level should be between -1 and 9');
|
||||
}
|
||||
$this->comptype = $type;
|
||||
$this->complevel = $level;
|
||||
if ($level == 0) {
|
||||
$this->comptype = Archive::COMPRESS_NONE;
|
||||
}
|
||||
if ($type == Archive::COMPRESS_NONE) {
|
||||
$this->complevel = 0;
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Open an existing TAR file for reading
|
||||
*
|
||||
* @param string $file
|
||||
* @throws ArchiveIOException
|
||||
* @throws ArchiveIllegalCompressionException
|
||||
*/
|
||||
public function open($file)
|
||||
{
|
||||
$this->file = $file;
|
||||
// update compression to mach file
|
||||
if ($this->comptype == Tar::COMPRESS_AUTO) {
|
||||
$this->setCompression($this->complevel, $this->filetype($file));
|
||||
}
|
||||
// open file handles
|
||||
if ($this->comptype === Archive::COMPRESS_GZIP) {
|
||||
$this->fh = @\gzopen($this->file, 'rb');
|
||||
} elseif ($this->comptype === Archive::COMPRESS_BZIP) {
|
||||
$this->fh = @\bzopen($this->file, 'r');
|
||||
} else {
|
||||
$this->fh = @\fopen($this->file, 'rb');
|
||||
}
|
||||
if (!$this->fh) {
|
||||
throw new ArchiveIOException('Could not open file for reading: ' . $this->file);
|
||||
}
|
||||
$this->closed = \false;
|
||||
}
|
||||
/**
|
||||
* Read the contents of a TAR archive
|
||||
*
|
||||
* This function lists the files stored in the archive
|
||||
*
|
||||
* The archive is closed afer reading the contents, because rewinding is not possible in bzip2 streams.
|
||||
* Reopen the file with open() again if you want to do additional operations
|
||||
*
|
||||
* @throws ArchiveIOException
|
||||
* @throws ArchiveCorruptedException
|
||||
* @returns FileInfo[]
|
||||
*/
|
||||
public function contents()
|
||||
{
|
||||
$result = array();
|
||||
foreach ($this->yieldContents() as $fileinfo) {
|
||||
$result[] = $fileinfo;
|
||||
}
|
||||
return $result;
|
||||
}
|
||||
/**
|
||||
* Read the contents of a TAR archive and return each entry using yield
|
||||
* for memory efficiency.
|
||||
*
|
||||
* @see contents()
|
||||
* @throws ArchiveIOException
|
||||
* @throws ArchiveCorruptedException
|
||||
* @returns FileInfo[]
|
||||
*/
|
||||
public function yieldContents()
|
||||
{
|
||||
if ($this->closed || !$this->file) {
|
||||
throw new ArchiveIOException('Can not read from a closed archive');
|
||||
}
|
||||
while ($read = $this->readbytes(512)) {
|
||||
$header = $this->parseHeader($read);
|
||||
if (!\is_array($header)) {
|
||||
continue;
|
||||
}
|
||||
$this->skipbytes(\ceil($header['size'] / 512) * 512);
|
||||
(yield $this->header2fileinfo($header));
|
||||
}
|
||||
$this->close();
|
||||
}
|
||||
/**
|
||||
* Extract an existing TAR archive
|
||||
*
|
||||
* The $strip parameter allows you to strip a certain number of path components from the filenames
|
||||
* found in the tar file, similar to the --strip-components feature of GNU tar. This is triggered when
|
||||
* an integer is passed as $strip.
|
||||
* Alternatively a fixed string prefix may be passed in $strip. If the filename matches this prefix,
|
||||
* the prefix will be stripped. It is recommended to give prefixes with a trailing slash.
|
||||
*
|
||||
* By default this will extract all files found in the archive. You can restrict the output using the $include
|
||||
* and $exclude parameter. Both expect a full regular expression (including delimiters and modifiers). If
|
||||
* $include is set only files that match this expression will be extracted. Files that match the $exclude
|
||||
* expression will never be extracted. Both parameters can be used in combination. Expressions are matched against
|
||||
* stripped filenames as described above.
|
||||
*
|
||||
* The archive is closed afer reading the contents, because rewinding is not possible in bzip2 streams.
|
||||
* Reopen the file with open() again if you want to do additional operations
|
||||
*
|
||||
* @param string $outdir the target directory for extracting
|
||||
* @param int|string $strip either the number of path components or a fixed prefix to strip
|
||||
* @param string $exclude a regular expression of files to exclude
|
||||
* @param string $include a regular expression of files to include
|
||||
* @throws ArchiveIOException
|
||||
* @throws ArchiveCorruptedException
|
||||
* @return FileInfo[]
|
||||
*/
|
||||
public function extract($outdir, $strip = '', $exclude = '', $include = '')
|
||||
{
|
||||
if ($this->closed || !$this->file) {
|
||||
throw new ArchiveIOException('Can not read from a closed archive');
|
||||
}
|
||||
$outdir = \rtrim($outdir, '/');
|
||||
@\mkdir($outdir, 0777, \true);
|
||||
if (!\is_dir($outdir)) {
|
||||
throw new ArchiveIOException("Could not create directory '{$outdir}'");
|
||||
}
|
||||
$extracted = array();
|
||||
while ($dat = $this->readbytes(512)) {
|
||||
// read the file header
|
||||
$header = $this->parseHeader($dat);
|
||||
if (!\is_array($header)) {
|
||||
continue;
|
||||
}
|
||||
$fileinfo = $this->header2fileinfo($header);
|
||||
// apply strip rules
|
||||
$fileinfo->strip($strip);
|
||||
// skip unwanted files
|
||||
if (!\strlen($fileinfo->getPath()) || !$fileinfo->matchExpression($include, $exclude)) {
|
||||
$this->skipbytes(\ceil($header['size'] / 512) * 512);
|
||||
continue;
|
||||
}
|
||||
// create output directory
|
||||
$output = $outdir . '/' . $fileinfo->getPath();
|
||||
$directory = $fileinfo->getIsdir() ? $output : \dirname($output);
|
||||
if (!\file_exists($directory)) {
|
||||
\mkdir($directory, 0777, \true);
|
||||
}
|
||||
// extract data
|
||||
if (!$fileinfo->getIsdir()) {
|
||||
$fp = @\fopen($output, "wb");
|
||||
if (!$fp) {
|
||||
throw new ArchiveIOException('Could not open file for writing: ' . $output);
|
||||
}
|
||||
$size = \floor($header['size'] / 512);
|
||||
for ($i = 0; $i < $size; $i++) {
|
||||
\fwrite($fp, $this->readbytes(512), 512);
|
||||
}
|
||||
if ($header['size'] % 512 != 0) {
|
||||
\fwrite($fp, $this->readbytes(512), $header['size'] % 512);
|
||||
}
|
||||
\fclose($fp);
|
||||
@\touch($output, $fileinfo->getMtime());
|
||||
@\chmod($output, $fileinfo->getMode());
|
||||
} else {
|
||||
$this->skipbytes(\ceil($header['size'] / 512) * 512);
|
||||
// the size is usually 0 for directories
|
||||
}
|
||||
if (\is_callable($this->callback)) {
|
||||
\call_user_func($this->callback, $fileinfo);
|
||||
}
|
||||
$extracted[] = $fileinfo;
|
||||
}
|
||||
$this->close();
|
||||
return $extracted;
|
||||
}
|
||||
/**
|
||||
* Create a new TAR file
|
||||
*
|
||||
* If $file is empty, the tar file will be created in memory
|
||||
*
|
||||
* @param string $file
|
||||
* @throws ArchiveIOException
|
||||
* @throws ArchiveIllegalCompressionException
|
||||
*/
|
||||
public function create($file = '')
|
||||
{
|
||||
$this->file = $file;
|
||||
$this->memory = '';
|
||||
$this->fh = 0;
|
||||
if ($this->file) {
|
||||
// determine compression
|
||||
if ($this->comptype == Archive::COMPRESS_AUTO) {
|
||||
$this->setCompression($this->complevel, $this->filetype($file));
|
||||
}
|
||||
if ($this->comptype === Archive::COMPRESS_GZIP) {
|
||||
$this->fh = @\gzopen($this->file, 'wb' . $this->complevel);
|
||||
} elseif ($this->comptype === Archive::COMPRESS_BZIP) {
|
||||
$this->fh = @\bzopen($this->file, 'w');
|
||||
} else {
|
||||
$this->fh = @\fopen($this->file, 'wb');
|
||||
}
|
||||
if (!$this->fh) {
|
||||
throw new ArchiveIOException('Could not open file for writing: ' . $this->file);
|
||||
}
|
||||
}
|
||||
$this->writeaccess = \true;
|
||||
$this->closed = \false;
|
||||
}
|
||||
/**
|
||||
* Add a file to the current TAR archive using an existing file in the filesystem
|
||||
*
|
||||
* @param string $file path to the original file
|
||||
* @param string|FileInfo $fileinfo either the name to us in archive (string) or a FileInfo oject with all meta data, empty to take from original
|
||||
* @throws ArchiveCorruptedException when the file changes while reading it, the archive will be corrupt and should be deleted
|
||||
* @throws ArchiveIOException there was trouble reading the given file, it was not added
|
||||
* @throws FileInfoException trouble reading file info, it was not added
|
||||
*/
|
||||
public function addFile($file, $fileinfo = '')
|
||||
{
|
||||
if (\is_string($fileinfo)) {
|
||||
$fileinfo = FileInfo::fromPath($file, $fileinfo);
|
||||
}
|
||||
if ($this->closed) {
|
||||
throw new ArchiveIOException('Archive has been closed, files can no longer be added');
|
||||
}
|
||||
// create file header
|
||||
$this->writeFileHeader($fileinfo);
|
||||
// write data, but only if we have data to write.
|
||||
// note: on Windows fopen() on a directory will fail, so we prevent
|
||||
// errors on Windows by testing if we have data to write.
|
||||
if (!$fileinfo->getIsdir() && $fileinfo->getSize() > 0) {
|
||||
$read = 0;
|
||||
$fp = @\fopen($file, 'rb');
|
||||
if (!$fp) {
|
||||
throw new ArchiveIOException('Could not open file for reading: ' . $file);
|
||||
}
|
||||
while (!\feof($fp)) {
|
||||
$data = \fread($fp, 512);
|
||||
$read += \strlen($data);
|
||||
if ($data === \false) {
|
||||
break;
|
||||
}
|
||||
if ($data === '') {
|
||||
break;
|
||||
}
|
||||
$packed = \pack("a512", $data);
|
||||
$this->writebytes($packed);
|
||||
}
|
||||
\fclose($fp);
|
||||
if ($read != $fileinfo->getSize()) {
|
||||
$this->close();
|
||||
throw new ArchiveCorruptedException("The size of {$file} changed while reading, archive corrupted. read {$read} expected " . $fileinfo->getSize());
|
||||
}
|
||||
}
|
||||
if (\is_callable($this->callback)) {
|
||||
\call_user_func($this->callback, $fileinfo);
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Add a file to the current TAR archive using the given $data as content
|
||||
*
|
||||
* @param string|FileInfo $fileinfo either the name to us in archive (string) or a FileInfo oject with all meta data
|
||||
* @param string $data binary content of the file to add
|
||||
* @throws ArchiveIOException
|
||||
*/
|
||||
public function addData($fileinfo, $data)
|
||||
{
|
||||
if (\is_string($fileinfo)) {
|
||||
$fileinfo = new FileInfo($fileinfo);
|
||||
}
|
||||
if ($this->closed) {
|
||||
throw new ArchiveIOException('Archive has been closed, files can no longer be added');
|
||||
}
|
||||
$len = \strlen($data);
|
||||
$fileinfo->setSize($len);
|
||||
$this->writeFileHeader($fileinfo);
|
||||
for ($s = 0; $s < $len; $s += 512) {
|
||||
$this->writebytes(\pack("a512", \substr($data, $s, 512)));
|
||||
}
|
||||
if (\is_callable($this->callback)) {
|
||||
\call_user_func($this->callback, $fileinfo);
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Add the closing footer to the archive if in write mode, close all file handles
|
||||
*
|
||||
* After a call to this function no more data can be added to the archive, for
|
||||
* read access no reading is allowed anymore
|
||||
*
|
||||
* "Physically, an archive consists of a series of file entries terminated by an end-of-archive entry, which
|
||||
* consists of two 512 blocks of zero bytes"
|
||||
*
|
||||
* @link http://www.gnu.org/software/tar/manual/html_chapter/tar_8.html#SEC134
|
||||
* @throws ArchiveIOException
|
||||
*/
|
||||
public function close()
|
||||
{
|
||||
if ($this->closed) {
|
||||
return;
|
||||
}
|
||||
// we did this already
|
||||
// write footer
|
||||
if ($this->writeaccess) {
|
||||
$this->writebytes(\pack("a512", ""));
|
||||
$this->writebytes(\pack("a512", ""));
|
||||
}
|
||||
// close file handles
|
||||
if ($this->file) {
|
||||
if ($this->comptype === Archive::COMPRESS_GZIP) {
|
||||
\gzclose($this->fh);
|
||||
} elseif ($this->comptype === Archive::COMPRESS_BZIP) {
|
||||
\bzclose($this->fh);
|
||||
} else {
|
||||
\fclose($this->fh);
|
||||
}
|
||||
$this->file = '';
|
||||
$this->fh = 0;
|
||||
}
|
||||
$this->writeaccess = \false;
|
||||
$this->closed = \true;
|
||||
}
|
||||
/**
|
||||
* Returns the created in-memory archive data
|
||||
*
|
||||
* This implicitly calls close() on the Archive
|
||||
* @throws ArchiveIOException
|
||||
*/
|
||||
public function getArchive()
|
||||
{
|
||||
$this->close();
|
||||
if ($this->comptype === Archive::COMPRESS_AUTO) {
|
||||
$this->comptype = Archive::COMPRESS_NONE;
|
||||
}
|
||||
if ($this->comptype === Archive::COMPRESS_GZIP) {
|
||||
return \gzencode($this->memory, $this->complevel);
|
||||
}
|
||||
if ($this->comptype === Archive::COMPRESS_BZIP) {
|
||||
return \bzcompress($this->memory);
|
||||
}
|
||||
return $this->memory;
|
||||
}
|
||||
/**
|
||||
* Save the created in-memory archive data
|
||||
*
|
||||
* Note: It more memory effective to specify the filename in the create() function and
|
||||
* let the library work on the new file directly.
|
||||
*
|
||||
* @param string $file
|
||||
* @throws ArchiveIOException
|
||||
* @throws ArchiveIllegalCompressionException
|
||||
*/
|
||||
public function save($file)
|
||||
{
|
||||
if ($this->comptype === Archive::COMPRESS_AUTO) {
|
||||
$this->setCompression($this->complevel, $this->filetype($file));
|
||||
}
|
||||
if (!@\file_put_contents($file, $this->getArchive())) {
|
||||
throw new ArchiveIOException('Could not write to file: ' . $file);
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Read from the open file pointer
|
||||
*
|
||||
* @param int $length bytes to read
|
||||
* @return string
|
||||
*/
|
||||
protected function readbytes($length)
|
||||
{
|
||||
if ($this->comptype === Archive::COMPRESS_GZIP) {
|
||||
return @\gzread($this->fh, $length);
|
||||
} elseif ($this->comptype === Archive::COMPRESS_BZIP) {
|
||||
return @\bzread($this->fh, $length);
|
||||
} else {
|
||||
return @\fread($this->fh, $length);
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Write to the open filepointer or memory
|
||||
*
|
||||
* @param string $data
|
||||
* @throws ArchiveIOException
|
||||
* @return int number of bytes written
|
||||
*/
|
||||
protected function writebytes($data)
|
||||
{
|
||||
if (!$this->file) {
|
||||
$this->memory .= $data;
|
||||
$written = \strlen($data);
|
||||
} elseif ($this->comptype === Archive::COMPRESS_GZIP) {
|
||||
$written = @\gzwrite($this->fh, $data);
|
||||
} elseif ($this->comptype === Archive::COMPRESS_BZIP) {
|
||||
$written = @\bzwrite($this->fh, $data);
|
||||
} else {
|
||||
$written = @\fwrite($this->fh, $data);
|
||||
}
|
||||
if ($written === \false) {
|
||||
throw new ArchiveIOException('Failed to write to archive stream');
|
||||
}
|
||||
return $written;
|
||||
}
|
||||
/**
|
||||
* Skip forward in the open file pointer
|
||||
*
|
||||
* This is basically a wrapper around seek() (and a workaround for bzip2)
|
||||
*
|
||||
* @param int $bytes seek to this position
|
||||
*/
|
||||
protected function skipbytes($bytes)
|
||||
{
|
||||
if ($this->comptype === Archive::COMPRESS_GZIP) {
|
||||
@\gzseek($this->fh, $bytes, \SEEK_CUR);
|
||||
} elseif ($this->comptype === Archive::COMPRESS_BZIP) {
|
||||
// there is no seek in bzip2, we simply read on
|
||||
// bzread allows to read a max of 8kb at once
|
||||
while ($bytes) {
|
||||
$toread = \min(8192, $bytes);
|
||||
@\bzread($this->fh, $toread);
|
||||
$bytes -= $toread;
|
||||
}
|
||||
} else {
|
||||
@\fseek($this->fh, $bytes, \SEEK_CUR);
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Write the given file meta data as header
|
||||
*
|
||||
* @param FileInfo $fileinfo
|
||||
* @throws ArchiveIOException
|
||||
*/
|
||||
protected function writeFileHeader(FileInfo $fileinfo)
|
||||
{
|
||||
$this->writeRawFileHeader($fileinfo->getPath(), $fileinfo->getUid(), $fileinfo->getGid(), $fileinfo->getMode(), $fileinfo->getSize(), $fileinfo->getMtime(), $fileinfo->getIsdir() ? '5' : '0');
|
||||
}
|
||||
/**
|
||||
* Write a file header to the stream
|
||||
*
|
||||
* @param string $name
|
||||
* @param int $uid
|
||||
* @param int $gid
|
||||
* @param int $perm
|
||||
* @param int $size
|
||||
* @param int $mtime
|
||||
* @param string $typeflag Set to '5' for directories
|
||||
* @throws ArchiveIOException
|
||||
*/
|
||||
protected function writeRawFileHeader($name, $uid, $gid, $perm, $size, $mtime, $typeflag = '')
|
||||
{
|
||||
// handle filename length restrictions
|
||||
$prefix = '';
|
||||
$namelen = \strlen($name);
|
||||
if ($namelen > 100) {
|
||||
$file = \basename($name);
|
||||
$dir = \dirname($name);
|
||||
if (\strlen($file) > 100 || \strlen($dir) > 155) {
|
||||
// we're still too large, let's use GNU longlink
|
||||
$this->writeRawFileHeader('././@LongLink', 0, 0, 0, $namelen, 0, 'L');
|
||||
for ($s = 0; $s < $namelen; $s += 512) {
|
||||
$this->writebytes(\pack("a512", \substr($name, $s, 512)));
|
||||
}
|
||||
$name = \substr($name, 0, 100);
|
||||
// cut off name
|
||||
} else {
|
||||
// we're fine when splitting, use POSIX ustar
|
||||
$prefix = $dir;
|
||||
$name = $file;
|
||||
}
|
||||
}
|
||||
// values are needed in octal
|
||||
$uid = \sprintf("%6s ", \decoct($uid));
|
||||
$gid = \sprintf("%6s ", \decoct($gid));
|
||||
$perm = \sprintf("%6s ", \decoct($perm));
|
||||
$size = \sprintf("%11s ", \decoct($size));
|
||||
$mtime = \sprintf("%11s", \decoct($mtime));
|
||||
$data_first = \pack("a100a8a8a8a12A12", $name, $perm, $uid, $gid, $size, $mtime);
|
||||
$data_last = \pack("a1a100a6a2a32a32a8a8a155a12", $typeflag, '', 'ustar', '', '', '', '', '', $prefix, "");
|
||||
for ($i = 0, $chks = 0; $i < 148; $i++) {
|
||||
$chks += \ord($data_first[$i]);
|
||||
}
|
||||
for ($i = 156, $chks += 256, $j = 0; $i < 512; $i++, $j++) {
|
||||
$chks += \ord($data_last[$j]);
|
||||
}
|
||||
$this->writebytes($data_first);
|
||||
$chks = \pack("a8", \sprintf("%6s ", \decoct($chks)));
|
||||
$this->writebytes($chks . $data_last);
|
||||
}
|
||||
/**
|
||||
* Decode the given tar file header
|
||||
*
|
||||
* @param string $block a 512 byte block containing the header data
|
||||
* @return array|false returns false when this was a null block
|
||||
* @throws ArchiveCorruptedException
|
||||
*/
|
||||
protected function parseHeader($block)
|
||||
{
|
||||
if (!$block || \strlen($block) != 512) {
|
||||
throw new ArchiveCorruptedException('Unexpected length of header');
|
||||
}
|
||||
// null byte blocks are ignored
|
||||
if (\trim($block) === '') {
|
||||
return \false;
|
||||
}
|
||||
for ($i = 0, $chks = 0; $i < 148; $i++) {
|
||||
$chks += \ord($block[$i]);
|
||||
}
|
||||
for ($i = 156, $chks += 256; $i < 512; $i++) {
|
||||
$chks += \ord($block[$i]);
|
||||
}
|
||||
$header = @\unpack("a100filename/a8perm/a8uid/a8gid/a12size/a12mtime/a8checksum/a1typeflag/a100link/a6magic/a2version/a32uname/a32gname/a8devmajor/a8devminor/a155prefix", $block);
|
||||
if (!$header) {
|
||||
throw new ArchiveCorruptedException('Failed to parse header');
|
||||
}
|
||||
$return['checksum'] = \OctDec(\trim($header['checksum']));
|
||||
if ($return['checksum'] != $chks) {
|
||||
throw new ArchiveCorruptedException('Header does not match its checksum');
|
||||
}
|
||||
$return['filename'] = \trim($header['filename']);
|
||||
$return['perm'] = \OctDec(\trim($header['perm']));
|
||||
$return['uid'] = \OctDec(\trim($header['uid']));
|
||||
$return['gid'] = \OctDec(\trim($header['gid']));
|
||||
$return['size'] = \OctDec(\trim($header['size']));
|
||||
$return['mtime'] = \OctDec(\trim($header['mtime']));
|
||||
$return['typeflag'] = $header['typeflag'];
|
||||
$return['link'] = \trim($header['link']);
|
||||
$return['uname'] = \trim($header['uname']);
|
||||
$return['gname'] = \trim($header['gname']);
|
||||
// Handle ustar Posix compliant path prefixes
|
||||
if (\trim($header['prefix'])) {
|
||||
$return['filename'] = \trim($header['prefix']) . '/' . $return['filename'];
|
||||
}
|
||||
// Handle Long-Link entries from GNU Tar
|
||||
if ($return['typeflag'] == 'L') {
|
||||
// following data block(s) is the filename
|
||||
$filename = \trim($this->readbytes(\ceil($return['size'] / 512) * 512));
|
||||
// next block is the real header
|
||||
$block = $this->readbytes(512);
|
||||
$return = $this->parseHeader($block);
|
||||
// overwrite the filename
|
||||
$return['filename'] = $filename;
|
||||
}
|
||||
return $return;
|
||||
}
|
||||
/**
|
||||
* Creates a FileInfo object from the given parsed header
|
||||
*
|
||||
* @param $header
|
||||
* @return FileInfo
|
||||
*/
|
||||
protected function header2fileinfo($header)
|
||||
{
|
||||
$fileinfo = new FileInfo();
|
||||
$fileinfo->setPath($header['filename']);
|
||||
$fileinfo->setMode($header['perm']);
|
||||
$fileinfo->setUid($header['uid']);
|
||||
$fileinfo->setGid($header['gid']);
|
||||
$fileinfo->setSize($header['size']);
|
||||
$fileinfo->setMtime($header['mtime']);
|
||||
$fileinfo->setOwner($header['uname']);
|
||||
$fileinfo->setGroup($header['gname']);
|
||||
$fileinfo->setIsdir((bool) $header['typeflag']);
|
||||
return $fileinfo;
|
||||
}
|
||||
/**
|
||||
* Checks if the given compression type is available and throws an exception if not
|
||||
*
|
||||
* @param $comptype
|
||||
* @throws ArchiveIllegalCompressionException
|
||||
*/
|
||||
protected function compressioncheck($comptype)
|
||||
{
|
||||
if ($comptype === Archive::COMPRESS_GZIP && !\function_exists('gzopen')) {
|
||||
throw new ArchiveIllegalCompressionException('No gzip support available');
|
||||
}
|
||||
if ($comptype === Archive::COMPRESS_BZIP && !\function_exists('bzopen')) {
|
||||
throw new ArchiveIllegalCompressionException('No bzip2 support available');
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Guesses the wanted compression from the given file
|
||||
*
|
||||
* Uses magic bytes for existing files, the file extension otherwise
|
||||
*
|
||||
* You don't need to call this yourself. It's used when you pass Archive::COMPRESS_AUTO somewhere
|
||||
*
|
||||
* @param string $file
|
||||
* @return int
|
||||
*/
|
||||
public function filetype($file)
|
||||
{
|
||||
// for existing files, try to read the magic bytes
|
||||
if (\file_exists($file) && \is_readable($file) && \filesize($file) > 5) {
|
||||
$fh = @\fopen($file, 'rb');
|
||||
if (!$fh) {
|
||||
return \false;
|
||||
}
|
||||
$magic = \fread($fh, 5);
|
||||
\fclose($fh);
|
||||
if (\strpos($magic, "BZ") === 0) {
|
||||
return Archive::COMPRESS_BZIP;
|
||||
}
|
||||
if (\strpos($magic, "\x1f\x8b") === 0) {
|
||||
return Archive::COMPRESS_GZIP;
|
||||
}
|
||||
}
|
||||
// otherwise rely on file name
|
||||
$file = \strtolower($file);
|
||||
if (\substr($file, -3) == '.gz' || \substr($file, -4) == '.tgz') {
|
||||
return Archive::COMPRESS_GZIP;
|
||||
} elseif (\substr($file, -4) == '.bz2' || \substr($file, -4) == '.tbz') {
|
||||
return Archive::COMPRESS_BZIP;
|
||||
}
|
||||
return Archive::COMPRESS_NONE;
|
||||
}
|
||||
}
|
||||
898
plugins/system/tgeoip/vendor/splitbrain/php-archive/src/Zip.php
vendored
Normal file
898
plugins/system/tgeoip/vendor/splitbrain/php-archive/src/Zip.php
vendored
Normal file
@ -0,0 +1,898 @@
|
||||
<?php
|
||||
|
||||
namespace Tassos\Vendor\splitbrain\PHPArchive;
|
||||
|
||||
/**
|
||||
* Class Zip
|
||||
*
|
||||
* Creates or extracts Zip archives
|
||||
*
|
||||
* for specs see http://www.pkware.com/appnote
|
||||
*
|
||||
* @author Andreas Gohr <andi@splitbrain.org>
|
||||
* @package splitbrain\PHPArchive
|
||||
* @license MIT
|
||||
*/
|
||||
class Zip extends Archive
|
||||
{
|
||||
const LOCAL_FILE_HEADER_CRC_OFFSET = 14;
|
||||
protected $file = '';
|
||||
protected $fh;
|
||||
protected $memory = '';
|
||||
protected $closed = \true;
|
||||
protected $writeaccess = \false;
|
||||
protected $ctrl_dir;
|
||||
protected $complevel = 9;
|
||||
/**
|
||||
* Set the compression level.
|
||||
*
|
||||
* Compression Type is ignored for ZIP
|
||||
*
|
||||
* You can call this function before adding each file to set differen compression levels
|
||||
* for each file.
|
||||
*
|
||||
* @param int $level Compression level (0 to 9)
|
||||
* @param int $type Type of compression to use ignored for ZIP
|
||||
* @throws ArchiveIllegalCompressionException
|
||||
*/
|
||||
public function setCompression($level = 9, $type = Archive::COMPRESS_AUTO)
|
||||
{
|
||||
if ($level < -1 || $level > 9) {
|
||||
throw new ArchiveIllegalCompressionException('Compression level should be between -1 and 9');
|
||||
}
|
||||
$this->complevel = $level;
|
||||
}
|
||||
/**
|
||||
* Open an existing ZIP file for reading
|
||||
*
|
||||
* @param string $file
|
||||
* @throws ArchiveIOException
|
||||
*/
|
||||
public function open($file)
|
||||
{
|
||||
$this->file = $file;
|
||||
$this->fh = @\fopen($this->file, 'rb');
|
||||
if (!$this->fh) {
|
||||
throw new ArchiveIOException('Could not open file for reading: ' . $this->file);
|
||||
}
|
||||
$this->closed = \false;
|
||||
}
|
||||
/**
|
||||
* Read the contents of a ZIP archive
|
||||
*
|
||||
* This function lists the files stored in the archive, and returns an indexed array of FileInfo objects
|
||||
*
|
||||
* The archive is closed afer reading the contents, for API compatibility with TAR files
|
||||
* Reopen the file with open() again if you want to do additional operations
|
||||
*
|
||||
* @throws ArchiveIOException
|
||||
* @return FileInfo[]
|
||||
*/
|
||||
public function contents()
|
||||
{
|
||||
$result = array();
|
||||
foreach ($this->yieldContents() as $fileinfo) {
|
||||
$result[] = $fileinfo;
|
||||
}
|
||||
return $result;
|
||||
}
|
||||
/**
|
||||
* Read the contents of a ZIP archive and return each entry using yield
|
||||
* for memory efficiency.
|
||||
*
|
||||
* @see contents()
|
||||
* @throws ArchiveIOException
|
||||
* @return FileInfo[]
|
||||
*/
|
||||
public function yieldContents()
|
||||
{
|
||||
if ($this->closed || !$this->file) {
|
||||
throw new ArchiveIOException('Can not read from a closed archive');
|
||||
}
|
||||
$centd = $this->readCentralDir();
|
||||
@\rewind($this->fh);
|
||||
@\fseek($this->fh, $centd['offset']);
|
||||
for ($i = 0; $i < $centd['entries']; $i++) {
|
||||
(yield $this->header2fileinfo($this->readCentralFileHeader()));
|
||||
}
|
||||
$this->close();
|
||||
}
|
||||
/**
|
||||
* Extract an existing ZIP archive
|
||||
*
|
||||
* The $strip parameter allows you to strip a certain number of path components from the filenames
|
||||
* found in the tar file, similar to the --strip-components feature of GNU tar. This is triggered when
|
||||
* an integer is passed as $strip.
|
||||
* Alternatively a fixed string prefix may be passed in $strip. If the filename matches this prefix,
|
||||
* the prefix will be stripped. It is recommended to give prefixes with a trailing slash.
|
||||
*
|
||||
* By default this will extract all files found in the archive. You can restrict the output using the $include
|
||||
* and $exclude parameter. Both expect a full regular expression (including delimiters and modifiers). If
|
||||
* $include is set only files that match this expression will be extracted. Files that match the $exclude
|
||||
* expression will never be extracted. Both parameters can be used in combination. Expressions are matched against
|
||||
* stripped filenames as described above.
|
||||
*
|
||||
* @param string $outdir the target directory for extracting
|
||||
* @param int|string $strip either the number of path components or a fixed prefix to strip
|
||||
* @param string $exclude a regular expression of files to exclude
|
||||
* @param string $include a regular expression of files to include
|
||||
* @throws ArchiveIOException
|
||||
* @return FileInfo[]
|
||||
*/
|
||||
public function extract($outdir, $strip = '', $exclude = '', $include = '')
|
||||
{
|
||||
if ($this->closed || !$this->file) {
|
||||
throw new ArchiveIOException('Can not read from a closed archive');
|
||||
}
|
||||
$outdir = \rtrim($outdir, '/');
|
||||
@\mkdir($outdir, 0777, \true);
|
||||
$extracted = array();
|
||||
$cdir = $this->readCentralDir();
|
||||
$pos_entry = $cdir['offset'];
|
||||
// begin of the central file directory
|
||||
for ($i = 0; $i < $cdir['entries']; $i++) {
|
||||
// read file header
|
||||
@\fseek($this->fh, $pos_entry);
|
||||
$header = $this->readCentralFileHeader();
|
||||
$header['index'] = $i;
|
||||
$pos_entry = \ftell($this->fh);
|
||||
// position of the next file in central file directory
|
||||
\fseek($this->fh, $header['offset']);
|
||||
// seek to beginning of file header
|
||||
$header = $this->readFileHeader($header);
|
||||
$fileinfo = $this->header2fileinfo($header);
|
||||
// apply strip rules
|
||||
$fileinfo->strip($strip);
|
||||
// skip unwanted files
|
||||
if (!\strlen($fileinfo->getPath()) || !$fileinfo->matchExpression($include, $exclude)) {
|
||||
continue;
|
||||
}
|
||||
$extracted[] = $fileinfo;
|
||||
// create output directory
|
||||
$output = $outdir . '/' . $fileinfo->getPath();
|
||||
$directory = $header['folder'] ? $output : \dirname($output);
|
||||
@\mkdir($directory, 0777, \true);
|
||||
// nothing more to do for directories
|
||||
if ($fileinfo->getIsdir()) {
|
||||
if (\is_callable($this->callback)) {
|
||||
\call_user_func($this->callback, $fileinfo);
|
||||
}
|
||||
continue;
|
||||
}
|
||||
// compressed files are written to temporary .gz file first
|
||||
if ($header['compression'] == 0) {
|
||||
$extractto = $output;
|
||||
} else {
|
||||
$extractto = $output . '.gz';
|
||||
}
|
||||
// open file for writing
|
||||
$fp = @\fopen($extractto, "wb");
|
||||
if (!$fp) {
|
||||
throw new ArchiveIOException('Could not open file for writing: ' . $extractto);
|
||||
}
|
||||
// prepend compression header
|
||||
if ($header['compression'] != 0) {
|
||||
$binary_data = \pack('va1a1Va1a1', 0x8b1f, \chr($header['compression']), \chr(0x0), \time(), \chr(0x0), \chr(3));
|
||||
\fwrite($fp, $binary_data, 10);
|
||||
}
|
||||
// read the file and store it on disk
|
||||
$size = $header['compressed_size'];
|
||||
while ($size != 0) {
|
||||
$read_size = $size < 2048 ? $size : 2048;
|
||||
$buffer = \fread($this->fh, $read_size);
|
||||
$binary_data = \pack('a' . $read_size, $buffer);
|
||||
\fwrite($fp, $binary_data, $read_size);
|
||||
$size -= $read_size;
|
||||
}
|
||||
// finalize compressed file
|
||||
if ($header['compression'] != 0) {
|
||||
$binary_data = \pack('VV', $header['crc'], $header['size']);
|
||||
\fwrite($fp, $binary_data, 8);
|
||||
}
|
||||
// close file
|
||||
\fclose($fp);
|
||||
// unpack compressed file
|
||||
if ($header['compression'] != 0) {
|
||||
$gzp = @\gzopen($extractto, 'rb');
|
||||
if (!$gzp) {
|
||||
@\unlink($extractto);
|
||||
throw new ArchiveIOException('Failed file extracting. gzip support missing?');
|
||||
}
|
||||
$fp = @\fopen($output, 'wb');
|
||||
if (!$fp) {
|
||||
throw new ArchiveIOException('Could not open file for writing: ' . $extractto);
|
||||
}
|
||||
$size = $header['size'];
|
||||
while ($size != 0) {
|
||||
$read_size = $size < 2048 ? $size : 2048;
|
||||
$buffer = \gzread($gzp, $read_size);
|
||||
$binary_data = \pack('a' . $read_size, $buffer);
|
||||
@\fwrite($fp, $binary_data, $read_size);
|
||||
$size -= $read_size;
|
||||
}
|
||||
\fclose($fp);
|
||||
\gzclose($gzp);
|
||||
\unlink($extractto);
|
||||
// remove temporary gz file
|
||||
}
|
||||
@\touch($output, $fileinfo->getMtime());
|
||||
//FIXME what about permissions?
|
||||
if (\is_callable($this->callback)) {
|
||||
\call_user_func($this->callback, $fileinfo);
|
||||
}
|
||||
}
|
||||
$this->close();
|
||||
return $extracted;
|
||||
}
|
||||
/**
|
||||
* Create a new ZIP file
|
||||
*
|
||||
* If $file is empty, the zip file will be created in memory
|
||||
*
|
||||
* @param string $file
|
||||
* @throws ArchiveIOException
|
||||
*/
|
||||
public function create($file = '')
|
||||
{
|
||||
$this->file = $file;
|
||||
$this->memory = '';
|
||||
$this->fh = 0;
|
||||
if ($this->file) {
|
||||
$this->fh = @\fopen($this->file, 'wb');
|
||||
if (!$this->fh) {
|
||||
throw new ArchiveIOException('Could not open file for writing: ' . $this->file);
|
||||
}
|
||||
}
|
||||
$this->writeaccess = \true;
|
||||
$this->closed = \false;
|
||||
$this->ctrl_dir = array();
|
||||
}
|
||||
/**
|
||||
* Add a file to the current ZIP archive using an existing file in the filesystem
|
||||
*
|
||||
* @param string $file path to the original file
|
||||
* @param string|FileInfo $fileinfo either the name to us in archive (string) or a FileInfo oject with all meta data, empty to take from original
|
||||
* @throws ArchiveIOException
|
||||
*/
|
||||
/**
|
||||
* Add a file to the current archive using an existing file in the filesystem
|
||||
*
|
||||
* @param string $file path to the original file
|
||||
* @param string|FileInfo $fileinfo either the name to use in archive (string) or a FileInfo oject with all meta data, empty to take from original
|
||||
* @throws ArchiveIOException
|
||||
* @throws FileInfoException
|
||||
*/
|
||||
public function addFile($file, $fileinfo = '')
|
||||
{
|
||||
if (\is_string($fileinfo)) {
|
||||
$fileinfo = FileInfo::fromPath($file, $fileinfo);
|
||||
}
|
||||
if ($this->closed) {
|
||||
throw new ArchiveIOException('Archive has been closed, files can no longer be added');
|
||||
}
|
||||
$fp = @\fopen($file, 'rb');
|
||||
if ($fp === \false) {
|
||||
throw new ArchiveIOException('Could not open file for reading: ' . $file);
|
||||
}
|
||||
$offset = $this->dataOffset();
|
||||
$name = $fileinfo->getPath();
|
||||
$time = $fileinfo->getMtime();
|
||||
// write local file header (temporary CRC and size)
|
||||
$this->writebytes($this->makeLocalFileHeader($time, 0, 0, 0, $name, (bool) $this->complevel));
|
||||
// we store no encryption header
|
||||
// prepare info, compress and write data to archive
|
||||
$deflate_context = \deflate_init(\ZLIB_ENCODING_DEFLATE, ['level' => $this->complevel]);
|
||||
$crc_context = \hash_init('crc32b');
|
||||
$size = $csize = 0;
|
||||
while (!\feof($fp)) {
|
||||
$block = \fread($fp, 512);
|
||||
if ($this->complevel) {
|
||||
$is_first_block = $size === 0;
|
||||
$is_last_block = \feof($fp);
|
||||
if ($is_last_block) {
|
||||
$c_block = \deflate_add($deflate_context, $block, \ZLIB_FINISH);
|
||||
// get rid of the compression footer
|
||||
$c_block = \substr($c_block, 0, -4);
|
||||
} else {
|
||||
$c_block = \deflate_add($deflate_context, $block, \ZLIB_NO_FLUSH);
|
||||
}
|
||||
// get rid of the compression header
|
||||
if ($is_first_block) {
|
||||
$c_block = \substr($c_block, 2);
|
||||
}
|
||||
$csize += \strlen($c_block);
|
||||
$this->writebytes($c_block);
|
||||
} else {
|
||||
$this->writebytes($block);
|
||||
}
|
||||
$size += \strlen($block);
|
||||
\hash_update($crc_context, $block);
|
||||
}
|
||||
\fclose($fp);
|
||||
// update the local file header with the computed CRC and size
|
||||
$crc = \hexdec(\hash_final($crc_context));
|
||||
$csize = $this->complevel ? $csize : $size;
|
||||
$this->writebytesAt($this->makeCrcAndSize($crc, $size, $csize), $offset + self::LOCAL_FILE_HEADER_CRC_OFFSET);
|
||||
// we store no data descriptor
|
||||
// add info to central file directory
|
||||
$this->ctrl_dir[] = $this->makeCentralFileRecord($offset, $time, $crc, $size, $csize, $name, (bool) $this->complevel);
|
||||
if (\is_callable($this->callback)) {
|
||||
\call_user_func($this->callback, $fileinfo);
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Add a file to the current Zip archive using the given $data as content
|
||||
*
|
||||
* @param string|FileInfo $fileinfo either the name to us in archive (string) or a FileInfo oject with all meta data
|
||||
* @param string $data binary content of the file to add
|
||||
* @throws ArchiveIOException
|
||||
*/
|
||||
public function addData($fileinfo, $data)
|
||||
{
|
||||
if (\is_string($fileinfo)) {
|
||||
$fileinfo = new FileInfo($fileinfo);
|
||||
}
|
||||
if ($this->closed) {
|
||||
throw new ArchiveIOException('Archive has been closed, files can no longer be added');
|
||||
}
|
||||
// prepare info and compress data
|
||||
$size = \strlen($data);
|
||||
$crc = \crc32($data);
|
||||
if ($this->complevel) {
|
||||
$data = \gzcompress($data, $this->complevel);
|
||||
$data = \substr($data, 2, -4);
|
||||
// strip compression headers
|
||||
}
|
||||
$csize = \strlen($data);
|
||||
$offset = $this->dataOffset();
|
||||
$name = $fileinfo->getPath();
|
||||
$time = $fileinfo->getMtime();
|
||||
// write local file header
|
||||
$this->writebytes($this->makeLocalFileHeader($time, $crc, $size, $csize, $name, (bool) $this->complevel));
|
||||
// we store no encryption header
|
||||
// write data
|
||||
$this->writebytes($data);
|
||||
// we store no data descriptor
|
||||
// add info to central file directory
|
||||
$this->ctrl_dir[] = $this->makeCentralFileRecord($offset, $time, $crc, $size, $csize, $name, (bool) $this->complevel);
|
||||
if (\is_callable($this->callback)) {
|
||||
\call_user_func($this->callback, $fileinfo);
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Add the closing footer to the archive if in write mode, close all file handles
|
||||
*
|
||||
* After a call to this function no more data can be added to the archive, for
|
||||
* read access no reading is allowed anymore
|
||||
* @throws ArchiveIOException
|
||||
*/
|
||||
public function close()
|
||||
{
|
||||
if ($this->closed) {
|
||||
return;
|
||||
}
|
||||
// we did this already
|
||||
if ($this->writeaccess) {
|
||||
// write central directory
|
||||
$offset = $this->dataOffset();
|
||||
$ctrldir = \join('', $this->ctrl_dir);
|
||||
$this->writebytes($ctrldir);
|
||||
// write end of central directory record
|
||||
$this->writebytes("PK\x05\x06");
|
||||
// end of central dir signature
|
||||
$this->writebytes(\pack('v', 0));
|
||||
// number of this disk
|
||||
$this->writebytes(\pack('v', 0));
|
||||
// number of the disk with the start of the central directory
|
||||
$this->writebytes(\pack('v', \count($this->ctrl_dir)));
|
||||
// total number of entries in the central directory on this disk
|
||||
$this->writebytes(\pack('v', \count($this->ctrl_dir)));
|
||||
// total number of entries in the central directory
|
||||
$this->writebytes(\pack('V', \strlen($ctrldir)));
|
||||
// size of the central directory
|
||||
$this->writebytes(\pack('V', $offset));
|
||||
// offset of start of central directory with respect to the starting disk number
|
||||
$this->writebytes(\pack('v', 0));
|
||||
// .ZIP file comment length
|
||||
$this->ctrl_dir = array();
|
||||
}
|
||||
// close file handles
|
||||
if ($this->file) {
|
||||
\fclose($this->fh);
|
||||
$this->file = '';
|
||||
$this->fh = 0;
|
||||
}
|
||||
$this->writeaccess = \false;
|
||||
$this->closed = \true;
|
||||
}
|
||||
/**
|
||||
* Returns the created in-memory archive data
|
||||
*
|
||||
* This implicitly calls close() on the Archive
|
||||
* @throws ArchiveIOException
|
||||
*/
|
||||
public function getArchive()
|
||||
{
|
||||
$this->close();
|
||||
return $this->memory;
|
||||
}
|
||||
/**
|
||||
* Save the created in-memory archive data
|
||||
*
|
||||
* Note: It's more memory effective to specify the filename in the create() function and
|
||||
* let the library work on the new file directly.
|
||||
*
|
||||
* @param $file
|
||||
* @throws ArchiveIOException
|
||||
*/
|
||||
public function save($file)
|
||||
{
|
||||
if (!@\file_put_contents($file, $this->getArchive())) {
|
||||
throw new ArchiveIOException('Could not write to file: ' . $file);
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Read the central directory
|
||||
*
|
||||
* This key-value list contains general information about the ZIP file
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
protected function readCentralDir()
|
||||
{
|
||||
$size = \filesize($this->file);
|
||||
if ($size < 277) {
|
||||
$maximum_size = $size;
|
||||
} else {
|
||||
$maximum_size = 277;
|
||||
}
|
||||
@\fseek($this->fh, $size - $maximum_size);
|
||||
$pos = \ftell($this->fh);
|
||||
$bytes = 0x0;
|
||||
while ($pos < $size) {
|
||||
$byte = @\fread($this->fh, 1);
|
||||
$bytes = $bytes << 8 & 0xffffffff | \ord($byte);
|
||||
if ($bytes == 0x504b0506) {
|
||||
break;
|
||||
}
|
||||
$pos++;
|
||||
}
|
||||
$data = \unpack('vdisk/vdisk_start/vdisk_entries/ventries/Vsize/Voffset/vcomment_size', \fread($this->fh, 18));
|
||||
if ($data['comment_size'] != 0) {
|
||||
$centd['comment'] = \fread($this->fh, $data['comment_size']);
|
||||
} else {
|
||||
$centd['comment'] = '';
|
||||
}
|
||||
$centd['entries'] = $data['entries'];
|
||||
$centd['disk_entries'] = $data['disk_entries'];
|
||||
$centd['offset'] = $data['offset'];
|
||||
$centd['disk_start'] = $data['disk_start'];
|
||||
$centd['size'] = $data['size'];
|
||||
$centd['disk'] = $data['disk'];
|
||||
return $centd;
|
||||
}
|
||||
/**
|
||||
* Read the next central file header
|
||||
*
|
||||
* Assumes the current file pointer is pointing at the right position
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
protected function readCentralFileHeader()
|
||||
{
|
||||
$binary_data = \fread($this->fh, 46);
|
||||
$header = \unpack('vchkid/vid/vversion/vversion_extracted/vflag/vcompression/vmtime/vmdate/Vcrc/Vcompressed_size/Vsize/vfilename_len/vextra_len/vcomment_len/vdisk/vinternal/Vexternal/Voffset', $binary_data);
|
||||
if ($header['filename_len'] != 0) {
|
||||
$header['filename'] = \fread($this->fh, $header['filename_len']);
|
||||
} else {
|
||||
$header['filename'] = '';
|
||||
}
|
||||
if ($header['extra_len'] != 0) {
|
||||
$header['extra'] = \fread($this->fh, $header['extra_len']);
|
||||
$header['extradata'] = $this->parseExtra($header['extra']);
|
||||
} else {
|
||||
$header['extra'] = '';
|
||||
$header['extradata'] = array();
|
||||
}
|
||||
if ($header['comment_len'] != 0) {
|
||||
$header['comment'] = \fread($this->fh, $header['comment_len']);
|
||||
} else {
|
||||
$header['comment'] = '';
|
||||
}
|
||||
$header['mtime'] = $this->makeUnixTime($header['mdate'], $header['mtime']);
|
||||
$header['stored_filename'] = $header['filename'];
|
||||
$header['status'] = 'ok';
|
||||
if (\substr($header['filename'], -1) == '/') {
|
||||
$header['external'] = 0x41ff0010;
|
||||
}
|
||||
$header['folder'] = $header['external'] == 0x41ff0010 || $header['external'] == 16 ? 1 : 0;
|
||||
return $header;
|
||||
}
|
||||
/**
|
||||
* Reads the local file header
|
||||
*
|
||||
* This header precedes each individual file inside the zip file. Assumes the current file pointer is pointing at
|
||||
* the right position already. Enhances the given central header with the data found at the local header.
|
||||
*
|
||||
* @param array $header the central file header read previously (see above)
|
||||
* @return array
|
||||
*/
|
||||
protected function readFileHeader($header)
|
||||
{
|
||||
$binary_data = \fread($this->fh, 30);
|
||||
$data = \unpack('vchk/vid/vversion/vflag/vcompression/vmtime/vmdate/Vcrc/Vcompressed_size/Vsize/vfilename_len/vextra_len', $binary_data);
|
||||
$header['filename'] = \fread($this->fh, $data['filename_len']);
|
||||
if ($data['extra_len'] != 0) {
|
||||
$header['extra'] = \fread($this->fh, $data['extra_len']);
|
||||
$header['extradata'] = \array_merge($header['extradata'], $this->parseExtra($header['extra']));
|
||||
} else {
|
||||
$header['extra'] = '';
|
||||
$header['extradata'] = array();
|
||||
}
|
||||
$header['compression'] = $data['compression'];
|
||||
foreach (array('size', 'compressed_size', 'crc') as $hd) {
|
||||
// On ODT files, these headers are 0. Keep the previous value.
|
||||
if ($data[$hd] != 0) {
|
||||
$header[$hd] = $data[$hd];
|
||||
}
|
||||
}
|
||||
$header['flag'] = $data['flag'];
|
||||
$header['mtime'] = $this->makeUnixTime($data['mdate'], $data['mtime']);
|
||||
$header['stored_filename'] = $header['filename'];
|
||||
$header['status'] = "ok";
|
||||
$header['folder'] = $header['external'] == 0x41ff0010 || $header['external'] == 16 ? 1 : 0;
|
||||
return $header;
|
||||
}
|
||||
/**
|
||||
* Parse the extra headers into fields
|
||||
*
|
||||
* @param string $header
|
||||
* @return array
|
||||
*/
|
||||
protected function parseExtra($header)
|
||||
{
|
||||
$extra = array();
|
||||
// parse all extra fields as raw values
|
||||
while (\strlen($header) !== 0) {
|
||||
$set = \unpack('vid/vlen', $header);
|
||||
$header = \substr($header, 4);
|
||||
$value = \substr($header, 0, $set['len']);
|
||||
$header = \substr($header, $set['len']);
|
||||
$extra[$set['id']] = $value;
|
||||
}
|
||||
// handle known ones
|
||||
if (isset($extra[0x6375])) {
|
||||
$extra['utf8comment'] = \substr($extra[0x7075], 5);
|
||||
// strip version and crc
|
||||
}
|
||||
if (isset($extra[0x7075])) {
|
||||
$extra['utf8path'] = \substr($extra[0x7075], 5);
|
||||
// strip version and crc
|
||||
}
|
||||
return $extra;
|
||||
}
|
||||
/**
|
||||
* Create fileinfo object from header data
|
||||
*
|
||||
* @param $header
|
||||
* @return FileInfo
|
||||
*/
|
||||
protected function header2fileinfo($header)
|
||||
{
|
||||
$fileinfo = new FileInfo();
|
||||
$fileinfo->setSize($header['size']);
|
||||
$fileinfo->setCompressedSize($header['compressed_size']);
|
||||
$fileinfo->setMtime($header['mtime']);
|
||||
$fileinfo->setComment($header['comment']);
|
||||
$fileinfo->setIsdir($header['external'] == 0x41ff0010 || $header['external'] == 16);
|
||||
if (isset($header['extradata']['utf8path'])) {
|
||||
$fileinfo->setPath($header['extradata']['utf8path']);
|
||||
} else {
|
||||
$fileinfo->setPath($this->cpToUtf8($header['filename']));
|
||||
}
|
||||
if (isset($header['extradata']['utf8comment'])) {
|
||||
$fileinfo->setComment($header['extradata']['utf8comment']);
|
||||
} else {
|
||||
$fileinfo->setComment($this->cpToUtf8($header['comment']));
|
||||
}
|
||||
return $fileinfo;
|
||||
}
|
||||
/**
|
||||
* Convert the given CP437 encoded string to UTF-8
|
||||
*
|
||||
* Tries iconv with the correct encoding first, falls back to mbstring with CP850 which is
|
||||
* similar enough. CP437 seems not to be available in mbstring. Lastly falls back to keeping the
|
||||
* string as is, which is still better than nothing.
|
||||
*
|
||||
* On some systems iconv is available, but the codepage is not. We also check for that.
|
||||
*
|
||||
* @param $string
|
||||
* @return string
|
||||
*/
|
||||
protected function cpToUtf8($string)
|
||||
{
|
||||
if (\function_exists('iconv') && @\iconv_strlen('', 'CP437') !== \false) {
|
||||
return \iconv('CP437', 'UTF-8', $string);
|
||||
} elseif (\function_exists('mb_convert_encoding')) {
|
||||
return \mb_convert_encoding($string, 'UTF-8', 'CP850');
|
||||
} else {
|
||||
return $string;
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Convert the given UTF-8 encoded string to CP437
|
||||
*
|
||||
* Same caveats as for cpToUtf8() apply
|
||||
*
|
||||
* @param $string
|
||||
* @return string
|
||||
*/
|
||||
protected function utf8ToCp($string)
|
||||
{
|
||||
// try iconv first
|
||||
if (\function_exists('iconv')) {
|
||||
$conv = @\iconv('UTF-8', 'CP437//IGNORE', $string);
|
||||
if ($conv) {
|
||||
return $conv;
|
||||
}
|
||||
// it worked
|
||||
}
|
||||
// still here? iconv failed to convert the string. Try another method
|
||||
// see http://php.net/manual/en/function.iconv.php#108643
|
||||
if (\function_exists('mb_convert_encoding')) {
|
||||
return \mb_convert_encoding($string, 'CP850', 'UTF-8');
|
||||
} else {
|
||||
return $string;
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Write to the open filepointer or memory
|
||||
*
|
||||
* @param string $data
|
||||
* @throws ArchiveIOException
|
||||
* @return int number of bytes written
|
||||
*/
|
||||
protected function writebytes($data)
|
||||
{
|
||||
if (!$this->file) {
|
||||
$this->memory .= $data;
|
||||
$written = \strlen($data);
|
||||
} else {
|
||||
$written = @\fwrite($this->fh, $data);
|
||||
}
|
||||
if ($written === \false) {
|
||||
throw new ArchiveIOException('Failed to write to archive stream');
|
||||
}
|
||||
return $written;
|
||||
}
|
||||
/**
|
||||
* Write to the open filepointer or memory at the specified offset
|
||||
*
|
||||
* @param string $data
|
||||
* @param int $offset
|
||||
* @throws ArchiveIOException
|
||||
* @return int number of bytes written
|
||||
*/
|
||||
protected function writebytesAt($data, $offset)
|
||||
{
|
||||
if (!$this->file) {
|
||||
$this->memory .= \substr_replace($this->memory, $data, $offset);
|
||||
$written = \strlen($data);
|
||||
} else {
|
||||
@\fseek($this->fh, $offset);
|
||||
$written = @\fwrite($this->fh, $data);
|
||||
@\fseek($this->fh, 0, \SEEK_END);
|
||||
}
|
||||
if ($written === \false) {
|
||||
throw new ArchiveIOException('Failed to write to archive stream');
|
||||
}
|
||||
return $written;
|
||||
}
|
||||
/**
|
||||
* Current data pointer position
|
||||
*
|
||||
* @fixme might need a -1
|
||||
* @return int
|
||||
*/
|
||||
protected function dataOffset()
|
||||
{
|
||||
if ($this->file) {
|
||||
return \ftell($this->fh);
|
||||
} else {
|
||||
return \strlen($this->memory);
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Create a DOS timestamp from a UNIX timestamp
|
||||
*
|
||||
* DOS timestamps start at 1980-01-01, earlier UNIX stamps will be set to this date
|
||||
*
|
||||
* @param $time
|
||||
* @return int
|
||||
*/
|
||||
protected function makeDosTime($time)
|
||||
{
|
||||
$timearray = \getdate($time);
|
||||
if ($timearray['year'] < 1980) {
|
||||
$timearray['year'] = 1980;
|
||||
$timearray['mon'] = 1;
|
||||
$timearray['mday'] = 1;
|
||||
$timearray['hours'] = 0;
|
||||
$timearray['minutes'] = 0;
|
||||
$timearray['seconds'] = 0;
|
||||
}
|
||||
return $timearray['year'] - 1980 << 25 | $timearray['mon'] << 21 | $timearray['mday'] << 16 | $timearray['hours'] << 11 | $timearray['minutes'] << 5 | $timearray['seconds'] >> 1;
|
||||
}
|
||||
/**
|
||||
* Create a UNIX timestamp from a DOS timestamp
|
||||
*
|
||||
* @param $mdate
|
||||
* @param $mtime
|
||||
* @return int
|
||||
*/
|
||||
protected function makeUnixTime($mdate = null, $mtime = null)
|
||||
{
|
||||
if ($mdate && $mtime) {
|
||||
$year = (($mdate & 0xfe00) >> 9) + 1980;
|
||||
$month = ($mdate & 0x1e0) >> 5;
|
||||
$day = $mdate & 0x1f;
|
||||
$hour = ($mtime & 0xf800) >> 11;
|
||||
$minute = ($mtime & 0x7e0) >> 5;
|
||||
$seconde = ($mtime & 0x1f) << 1;
|
||||
$mtime = \mktime($hour, $minute, $seconde, $month, $day, $year);
|
||||
} else {
|
||||
$mtime = \time();
|
||||
}
|
||||
return $mtime;
|
||||
}
|
||||
/**
|
||||
* Returns a local file header for the given data
|
||||
*
|
||||
* @param int $offset location of the local header
|
||||
* @param int $ts unix timestamp
|
||||
* @param int $crc CRC32 checksum of the uncompressed data
|
||||
* @param int $len length of the uncompressed data
|
||||
* @param int $clen length of the compressed data
|
||||
* @param string $name file name
|
||||
* @param boolean|null $comp if compression is used, if null it's determined from $len != $clen
|
||||
* @return string
|
||||
*/
|
||||
protected function makeCentralFileRecord($offset, $ts, $crc, $len, $clen, $name, $comp = null)
|
||||
{
|
||||
if (\is_null($comp)) {
|
||||
$comp = $len != $clen;
|
||||
}
|
||||
$comp = $comp ? 8 : 0;
|
||||
$dtime = \dechex($this->makeDosTime($ts));
|
||||
list($name, $extra) = $this->encodeFilename($name);
|
||||
$header = "PK\x01\x02";
|
||||
// central file header signature
|
||||
$header .= \pack('v', 14);
|
||||
// version made by - VFAT
|
||||
$header .= \pack('v', 20);
|
||||
// version needed to extract - 2.0
|
||||
$header .= \pack('v', 0);
|
||||
// general purpose flag - no flags set
|
||||
$header .= \pack('v', $comp);
|
||||
// compression method - deflate|none
|
||||
$header .= \pack('H*', $dtime[6] . $dtime[7] . $dtime[4] . $dtime[5] . $dtime[2] . $dtime[3] . $dtime[0] . $dtime[1]);
|
||||
// last mod file time and date
|
||||
$header .= \pack('V', $crc);
|
||||
// crc-32
|
||||
$header .= \pack('V', $clen);
|
||||
// compressed size
|
||||
$header .= \pack('V', $len);
|
||||
// uncompressed size
|
||||
$header .= \pack('v', \strlen($name));
|
||||
// file name length
|
||||
$header .= \pack('v', \strlen($extra));
|
||||
// extra field length
|
||||
$header .= \pack('v', 0);
|
||||
// file comment length
|
||||
$header .= \pack('v', 0);
|
||||
// disk number start
|
||||
$header .= \pack('v', 0);
|
||||
// internal file attributes
|
||||
$header .= \pack('V', 0);
|
||||
// external file attributes @todo was 0x32!?
|
||||
$header .= \pack('V', $offset);
|
||||
// relative offset of local header
|
||||
$header .= $name;
|
||||
// file name
|
||||
$header .= $extra;
|
||||
// extra (utf-8 filename)
|
||||
return $header;
|
||||
}
|
||||
/**
|
||||
* Returns a local file header for the given data
|
||||
*
|
||||
* @param int $ts unix timestamp
|
||||
* @param int $crc CRC32 checksum of the uncompressed data
|
||||
* @param int $len length of the uncompressed data
|
||||
* @param int $clen length of the compressed data
|
||||
* @param string $name file name
|
||||
* @param boolean|null $comp if compression is used, if null it's determined from $len != $clen
|
||||
* @return string
|
||||
*/
|
||||
protected function makeLocalFileHeader($ts, $crc, $len, $clen, $name, $comp = null)
|
||||
{
|
||||
if (\is_null($comp)) {
|
||||
$comp = $len != $clen;
|
||||
}
|
||||
$comp = $comp ? 8 : 0;
|
||||
$dtime = \dechex($this->makeDosTime($ts));
|
||||
list($name, $extra) = $this->encodeFilename($name);
|
||||
$header = "PK\x03\x04";
|
||||
// local file header signature
|
||||
$header .= \pack('v', 20);
|
||||
// version needed to extract - 2.0
|
||||
$header .= \pack('v', 0);
|
||||
// general purpose flag - no flags set
|
||||
$header .= \pack('v', $comp);
|
||||
// compression method - deflate|none
|
||||
$header .= \pack('H*', $dtime[6] . $dtime[7] . $dtime[4] . $dtime[5] . $dtime[2] . $dtime[3] . $dtime[0] . $dtime[1]);
|
||||
// last mod file time and date
|
||||
$header .= \pack('V', $crc);
|
||||
// crc-32
|
||||
$header .= \pack('V', $clen);
|
||||
// compressed size
|
||||
$header .= \pack('V', $len);
|
||||
// uncompressed size
|
||||
$header .= \pack('v', \strlen($name));
|
||||
// file name length
|
||||
$header .= \pack('v', \strlen($extra));
|
||||
// extra field length
|
||||
$header .= $name;
|
||||
// file name
|
||||
$header .= $extra;
|
||||
// extra (utf-8 filename)
|
||||
return $header;
|
||||
}
|
||||
/**
|
||||
* Returns only a part of the local file header containing the CRC, size and compressed size.
|
||||
* Used to update these fields for an already written header.
|
||||
*
|
||||
* @param int $crc CRC32 checksum of the uncompressed data
|
||||
* @param int $len length of the uncompressed data
|
||||
* @param int $clen length of the compressed data
|
||||
* @return string
|
||||
*/
|
||||
protected function makeCrcAndSize($crc, $len, $clen)
|
||||
{
|
||||
$header = \pack('V', $crc);
|
||||
// crc-32
|
||||
$header .= \pack('V', $clen);
|
||||
// compressed size
|
||||
$header .= \pack('V', $len);
|
||||
// uncompressed size
|
||||
return $header;
|
||||
}
|
||||
/**
|
||||
* Returns an allowed filename and an extra field header
|
||||
*
|
||||
* When encoding stuff outside the 7bit ASCII range it needs to be placed in a separate
|
||||
* extra field
|
||||
*
|
||||
* @param $original
|
||||
* @return array($filename, $extra)
|
||||
*/
|
||||
protected function encodeFilename($original)
|
||||
{
|
||||
$cp437 = $this->utf8ToCp($original);
|
||||
if ($cp437 === $original) {
|
||||
return array($original, '');
|
||||
}
|
||||
$extra = \pack(
|
||||
'vvCV',
|
||||
0x7075,
|
||||
// tag
|
||||
\strlen($original) + 5,
|
||||
// length of file + version + crc
|
||||
1,
|
||||
// version
|
||||
\crc32($original)
|
||||
);
|
||||
$extra .= $original;
|
||||
return array($cp437, $extra);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user