├── msyh.ttf ├── xhxh.jpg ├── composer.json ├── vendor ├── autoload.php ├── composer │ ├── autoload_classmap.php │ ├── autoload_namespaces.php │ ├── autoload_psr4.php │ ├── ca-bundle │ │ ├── LICENSE │ │ ├── composer.json │ │ ├── README.md │ │ └── src │ │ │ └── CaBundle.php │ ├── LICENSE │ ├── autoload_static.php │ ├── autoload_real.php │ ├── installed.json │ └── ClassLoader.php ├── ua-parser │ └── uap-php │ │ ├── src │ │ ├── Exception │ │ │ ├── DomainException.php │ │ │ ├── ReaderException.php │ │ │ ├── FetcherException.php │ │ │ ├── InvalidArgumentException.php │ │ │ └── FileNotFoundException.php │ │ ├── Result │ │ │ ├── Device.php │ │ │ ├── AbstractSoftware.php │ │ │ ├── AbstractClient.php │ │ │ ├── UserAgent.php │ │ │ ├── OperatingSystem.php │ │ │ ├── AbstractVersionedSoftware.php │ │ │ └── Client.php │ │ ├── Util │ │ │ ├── Logfile │ │ │ │ ├── ReaderInterface.php │ │ │ │ ├── ApacheCommonLogFormatReader.php │ │ │ │ └── AbstractReader.php │ │ │ ├── Fetcher.php │ │ │ └── Converter.php │ │ ├── Command │ │ │ ├── ParserCommand.php │ │ │ ├── FetchCommand.php │ │ │ ├── UpdateCommand.php │ │ │ ├── ConvertCommand.php │ │ │ └── LogfileCommand.php │ │ ├── DeviceParser.php │ │ ├── OperatingSystemParser.php │ │ ├── Parser.php │ │ ├── UserAgentParser.php │ │ └── AbstractParser.php │ │ ├── LICENSE │ │ ├── update-resources.sh │ │ ├── bin │ │ └── uaparser │ │ ├── composer.json │ │ ├── README.md │ │ └── CHANGELOG.md └── bin │ └── uaparser ├── README.md ├── index.php └── composer.lock /msyh.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xhboke/IP/HEAD/msyh.ttf -------------------------------------------------------------------------------- /xhxh.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xhboke/IP/HEAD/xhxh.jpg -------------------------------------------------------------------------------- /composer.json: -------------------------------------------------------------------------------- 1 | { 2 | "require": { 3 | "ua-parser/uap-php": "^3.9" 4 | } 5 | } 6 | -------------------------------------------------------------------------------- /vendor/autoload.php: -------------------------------------------------------------------------------- 1 | array($vendorDir . '/ua-parser/uap-php/src'), 10 | 'Composer\\CaBundle\\' => array($vendorDir . '/composer/ca-bundle/src'), 11 | ); 12 | -------------------------------------------------------------------------------- /vendor/ua-parser/uap-php/src/Exception/DomainException.php: -------------------------------------------------------------------------------- 1 | /dev/null; cd '../ua-parser/uap-php/bin' && pwd) 4 | 5 | if [ -d /proc/cygdrive ]; then 6 | case $(which php) in 7 | $(readlink -n /proc/cygdrive)/*) 8 | # We are in Cygwin using Windows php, so the path must be translated 9 | dir=$(cygpath -m "$dir"); 10 | ;; 11 | esac 12 | fi 13 | 14 | "${dir}/uaparser" "$@" 15 | -------------------------------------------------------------------------------- /vendor/ua-parser/uap-php/src/Result/Device.php: -------------------------------------------------------------------------------- 1 | family; 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /vendor/ua-parser/uap-php/src/Util/Logfile/ReaderInterface.php: -------------------------------------------------------------------------------- 1 | toString(); 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /vendor/ua-parser/uap-php/LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2011-2012 Dave Olsen, http://dmolsen.com 2 | Licensed under the MIT license 3 | 4 | ua-parser-php is a PHP-based pseudo-port of the ua-parser project. Learn more about the ua-parser project at: 5 | 6 | http://code.google.com/p/ua-parser/ 7 | 8 | The user agents data from the ua-parser project is licensed under the Apache license. 9 | spyc-0.5, for loading the YAML, is licensed under the MIT license. 10 | The initial list of generic feature phones & smartphones came from Mobile Web OSP under the MIT license 11 | The initial list of spiders was taken from Yiibu's profile project under the MIT license. -------------------------------------------------------------------------------- /vendor/ua-parser/uap-php/src/Result/UserAgent.php: -------------------------------------------------------------------------------- 1 | formatVersion($this->major, $this->minor, $this->patch); 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /vendor/ua-parser/uap-php/src/Result/OperatingSystem.php: -------------------------------------------------------------------------------- 1 | formatVersion($this->major, $this->minor, $this->patch, $this->patchMinor); 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /vendor/ua-parser/uap-php/update-resources.sh: -------------------------------------------------------------------------------- 1 | #! /bin/bash 2 | 3 | function try_catch() { 4 | output=`"$@" &>/dev/stdout` 5 | if [ $? -gt 0 ]; then 6 | echo -e "Command $@ failed\n\n$output" 7 | exit 1 8 | fi 9 | } 10 | 11 | try_catch git pull 12 | try_catch git submodule foreach git pull origin master 13 | try_catch bin/uaparser ua-parser:convert uap-core/regexes.yaml 14 | try_catch vendor/bin/phpunit --stop-on-failure 15 | try_catch git commit -a -m "Scheduled resource update" 16 | try_catch git push origin master 17 | new_version=`git tag | sort --version-sort | tail -n 1 | awk -F. -v OFS=. 'NF==1{print ++$NF}; NF>1{if(length($NF+1)>length($NF))$(NF-1)++; $NF=sprintf("%0*d", length($NF), ($NF+1)%(10^length($NF))); print}'` 18 | try_catch git tag $new_version 19 | git push origin $new_version 20 | -------------------------------------------------------------------------------- /vendor/ua-parser/uap-php/src/Result/AbstractVersionedSoftware.php: -------------------------------------------------------------------------------- 1 | family, $this->toVersion()))); 21 | } 22 | 23 | /** @return string */ 24 | protected function formatVersion() 25 | { 26 | return join('.', array_filter(func_get_args(), 'is_numeric')); 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # IP签名档源码 2 |

说在前面

3 | 自从论坛IP签名档开放以来,访问量达到1806287,一百八十多万,由于证书过期和懒得维护。今特开源。 4 |

演示效果

5 | 6 |

原帖地址

7 | https://www.xhboke.com/858.html 8 |

修复

9 |

2020.04.22

10 |

时隔两年,新增天气

11 |

修复部分ua无法解析

12 |

效果:https://xhboke.com/news/?s=6L+Z5piv5ryU56S65pWI5p6c77yM6L+Z6YeM5paH5a2X5Y+v5Lul5pS55Y+Y

13 |

2019.7.16

14 |

修复并发量限制

15 |

测试CentOS+PHP7.2

16 |

2018.6.11

17 | $url="http://ip.taobao.com/service/getIpInfo.php?ip=".$ip;
18 | $country = $data['data']['country'];
19 | $region = $data['data']['region'];
20 | $city = $data['data']['city']; 21 |

感谢

22 | https://github.com/ua-parser/uap-php 23 | 24 | -------------------------------------------------------------------------------- /vendor/ua-parser/uap-php/src/Result/Client.php: -------------------------------------------------------------------------------- 1 | originalUserAgent = $originalUserAgent; 32 | } 33 | 34 | public function toString() 35 | { 36 | return $this->ua->toString() . '/' . $this->os->toString(); 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /vendor/ua-parser/uap-php/src/Exception/InvalidArgumentException.php: -------------------------------------------------------------------------------- 1 | add(new ConvertCommand($resourceDirectory, $defaultYamlFile)); 26 | $application->add(new UpdateCommand($resourceDirectory)); 27 | $application->add(new ParserCommand()); 28 | $application->add(new LogfileCommand()); 29 | $application->add(new FetchCommand($defaultYamlFile)); 30 | 31 | $application->run(); 32 | -------------------------------------------------------------------------------- /vendor/composer/autoload_static.php: -------------------------------------------------------------------------------- 1 | 11 | array ( 12 | 'UAParser\\' => 9, 13 | ), 14 | 'C' => 15 | array ( 16 | 'Composer\\CaBundle\\' => 18, 17 | ), 18 | ); 19 | 20 | public static $prefixDirsPsr4 = array ( 21 | 'UAParser\\' => 22 | array ( 23 | 0 => __DIR__ . '/..' . '/ua-parser/uap-php/src', 24 | ), 25 | 'Composer\\CaBundle\\' => 26 | array ( 27 | 0 => __DIR__ . '/..' . '/composer/ca-bundle/src', 28 | ), 29 | ); 30 | 31 | public static function getInitializer(ClassLoader $loader) 32 | { 33 | return \Closure::bind(function () use ($loader) { 34 | $loader->prefixLengthsPsr4 = ComposerStaticInit94fa57844104d91fdb2d302dc7e75828::$prefixLengthsPsr4; 35 | $loader->prefixDirsPsr4 = ComposerStaticInit94fa57844104d91fdb2d302dc7e75828::$prefixDirsPsr4; 36 | 37 | }, null, ClassLoader::class); 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /vendor/ua-parser/uap-php/src/Command/ParserCommand.php: -------------------------------------------------------------------------------- 1 | setName('ua-parser:parse') 23 | ->setDescription('Parses a user agent string and dumps the results.') 24 | ->addArgument( 25 | 'user-agent', 26 | null, 27 | InputArgument::REQUIRED, 28 | 'User agent string to analyze' 29 | ) 30 | ; 31 | } 32 | 33 | protected function execute(InputInterface $input, OutputInterface $output) 34 | { 35 | $result = Parser::create()->parse($input->getArgument('user-agent')); 36 | 37 | $output->writeln(json_encode($result, JSON_PRETTY_PRINT)); 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /vendor/ua-parser/uap-php/src/DeviceParser.php: -------------------------------------------------------------------------------- 1 | regexes['device_parsers'], $userAgent); 27 | 28 | if ($matches) { 29 | $device->family = self::multiReplace($regex, 'device_replacement', $matches[1], $matches); 30 | $device->brand = self::multiReplace($regex, 'brand_replacement', null, $matches); 31 | $deviceModelDefault = $matches[1] !== 'Other' ? $matches[1] : null; 32 | $device->model = self::multiReplace($regex, 'model_replacement', $deviceModelDefault, $matches); 33 | } 34 | 35 | return $device; 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /vendor/ua-parser/uap-php/src/Util/Logfile/ApacheCommonLogFormatReader.php: -------------------------------------------------------------------------------- 1 | .*?)\" # User Agent 35 | $@x'; 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /vendor/ua-parser/uap-php/src/OperatingSystemParser.php: -------------------------------------------------------------------------------- 1 | regexes['os_parsers'], $userAgent); 27 | 28 | if ($matches) { 29 | $os->family = self::multiReplace($regex, 'os_replacement', $matches[1], $matches); 30 | $os->major = self::multiReplace($regex, 'os_v1_replacement', $matches[2], $matches); 31 | $os->minor = self::multiReplace($regex, 'os_v2_replacement', $matches[3], $matches); 32 | $os->patch = self::multiReplace($regex, 'os_v3_replacement', $matches[4], $matches); 33 | $os->patchMinor = self::multiReplace($regex, 'os_v4_replacement', $matches[5], $matches); 34 | } 35 | 36 | return $os; 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /vendor/ua-parser/uap-php/composer.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "ua-parser/uap-php", 3 | "description": "A multi-language port of Browserscope's user agent parser.", 4 | "require": { 5 | "php": ">=5.3.0", 6 | "composer/ca-bundle": "^1.1" 7 | }, 8 | "require-dev": { 9 | "phpunit/phpunit": "<8", 10 | "symfony/yaml": "^2.0 || ^3.0 || ^4.0", 11 | "symfony/filesystem": "^2.0 || ^3.0 || ^4.0", 12 | "symfony/finder": "^2.0 || ^3.0 || ^4.0", 13 | "symfony/console": "^2.0 || ^3.0 || ^4.0" 14 | }, 15 | "suggest": { 16 | "symfony/yaml": "Required for CLI usage - ^4.0 || ^5.0", 17 | "symfony/filesystem": "Required for CLI usage - 2.0 || ^3.0 || ^4.0", 18 | "symfony/finder": "Required for CLI usage - ^2.0 || ^3.0 || ^4.0", 19 | "symfony/console": "Required for CLI usage - ^2.0 || ^3.0 || ^4.0" 20 | }, 21 | "prefer-stable": true, 22 | "license": "MIT", 23 | "authors": [ 24 | { 25 | "name": "Dave Olsen", 26 | "email": "dmolsen@gmail.com" 27 | }, 28 | { 29 | "name": "Lars Strojny", 30 | "email": "lars@strojny.net" 31 | } 32 | ], 33 | "autoload": { 34 | "psr-4": { 35 | "UAParser\\": "src" 36 | } 37 | }, 38 | "autoload-dev": { 39 | "psr-4": { 40 | "UAParser\\Test\\": "tests/" 41 | } 42 | }, 43 | "bin": ["bin/uaparser"] 44 | } 45 | -------------------------------------------------------------------------------- /vendor/ua-parser/uap-php/src/Command/FetchCommand.php: -------------------------------------------------------------------------------- 1 | defaultYamlFile = $defaultYamlFile; 26 | parent::__construct(); 27 | } 28 | 29 | protected function configure() 30 | { 31 | $this 32 | ->setName('ua-parser:fetch') 33 | ->setDescription('Fetches an updated YAML file for ua-parser.') 34 | ->addArgument( 35 | 'file', 36 | InputArgument::OPTIONAL, 37 | 'regexes.yaml output file', 38 | $this->defaultYamlFile 39 | ) 40 | ; 41 | } 42 | 43 | protected function execute(InputInterface $input, OutputInterface $output) 44 | { 45 | $fs = new Filesystem(); 46 | $fetcher = new Fetcher(); 47 | $fs->dumpFile($input->getArgument('file'), $fetcher->fetch()); 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /vendor/composer/ca-bundle/composer.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "composer/ca-bundle", 3 | "description": "Lets you find a path to the system CA bundle, and includes a fallback to the Mozilla CA bundle.", 4 | "type": "library", 5 | "license": "MIT", 6 | "keywords": [ 7 | "cabundle", 8 | "cacert", 9 | "certificate", 10 | "ssl", 11 | "tls" 12 | ], 13 | "authors": [ 14 | { 15 | "name": "Jordi Boggiano", 16 | "email": "j.boggiano@seld.be", 17 | "homepage": "http://seld.be" 18 | } 19 | ], 20 | "support": { 21 | "irc": "irc://irc.freenode.org/composer", 22 | "issues": "https://github.com/composer/ca-bundle/issues" 23 | }, 24 | "require": { 25 | "ext-openssl": "*", 26 | "ext-pcre": "*", 27 | "php": "^5.3.2 || ^7.0 || ^8.0" 28 | }, 29 | "require-dev": { 30 | "phpunit/phpunit": "^4.8.35 || ^5.7 || 6.5 - 8", 31 | "psr/log": "^1.0", 32 | "symfony/process": "^2.5 || ^3.0 || ^4.0 || ^5.0" 33 | }, 34 | "autoload": { 35 | "psr-4": { 36 | "Composer\\CaBundle\\": "src" 37 | } 38 | }, 39 | "autoload-dev": { 40 | "psr-4": { 41 | "Composer\\CaBundle\\": "tests" 42 | } 43 | }, 44 | "extra": { 45 | "branch-alias": { 46 | "dev-master": "1.x-dev" 47 | } 48 | }, 49 | "config": { 50 | "platform": { 51 | "php": "5.3.9" 52 | } 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /vendor/ua-parser/uap-php/src/Command/UpdateCommand.php: -------------------------------------------------------------------------------- 1 | resourceDirectory = $resourceDirectory; 26 | parent::__construct(); 27 | } 28 | 29 | protected function configure() 30 | { 31 | $this 32 | ->setName('ua-parser:update') 33 | ->setDescription('Fetches an updated YAML file for ua-parser and overwrites the current PHP file.') 34 | ->addOption( 35 | 'no-backup', 36 | null, 37 | InputOption::VALUE_NONE, 38 | 'Do not backup the previously existing file' 39 | ) 40 | ; 41 | } 42 | 43 | protected function execute(InputInterface $input, OutputInterface $output) 44 | { 45 | $fetcher = new Fetcher(); 46 | $converter = new Converter($this->resourceDirectory); 47 | 48 | $converter->convertString($fetcher->fetch(), !$input->getOption('no-backup')); 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /vendor/ua-parser/uap-php/src/Util/Logfile/AbstractReader.php: -------------------------------------------------------------------------------- 1 | test($line)) { 26 | return $reader; 27 | } 28 | } 29 | } 30 | 31 | private static function getReaders() 32 | { 33 | if (static::$readers) { 34 | return static::$readers; 35 | } 36 | 37 | static::$readers[] = new ApacheCommonLogFormatReader(); 38 | 39 | return static::$readers; 40 | } 41 | 42 | public function test($line) 43 | { 44 | $matches = $this->match($line); 45 | 46 | return isset($matches['userAgentString']); 47 | } 48 | 49 | public function read($line) 50 | { 51 | $matches = $this->match($line); 52 | 53 | if (!isset($matches['userAgentString'])) { 54 | throw ReaderException::userAgentParserError($line); 55 | } 56 | 57 | return $matches['userAgentString']; 58 | } 59 | 60 | protected function match($line) 61 | { 62 | if (preg_match($this->getRegex(), $line, $matches)) { 63 | return $matches; 64 | } 65 | 66 | return array(); 67 | } 68 | 69 | abstract protected function getRegex(); 70 | } 71 | -------------------------------------------------------------------------------- /vendor/ua-parser/uap-php/src/Parser.php: -------------------------------------------------------------------------------- 1 | regexes 27 | * 28 | * @param array $regexes 29 | */ 30 | public function __construct(array $regexes) 31 | { 32 | parent::__construct($regexes); 33 | $this->deviceParser = new DeviceParser($this->regexes); 34 | $this->operatingSystemParser = new OperatingSystemParser($this->regexes); 35 | $this->userAgentParser = new UserAgentParser($this->regexes); 36 | } 37 | 38 | /** 39 | * Sets up some standard variables as well as starts the user agent parsing process 40 | * 41 | * @param string $userAgent a user agent string to test, defaults to an empty string 42 | * @param array $jsParseBits 43 | * @return Client 44 | */ 45 | public function parse($userAgent, array $jsParseBits = array()) 46 | { 47 | $client = new Client($userAgent); 48 | 49 | $client->ua = $this->userAgentParser->parseUserAgent($userAgent, $jsParseBits); 50 | $client->os = $this->operatingSystemParser->parseOperatingSystem($userAgent); 51 | $client->device = $this->deviceParser->parseDevice($userAgent); 52 | 53 | return $client; 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /vendor/ua-parser/uap-php/src/Util/Fetcher.php: -------------------------------------------------------------------------------- 1 | streamContext = $streamContext; 25 | } else { 26 | $this->streamContext = stream_context_create( 27 | array( 28 | 'ssl' => array( 29 | 'verify_peer' => true, 30 | 'verify_depth' => 10, 31 | 'cafile' => CaBundle::getSystemCaRootBundlePath(), 32 | static::getPeerNameKey() => 'www.github.com', 33 | 'disable_compression' => true, 34 | ) 35 | ) 36 | ); 37 | } 38 | } 39 | 40 | public function fetch() 41 | { 42 | $level = error_reporting(0); 43 | $result = file_get_contents($this->resourceUri, null, $this->streamContext); 44 | error_reporting($level); 45 | 46 | if ($result === false) { 47 | $error = error_get_last(); 48 | throw FetcherException::httpError($this->resourceUri, $error['message']); 49 | } 50 | 51 | return $result; 52 | } 53 | 54 | public static function getPeerNameKey() 55 | { 56 | return version_compare(PHP_VERSION, '5.6') === 1 ? 'peer_name' : 'CN_match'; 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /vendor/ua-parser/uap-php/src/Command/ConvertCommand.php: -------------------------------------------------------------------------------- 1 | resourceDirectory = $resourceDirectory; 29 | $this->defaultYamlFile = $defaultYamlFile; 30 | parent::__construct(); 31 | } 32 | 33 | protected function configure() 34 | { 35 | $this 36 | ->setName('ua-parser:convert') 37 | ->setDescription('Converts an existing regexes.yaml file to a regexes.php file.') 38 | ->addArgument( 39 | 'file', 40 | InputArgument::OPTIONAL, 41 | 'Path to the regexes.yaml file', 42 | $this->defaultYamlFile 43 | ) 44 | ->addOption( 45 | 'no-backup', 46 | null, 47 | InputOption::VALUE_NONE, 48 | 'Do not backup the previously existing file' 49 | ) 50 | ; 51 | } 52 | 53 | protected function execute(InputInterface $input, OutputInterface $output) 54 | { 55 | $this->getConverter()->convertFile($input->getArgument('file'), $input->getOption('no-backup')); 56 | } 57 | 58 | private function getConverter() 59 | { 60 | return new Converter($this->resourceDirectory); 61 | } 62 | } 63 | -------------------------------------------------------------------------------- /vendor/composer/autoload_real.php: -------------------------------------------------------------------------------- 1 | = 50600 && !defined('HHVM_VERSION') && (!function_exists('zend_loader_file_encoded') || !zend_loader_file_encoded()); 30 | if ($useStaticLoader) { 31 | require_once __DIR__ . '/autoload_static.php'; 32 | 33 | call_user_func(\Composer\Autoload\ComposerStaticInit94fa57844104d91fdb2d302dc7e75828::getInitializer($loader)); 34 | } else { 35 | $map = require __DIR__ . '/autoload_namespaces.php'; 36 | foreach ($map as $namespace => $path) { 37 | $loader->set($namespace, $path); 38 | } 39 | 40 | $map = require __DIR__ . '/autoload_psr4.php'; 41 | foreach ($map as $namespace => $path) { 42 | $loader->setPsr4($namespace, $path); 43 | } 44 | 45 | $classMap = require __DIR__ . '/autoload_classmap.php'; 46 | if ($classMap) { 47 | $loader->addClassMap($classMap); 48 | } 49 | } 50 | 51 | $loader->register(true); 52 | 53 | return $loader; 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /index.php: -------------------------------------------------------------------------------- 1 | parse($ua); 14 | $os = $result->os->toString(); // Mac OS X 15 | $browser = $result->device->family.'-'.$result->ua->family;// Safari 6.0.2 16 | //地址、温度 17 | $data = json_decode(curl_get('https://api.xhboke.com/ip/v1.php?ip='.$ip), true); 18 | $country = $data['site']['country']; 19 | $region = $data['site']['region']; 20 | $adcode = $data['site']['adcode']; 21 | $weather = $data['city']['weather']; 22 | $temperature = $data['city']['temperature']; 23 | //历史上今天 24 | //$data = json_decode(get_curl('https://xhboke.com/mz/today.php'), true); 25 | //$today = $data['cover']['title']; 26 | //定义颜色 27 | $black = ImageColorAllocate($im, 0,0,0);//定义黑色的值 28 | $red = ImageColorAllocate($im, 255,0,0);//红色 29 | $font = 'msyh.ttf';//加载字体 30 | //输出 31 | imagettftext($im, 16, 0, 10, 40, $red, $font,'欢迎您来自'.$country.'-'.$region.'的朋友'); 32 | imagettftext($im, 16, 0, 10, 72, $red, $font, '今天是'.date('Y年n月j日').' 星期'.$weekarray[date("w")]);//当前时间添加到图片 33 | imagettftext($im, 16, 0, 10, 104, $red, $font,'您的IP是:'.$ip.' '.$weather." ".$temperature.'℃');//ip 34 | imagettftext($im, 16, 0, 10, 140, $red, $font,'您使用的是'.$os.'操作系统'); 35 | imagettftext($im, 16, 0, 10, 175, $red, $font,'您使用的是'.$browser); 36 | imagettftext($im, 13, 0, 10, 200, $black, $font,$get); 37 | ImageGif($im); 38 | ImageDestroy($im); 39 | 40 | 41 | function curl_get($url, array $params = array(), $timeout = 6){ 42 | $ch = curl_init(); 43 | curl_setopt($ch, CURLOPT_URL, $url); 44 | curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1); 45 | curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, $timeout); 46 | $file_contents = curl_exec($ch); 47 | curl_close($ch); 48 | return $file_contents; 49 | } 50 | ?> 51 | 52 | 53 | -------------------------------------------------------------------------------- /vendor/ua-parser/uap-php/src/UserAgentParser.php: -------------------------------------------------------------------------------- 1 | family = $jsParseBits['js_user_agent_family']; 30 | $ua->major = $jsParseBits['js_user_agent_v1']; 31 | $ua->minor = $jsParseBits['js_user_agent_v2']; 32 | $ua->patch = $jsParseBits['js_user_agent_v3']; 33 | 34 | } else { 35 | 36 | list($regex, $matches) = self::tryMatch($this->regexes['user_agent_parsers'], $userAgent); 37 | 38 | if ($matches) { 39 | $ua->family = self::multiReplace($regex, 'family_replacement', $matches[1], $matches); 40 | $ua->major = self::multiReplace($regex, 'v1_replacement', $matches[2], $matches); 41 | $ua->minor = self::multiReplace($regex, 'v2_replacement', $matches[3], $matches); 42 | $ua->patch = self::multiReplace($regex, 'v3_replacement', $matches[4], $matches); 43 | } 44 | } 45 | 46 | if (isset($jsParseBits['js_user_agent_string'])) { 47 | $jsUserAgentString = $jsParseBits['js_user_agent_string']; 48 | if (strpos($jsUserAgentString, 'Chrome/') !== false && strpos($userAgent, 'chromeframe') !== false) { 49 | $override = $this->parseUserAgent($jsUserAgentString); 50 | $ua->family = sprintf('Chrome Frame (%s %s)', $ua->family, $ua->major); 51 | $ua->major = $override->major; 52 | $ua->minor = $override->minor; 53 | $ua->patch = $override->patch; 54 | } 55 | } 56 | 57 | return $ua; 58 | } 59 | 60 | } 61 | -------------------------------------------------------------------------------- /vendor/composer/ca-bundle/README.md: -------------------------------------------------------------------------------- 1 | composer/ca-bundle 2 | ================== 3 | 4 | Small utility library that lets you find a path to the system CA bundle, 5 | and includes a fallback to the Mozilla CA bundle. 6 | 7 | Originally written as part of [composer/composer](https://github.com/composer/composer), 8 | now extracted and made available as a stand-alone library. 9 | 10 | 11 | Installation 12 | ------------ 13 | 14 | Install the latest version with: 15 | 16 | ```bash 17 | $ composer require composer/ca-bundle 18 | ``` 19 | 20 | 21 | Requirements 22 | ------------ 23 | 24 | * PHP 5.3.2 is required but using the latest version of PHP is highly recommended. 25 | 26 | 27 | Basic usage 28 | ----------- 29 | 30 | ### `Composer\CaBundle\CaBundle` 31 | 32 | - `CaBundle::getSystemCaRootBundlePath()`: Returns the system CA bundle path, or a path to the bundled one as fallback 33 | - `CaBundle::getBundledCaBundlePath()`: Returns the path to the bundled CA file 34 | - `CaBundle::validateCaFile($filename)`: Validates a CA file using openssl_x509_parse only if it is safe to use 35 | - `CaBundle::isOpensslParseSafe()`: Test if it is safe to use the PHP function openssl_x509_parse() 36 | - `CaBundle::reset()`: Resets the static caches 37 | 38 | 39 | #### To use with curl 40 | 41 | ```php 42 | $curl = curl_init("https://example.org/"); 43 | 44 | $caPathOrFile = \Composer\CaBundle\CaBundle::getSystemCaRootBundlePath(); 45 | if (is_dir($caPathOrFile)) { 46 | curl_setopt($curl, CURLOPT_CAPATH, $caPathOrFile); 47 | } else { 48 | curl_setopt($curl, CURLOPT_CAINFO, $caPathOrFile); 49 | } 50 | 51 | $result = curl_exec($curl); 52 | ``` 53 | 54 | #### To use with php streams 55 | 56 | ```php 57 | $opts = array( 58 | 'http' => array( 59 | 'method' => "GET" 60 | ) 61 | ); 62 | 63 | $caPathOrFile = \Composer\CaBundle\CaBundle::getSystemCaRootBundlePath(); 64 | if (is_dir($caPathOrFile)) { 65 | $opts['ssl']['capath'] = $caPathOrFile; 66 | } else { 67 | $opts['ssl']['cafile'] = $caPathOrFile; 68 | } 69 | 70 | $context = stream_context_create($opts); 71 | $result = file_get_contents('https://example.com', false, $context); 72 | ``` 73 | 74 | #### To use with Guzzle 75 | 76 | ```php 77 | $client = new \GuzzleHttp\Client([ 78 | \GuzzleHttp\RequestOptions::VERIFY => \Composer\CaBundle\CaBundle::getSystemCaRootBundlePath() 79 | ]); 80 | ``` 81 | 82 | License 83 | ------- 84 | 85 | composer/ca-bundle is licensed under the MIT License, see the LICENSE file for details. 86 | -------------------------------------------------------------------------------- /vendor/ua-parser/uap-php/src/Util/Converter.php: -------------------------------------------------------------------------------- 1 | destination = $destination; 30 | $this->fs = $fs ? $fs : new Filesystem(); 31 | } 32 | 33 | /** 34 | * @param string $yamlFile 35 | * @param bool $backupBeforeOverride 36 | * @throws FileNotFoundException 37 | */ 38 | public function convertFile($yamlFile, $backupBeforeOverride = true) 39 | { 40 | if (!$this->fs->exists($yamlFile)) { 41 | throw FileNotFoundException::fileNotFound($yamlFile); 42 | } 43 | 44 | $this->doConvert(Yaml::parse(file_get_contents($yamlFile)), $backupBeforeOverride); 45 | } 46 | 47 | /** 48 | * @param string $yamlString 49 | * @param bool $backupBeforeOverride 50 | */ 51 | public function convertString($yamlString, $backupBeforeOverride = true) 52 | { 53 | $this->doConvert(Yaml::parse($yamlString), $backupBeforeOverride); 54 | } 55 | 56 | /** 57 | * @param array $regexes 58 | * @param bool $backupBeforeOverride 59 | */ 60 | protected function doConvert(array $regexes, $backupBeforeOverride = true) 61 | { 62 | $regexes = $this->sanitizeRegexes($regexes); 63 | $data = "destination . '/regexes.php'; 66 | if ($backupBeforeOverride && $this->fs->exists($regexesFile)) { 67 | 68 | $currentHash = hash('sha512', file_get_contents($regexesFile)); 69 | $futureHash = hash('sha512', $data); 70 | 71 | if ($futureHash === $currentHash) { 72 | return; 73 | } 74 | 75 | $backupFile = $this->destination . '/regexes-' . $currentHash . '.php'; 76 | $this->fs->copy($regexesFile, $backupFile); 77 | } 78 | 79 | $this->fs->dumpFile($regexesFile, $data); 80 | } 81 | 82 | private function sanitizeRegexes(array $regexes) 83 | { 84 | foreach ($regexes as $groupName => $group) { 85 | $regexes[$groupName] = array_map(array($this, 'sanitizeRegex'), $group); 86 | } 87 | 88 | return $regexes; 89 | } 90 | 91 | private function sanitizeRegex(array $regex) 92 | { 93 | $regex['regex'] = str_replace('@', '\@', $regex['regex']); 94 | 95 | return $regex; 96 | } 97 | } 98 | -------------------------------------------------------------------------------- /vendor/ua-parser/uap-php/src/AbstractParser.php: -------------------------------------------------------------------------------- 1 | regexes = $regexes; 25 | } 26 | 27 | /** 28 | * Create parser instance 29 | * 30 | * Either pass a custom regexes.php file or leave the argument empty and use the default file. 31 | * 32 | * @param string $file 33 | * @throws FileNotFoundException 34 | * @return static 35 | */ 36 | public static function create($file = null) 37 | { 38 | return $file ? static::createCustom($file) : static::createDefault(); 39 | } 40 | 41 | /** 42 | * @return static 43 | * @throws FileNotFoundException 44 | */ 45 | protected static function createDefault() 46 | { 47 | return static::createInstance( 48 | static::getDefaultFile(), 49 | array('UAParser\Exception\FileNotFoundException', 'defaultFileNotFound') 50 | ); 51 | } 52 | 53 | /** 54 | * @return static 55 | * @throws FileNotFoundException 56 | */ 57 | protected static function createCustom($file) 58 | { 59 | return static::createInstance( 60 | $file, 61 | array('UAParser\Exception\FileNotFoundException', 'customRegexFileNotFound') 62 | ); 63 | } 64 | 65 | private static function createInstance($file, $exceptionFactory) 66 | { 67 | if (!file_exists($file)) { 68 | throw call_user_func($exceptionFactory, $file); 69 | } 70 | 71 | return new static(include $file); 72 | } 73 | 74 | /** 75 | * @param array $regexes 76 | * @param string $userAgent 77 | * @return array 78 | */ 79 | protected static function tryMatch(array $regexes, $userAgent) 80 | { 81 | foreach ($regexes as $regex) { 82 | $flag = isset($regex['regex_flag']) ? $regex['regex_flag'] : ''; 83 | if (preg_match('@' . $regex['regex'] . '@' . $flag, $userAgent, $matches)) { 84 | 85 | $defaults = array( 86 | 1 => 'Other', 87 | 2 => null, 88 | 3 => null, 89 | 4 => null, 90 | 5 => null, 91 | ); 92 | 93 | return array($regex, $matches + $defaults); 94 | } 95 | } 96 | 97 | return array(null, null); 98 | } 99 | 100 | /** 101 | * @param array $regex 102 | * @param string $key 103 | * @param string $default 104 | * @param array $matches 105 | * @return string|null 106 | */ 107 | protected static function multiReplace(array $regex, $key, $default, array $matches) 108 | { 109 | if (!isset($regex[$key])) { 110 | return self::emptyStringToNull($default); 111 | } 112 | 113 | $replacement = preg_replace_callback( 114 | '|\$(?P\d)|', 115 | function ($m) use ($matches) { 116 | return isset($matches[$m['key']]) ? $matches[$m['key']] : ''; 117 | }, 118 | $regex[$key] 119 | ); 120 | 121 | return self::emptyStringToNull($replacement); 122 | } 123 | 124 | private static function emptyStringToNull($string) 125 | { 126 | $string = trim($string); 127 | 128 | return $string === '' ? null : $string; 129 | } 130 | 131 | /** 132 | * @return string 133 | */ 134 | protected static function getDefaultFile() 135 | { 136 | return static::$defaultFile 137 | ? static::$defaultFile 138 | : realpath(__DIR__ . '/../resources') . DIRECTORY_SEPARATOR . 'regexes.php'; 139 | } 140 | } 141 | -------------------------------------------------------------------------------- /vendor/composer/installed.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "name": "composer/ca-bundle", 4 | "version": "1.2.6", 5 | "version_normalized": "1.2.6.0", 6 | "source": { 7 | "type": "git", 8 | "url": "https://github.com/composer/ca-bundle.git", 9 | "reference": "47fe531de31fca4a1b997f87308e7d7804348f7e" 10 | }, 11 | "dist": { 12 | "type": "zip", 13 | "url": "https://api.github.com/repos/composer/ca-bundle/zipball/47fe531de31fca4a1b997f87308e7d7804348f7e", 14 | "reference": "47fe531de31fca4a1b997f87308e7d7804348f7e", 15 | "shasum": "" 16 | }, 17 | "require": { 18 | "ext-openssl": "*", 19 | "ext-pcre": "*", 20 | "php": "^5.3.2 || ^7.0 || ^8.0" 21 | }, 22 | "require-dev": { 23 | "phpunit/phpunit": "^4.8.35 || ^5.7 || 6.5 - 8", 24 | "psr/log": "^1.0", 25 | "symfony/process": "^2.5 || ^3.0 || ^4.0 || ^5.0" 26 | }, 27 | "time": "2020-01-13T10:02:55+00:00", 28 | "type": "library", 29 | "extra": { 30 | "branch-alias": { 31 | "dev-master": "1.x-dev" 32 | } 33 | }, 34 | "installation-source": "dist", 35 | "autoload": { 36 | "psr-4": { 37 | "Composer\\CaBundle\\": "src" 38 | } 39 | }, 40 | "notification-url": "https://packagist.org/downloads/", 41 | "license": [ 42 | "MIT" 43 | ], 44 | "authors": [ 45 | { 46 | "name": "Jordi Boggiano", 47 | "email": "j.boggiano@seld.be", 48 | "homepage": "http://seld.be" 49 | } 50 | ], 51 | "description": "Lets you find a path to the system CA bundle, and includes a fallback to the Mozilla CA bundle.", 52 | "keywords": [ 53 | "cabundle", 54 | "cacert", 55 | "certificate", 56 | "ssl", 57 | "tls" 58 | ] 59 | }, 60 | { 61 | "name": "ua-parser/uap-php", 62 | "version": "v3.9.7", 63 | "version_normalized": "3.9.7.0", 64 | "source": { 65 | "type": "git", 66 | "url": "https://github.com/ua-parser/uap-php.git", 67 | "reference": "7efc2f05b7d9817a59132e5d2e5ca91a1c071f6a" 68 | }, 69 | "dist": { 70 | "type": "zip", 71 | "url": "https://api.github.com/repos/ua-parser/uap-php/zipball/7efc2f05b7d9817a59132e5d2e5ca91a1c071f6a", 72 | "reference": "7efc2f05b7d9817a59132e5d2e5ca91a1c071f6a", 73 | "shasum": "" 74 | }, 75 | "require": { 76 | "composer/ca-bundle": "^1.1", 77 | "php": ">=5.3.0" 78 | }, 79 | "require-dev": { 80 | "phpunit/phpunit": "<8", 81 | "symfony/console": "^2.0 || ^3.0 || ^4.0", 82 | "symfony/filesystem": "^2.0 || ^3.0 || ^4.0", 83 | "symfony/finder": "^2.0 || ^3.0 || ^4.0", 84 | "symfony/yaml": "^2.0 || ^3.0 || ^4.0" 85 | }, 86 | "suggest": { 87 | "symfony/console": "Required for CLI usage - ^2.0 || ^3.0 || ^4.0", 88 | "symfony/filesystem": "Required for CLI usage - 2.0 || ^3.0 || ^4.0", 89 | "symfony/finder": "Required for CLI usage - ^2.0 || ^3.0 || ^4.0", 90 | "symfony/yaml": "Required for CLI usage - ^4.0 || ^5.0" 91 | }, 92 | "time": "2020-02-21T09:54:14+00:00", 93 | "bin": [ 94 | "bin/uaparser" 95 | ], 96 | "type": "library", 97 | "installation-source": "dist", 98 | "autoload": { 99 | "psr-4": { 100 | "UAParser\\": "src" 101 | } 102 | }, 103 | "notification-url": "https://packagist.org/downloads/", 104 | "license": [ 105 | "MIT" 106 | ], 107 | "authors": [ 108 | { 109 | "name": "Dave Olsen", 110 | "email": "dmolsen@gmail.com" 111 | }, 112 | { 113 | "name": "Lars Strojny", 114 | "email": "lars@strojny.net" 115 | } 116 | ], 117 | "description": "A multi-language port of Browserscope's user agent parser." 118 | } 119 | ] 120 | -------------------------------------------------------------------------------- /composer.lock: -------------------------------------------------------------------------------- 1 | { 2 | "_readme": [ 3 | "This file locks the dependencies of your project to a known state", 4 | "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", 5 | "This file is @generated automatically" 6 | ], 7 | "content-hash": "1d5c899fd1cfa4469bbd76b2735efb15", 8 | "packages": [ 9 | { 10 | "name": "composer/ca-bundle", 11 | "version": "1.2.6", 12 | "source": { 13 | "type": "git", 14 | "url": "https://github.com/composer/ca-bundle.git", 15 | "reference": "47fe531de31fca4a1b997f87308e7d7804348f7e" 16 | }, 17 | "dist": { 18 | "type": "zip", 19 | "url": "https://api.github.com/repos/composer/ca-bundle/zipball/47fe531de31fca4a1b997f87308e7d7804348f7e", 20 | "reference": "47fe531de31fca4a1b997f87308e7d7804348f7e", 21 | "shasum": "" 22 | }, 23 | "require": { 24 | "ext-openssl": "*", 25 | "ext-pcre": "*", 26 | "php": "^5.3.2 || ^7.0 || ^8.0" 27 | }, 28 | "require-dev": { 29 | "phpunit/phpunit": "^4.8.35 || ^5.7 || 6.5 - 8", 30 | "psr/log": "^1.0", 31 | "symfony/process": "^2.5 || ^3.0 || ^4.0 || ^5.0" 32 | }, 33 | "type": "library", 34 | "extra": { 35 | "branch-alias": { 36 | "dev-master": "1.x-dev" 37 | } 38 | }, 39 | "autoload": { 40 | "psr-4": { 41 | "Composer\\CaBundle\\": "src" 42 | } 43 | }, 44 | "notification-url": "https://packagist.org/downloads/", 45 | "license": [ 46 | "MIT" 47 | ], 48 | "authors": [ 49 | { 50 | "name": "Jordi Boggiano", 51 | "email": "j.boggiano@seld.be", 52 | "homepage": "http://seld.be" 53 | } 54 | ], 55 | "description": "Lets you find a path to the system CA bundle, and includes a fallback to the Mozilla CA bundle.", 56 | "keywords": [ 57 | "cabundle", 58 | "cacert", 59 | "certificate", 60 | "ssl", 61 | "tls" 62 | ], 63 | "time": "2020-01-13T10:02:55+00:00" 64 | }, 65 | { 66 | "name": "ua-parser/uap-php", 67 | "version": "v3.9.7", 68 | "source": { 69 | "type": "git", 70 | "url": "https://github.com/ua-parser/uap-php.git", 71 | "reference": "7efc2f05b7d9817a59132e5d2e5ca91a1c071f6a" 72 | }, 73 | "dist": { 74 | "type": "zip", 75 | "url": "https://api.github.com/repos/ua-parser/uap-php/zipball/7efc2f05b7d9817a59132e5d2e5ca91a1c071f6a", 76 | "reference": "7efc2f05b7d9817a59132e5d2e5ca91a1c071f6a", 77 | "shasum": "" 78 | }, 79 | "require": { 80 | "composer/ca-bundle": "^1.1", 81 | "php": ">=5.3.0" 82 | }, 83 | "require-dev": { 84 | "phpunit/phpunit": "<8", 85 | "symfony/console": "^2.0 || ^3.0 || ^4.0", 86 | "symfony/filesystem": "^2.0 || ^3.0 || ^4.0", 87 | "symfony/finder": "^2.0 || ^3.0 || ^4.0", 88 | "symfony/yaml": "^2.0 || ^3.0 || ^4.0" 89 | }, 90 | "suggest": { 91 | "symfony/console": "Required for CLI usage - ^2.0 || ^3.0 || ^4.0", 92 | "symfony/filesystem": "Required for CLI usage - 2.0 || ^3.0 || ^4.0", 93 | "symfony/finder": "Required for CLI usage - ^2.0 || ^3.0 || ^4.0", 94 | "symfony/yaml": "Required for CLI usage - ^4.0 || ^5.0" 95 | }, 96 | "bin": [ 97 | "bin/uaparser" 98 | ], 99 | "type": "library", 100 | "autoload": { 101 | "psr-4": { 102 | "UAParser\\": "src" 103 | } 104 | }, 105 | "notification-url": "https://packagist.org/downloads/", 106 | "license": [ 107 | "MIT" 108 | ], 109 | "authors": [ 110 | { 111 | "name": "Dave Olsen", 112 | "email": "dmolsen@gmail.com" 113 | }, 114 | { 115 | "name": "Lars Strojny", 116 | "email": "lars@strojny.net" 117 | } 118 | ], 119 | "description": "A multi-language port of Browserscope's user agent parser.", 120 | "time": "2020-02-21T09:54:14+00:00" 121 | } 122 | ], 123 | "packages-dev": [], 124 | "aliases": [], 125 | "minimum-stability": "stable", 126 | "stability-flags": [], 127 | "prefer-stable": false, 128 | "prefer-lowest": false, 129 | "platform": [], 130 | "platform-dev": [], 131 | "plugin-api-version": "1.1.0" 132 | } 133 | -------------------------------------------------------------------------------- /vendor/ua-parser/uap-php/README.md: -------------------------------------------------------------------------------- 1 | # ua-parser PHP Library # 2 | 3 | [![Gitter](https://badges.gitter.im/Join%20Chat.svg)](https://gitter.im/ua-parser/uap-php?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge) [![Build Status](https://travis-ci.org/ua-parser/uap-php.svg?branch=master)](https://travis-ci.org/ua-parser/uap-php) [![Average time to resolve an issue](http://isitmaintained.com/badge/resolution/ua-parser/uap-php.svg)](http://isitmaintained.com/project/ua-parser/uap-php "Average time to resolve an issue") [![Percentage of issues still open](http://isitmaintained.com/badge/open/ua-parser/uap-php.svg)](http://isitmaintained.com/project/ua-parser/uap-php "Percentage of issues still open") 4 | [![Latest Stable Version](https://poser.pugx.org/ua-parser/uap-php/v/stable)](https://packagist.org/packages/ua-parser/uap-php) 5 | [![Total Downloads](https://poser.pugx.org/ua-parser/uap-php/downloads)](https://packagist.org/packages/ua-parser/uap-php) 6 | [![License](https://poser.pugx.org/ua-parser/uap-php/license)](https://packagist.org/packages/ua-parser/uap-php) 7 | 8 | This is the PHP library for the [uap-core](https://github.com/ua-parser/uap-core) project. 9 | 10 | ## Installation ## 11 | Add `ua-parser/uap-php` to the require section of your `composer.json` file and run `composer update`. 12 | 13 | ## Usage ## 14 | 15 | Straightforward: 16 | 17 | ```php 18 | require_once 'vendor/autoload.php'; 19 | use UAParser\Parser; 20 | 21 | $ua = "Mozilla/5.0 (Macintosh; Intel Ma..."; 22 | 23 | $parser = Parser::create(); 24 | $result = $parser->parse($ua); 25 | 26 | print $result->ua->family; // Safari 27 | print $result->ua->major; // 6 28 | print $result->ua->minor; // 0 29 | print $result->ua->patch; // 2 30 | print $result->ua->toString(); // Safari 6.0.2 31 | print $result->ua->toVersion(); // 6.0.2 32 | 33 | print $result->os->family; // Mac OS X 34 | print $result->os->major; // 10 35 | print $result->os->minor; // 7 36 | print $result->os->patch; // 5 37 | print $result->os->patchMinor; // [null] 38 | print $result->os->toString(); // Mac OS X 10.7.5 39 | print $result->os->toVersion(); // 10.7.5 40 | 41 | print $result->device->family; // Other 42 | 43 | print $result->toString(); // Safari 6.0.2/Mac OS X 10.7.5 44 | print $result->originalUserAgent; // Mozilla/5.0 (Macintosh; Intel Ma... 45 | ``` 46 | 47 | ## Using Your Own Custom regexes.php File ## 48 | 49 | You can use your own `regexes.php` file if you've customized the official file. I *strongly* encourage you to push back any changes you may have so others can benefit. That said, to use your own do the following: 50 | 51 | ```php 52 | require_once 'vendor/autoload.php'; 53 | use UAParser\Parser; 54 | 55 | $parser = Parser::create("path/to/custom/regexes.php"); 56 | ``` 57 | 58 | ## Using ua-parser PHP Library from the Command Line ## 59 | 60 | A command line utility is now included with the PHP library. The following commands are supported: 61 | 62 | ### Get Usage Info 63 | 64 | Provides simple usage information: 65 | 66 | php bin/uaparser 67 | 68 | ### Update the regexes.php File 69 | 70 | Fetches an updated YAML file for `ua-parser` and overwrites the current regexes.php file. You can use the following as part of a cron job that runs nightly. 71 | 72 | php bin/uaparser ua-parser:update [--no-backup] 73 | 74 | By default creates a backup file. Use `--no-backup` to turn that feature off. 75 | 76 | ### Convert an Existing regexes.yaml File to regexes.php 77 | 78 | With the change to v2.0 you may have an existing and customized YAML file for `ua-parser`. Use the following to convert it to JSON. 79 | 80 | php bin/uaparser ua-parser:convert [file] 81 | 82 | ### Grab Just the Latest regexes.yaml File From the Repository 83 | 84 | If you need to add a new UA it's easier to edit the original YAML and then convert it to JSON. 85 | 86 | php bin/uaparser ua-parser:fetch [file] 87 | 88 | Fetches an updated YAML file. *Warning:* This method overwrites any existing `regexes.yaml` file. 89 | 90 | ### Parse a Single User Agent String 91 | 92 | Parses a user agent string and dumps the results as a list. 93 | 94 | php bin/uaparser ua-parser:parse "your user agent string" 95 | 96 | ### Parse a Webserver Log File 97 | 98 | Parses the supplied log file or log directory to test ua-parser. Saves the UA to a file when the UA or OS family aren't recognized or when the UA is listed as a generic smartphone or as a generic feature phone. 99 | 100 | php bin/uaparser ua-parser:logfile [-f /path/to/logfile] [-d /path/to/logdir] [--include "*.gz"] [--exclude "*.gz"] errors.log 101 | 102 | Multiple `--include` and `--exclude` parameters are allowed. 103 | 104 | ## Credits ## 105 | 106 | Thanks to the [original ua-parser team](http://code.google.com/p/ua-parser/people/list) for making the YAML file available for others to build upon. 107 | 108 | Also, many thanks to the following major contributors to the PHP library: 109 | 110 | * Bryan Shelton 111 | * Michael Bond 112 | * @rjd22 113 | * Timo Tijhof 114 | * Marcus Bointon 115 | * Ryan Parman 116 | * Pravin Dahal 117 | 118 | ## Licensing ## 119 | * The library is licensed under the MIT license 120 | * The user agents data from the ua-parser project is licensed under the Apache license 121 | * The initial list of generic feature phones & smartphones came from Mobile Web OSP under the MIT license 122 | * The initial list of spiders was taken from Yiibu's profile project under the MIT license. 123 | 124 | -------------------------------------------------------------------------------- /vendor/ua-parser/uap-php/src/Command/LogfileCommand.php: -------------------------------------------------------------------------------- 1 | setName('ua-parser:log') 31 | ->setDescription('Parses the supplied webserver log file.') 32 | ->addArgument( 33 | 'output', 34 | InputArgument::REQUIRED, 35 | 'Path to output log file' 36 | ) 37 | ->addOption( 38 | 'log-file', 39 | 'f', 40 | InputOption::VALUE_REQUIRED, 41 | 'Path to a webserver log file' 42 | ) 43 | ->addOption( 44 | 'log-dir', 45 | 'd', 46 | InputOption::VALUE_REQUIRED, 47 | 'Path to webserver log directory' 48 | ) 49 | ->addOption( 50 | 'include', 51 | 'i', 52 | InputOption::VALUE_IS_ARRAY | InputOption::VALUE_REQUIRED, 53 | 'Include glob expressions for log files in the log directory', 54 | array('*.log', '*.log*.gz', '*.log*.bz2') 55 | ) 56 | ->addOption( 57 | 'exclude', 58 | 'e', 59 | InputOption::VALUE_IS_ARRAY | InputOption::VALUE_REQUIRED, 60 | 'Exclude glob expressions for log files in the log directory', 61 | array('*error*') 62 | ) 63 | ; 64 | } 65 | 66 | protected function execute(InputInterface $input, OutputInterface $output) 67 | { 68 | if (!$input->getOption('log-file') && !$input->getOption('log-dir')) { 69 | throw InvalidArgumentException::oneOfCommandArguments('log-file', 'log-dir'); 70 | } 71 | 72 | $parser = Parser::create(); 73 | $undefinedClients = array(); 74 | /** @var $file SplFileInfo */ 75 | foreach ($this->getFiles($input) as $file) { 76 | 77 | $path = $this->getPath($file); 78 | $lines = file($path); 79 | 80 | if (empty($lines)) { 81 | $output->writeln(sprintf('Skipping empty file "%s"', $file->getPathname())); 82 | $output->writeln(''); 83 | continue; 84 | } 85 | 86 | $firstLine = reset($lines); 87 | 88 | $reader = AbstractReader::factory($firstLine); 89 | if (!$reader) { 90 | $output->writeln(sprintf('Could not find reader for file "%s"', $file->getPathname())); 91 | $output->writeln(''); 92 | continue; 93 | } 94 | 95 | $output->writeln(''); 96 | $output->writeln(sprintf('Analyzing "%s"', $file->getPathname())); 97 | 98 | $count = 1; 99 | $totalCount = count($lines); 100 | foreach ($lines as $line) { 101 | 102 | try { 103 | $userAgentString = $reader->read($line); 104 | } catch (ReaderException $e) { 105 | $count = $this->outputProgress($output, 'E', $count, $totalCount); 106 | continue; 107 | } 108 | 109 | $client = $parser->parse($userAgentString); 110 | 111 | $result = $this->getResult($client); 112 | if ($result !== '.') { 113 | $undefinedClients[] = json_encode( 114 | array($client->toString(), $userAgentString), 115 | JSON_UNESCAPED_SLASHES 116 | ); 117 | } 118 | 119 | $count = $this->outputProgress($output, $result, $count, $totalCount); 120 | } 121 | $this->outputProgress($output, '', $count - 1, $totalCount, true); 122 | $output->writeln(''); 123 | } 124 | 125 | $undefinedClients = $this->filter($undefinedClients); 126 | 127 | $fs = new Filesystem(); 128 | $fs->dumpFile($input->getArgument('output'), join(PHP_EOL, $undefinedClients)); 129 | } 130 | 131 | private function outputProgress(OutputInterface $output, $result, $count, $totalCount, $end = false) 132 | { 133 | if (($count % 70) === 0 || $end) { 134 | $formatString = '%s %' . strlen($totalCount) . 'd / %-' . strlen($totalCount) . 'd (%3d%%)'; 135 | $result = $end ? str_repeat(' ', 70 - ($count % 70)) : $result; 136 | $output->writeln(sprintf($formatString, $result, $count, $totalCount, $count / $totalCount * 100)); 137 | } else { 138 | $output->write($result); 139 | } 140 | 141 | return $count + 1; 142 | } 143 | 144 | private function getResult(Client $client) 145 | { 146 | if ($client->device->family === 'Spider') { 147 | return '.'; 148 | } elseif ($client->ua->family === 'Other') { 149 | return 'U'; 150 | } elseif ($client->os->family === 'Other') { 151 | return 'O'; 152 | } elseif ($client->device->family === 'Generic Smartphone') { 153 | return 'S'; 154 | } elseif ($client->device->family === 'Generic Feature Phone') { 155 | return 'F'; 156 | } 157 | 158 | return '.'; 159 | } 160 | 161 | private function getFiles(InputInterface $input) 162 | { 163 | $finder = Finder::create(); 164 | 165 | if ($input->getOption('log-file')) { 166 | $file = $input->getOption('log-file'); 167 | $finder->append(Finder::create()->in(dirname($file))->name(basename($file))); 168 | } 169 | 170 | if ($input->getOption('log-dir')) { 171 | $dirFinder = Finder::create() 172 | ->in($input->getOption('log-dir')); 173 | array_map(array($dirFinder, 'name'), $input->getOption('include')); 174 | array_map(array($dirFinder, 'notName'), $input->getOption('exclude')); 175 | 176 | $finder->append($dirFinder); 177 | } 178 | 179 | return $finder; 180 | } 181 | 182 | private function filter(array $lines) 183 | { 184 | return array_values(array_unique($lines)); 185 | } 186 | 187 | private function getPath(SplFileInfo $file) 188 | { 189 | switch ($file->getExtension()) { 190 | case 'gz': 191 | $path = 'compress.zlib://' . $file->getPathname(); 192 | break; 193 | 194 | case 'bz2': 195 | $path = 'compress.bzip2://' . $file->getPathname(); 196 | break; 197 | 198 | default: 199 | $path = $file->getPathname(); 200 | break; 201 | } 202 | 203 | return $path; 204 | } 205 | } 206 | -------------------------------------------------------------------------------- /vendor/ua-parser/uap-php/CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Changelog 2 | 3 | ## 3.4.2 4 | - Update uap-core 5 | 6 | ## 3.4.1 7 | - Fix a regex delimiter issue with uap-core 8 | - Bundle regex.php with uap-php 9 | 10 | ## 3.4.0 11 | - ADD: device Parsing with brand model and case insensitive testing 12 | - Use `peer_name` instead of `CN_match` for PHP >=5.6 13 | - Advertise Gitter chat for support requests 14 | - Include uap-core as a git submodule 15 | 16 | ## 3.3.1 17 | - PSR-4 ready 18 | - Self repository, less useless files 19 | 20 | ## 3.3.0 21 | - Use composer for dependency management 22 | - Introduce namespaces 23 | - Removing legacy library dependencies 24 | - Use PHPUnit for testing 25 | - Make all tests pass, fix all the remaining bugs 26 | - Introduce specific result objects 27 | - Comply with PSR-X coding standards: 28 | * `UAParser` class is now `UAParser\Parser` 29 | * Typed result objects: `Parser::parse()` returns `UAParser\Result\Client`, `Client::$os` is a `UAParser\Result\OperatingSystem` and `Client::$device` is a `UAParser\Result\Device` 30 | * `toString()` and `toVersion()` are now methods 31 | * Properties now use camelCase, not underscore_case. 32 | - Use Travis for CI 33 | - Update README 34 | - Port command line tool to Symfony CLI 35 | - Secure updating: SSL certificate verification, hashing, try to do atomic updates 36 | - Restore fetching YAML file only (without generating JSON) 37 | 38 | ## 2.1.1 39 | - FIX: making sure patch minor is being populated correctly when showing a mismatch 40 | 41 | ## 2.1.0 42 | - ADD: support for custom regexes.json files (via @pravindahal) 43 | - FIX: formerly private vars/functions are now protected (via @pravindahal) 44 | - FIX: command line tool gets 'pretty' option for PHP 5.4 users (via @skyzyx) 45 | - FIX: refactored the regexes.yaml test suite 46 | - FIX: now check to see if allow_url_fopen is set to 'On' before trying to download the YAML file from the command line 47 | - THX: thanks to @pravindahal and @skyzyx for the pull requests 48 | 49 | ## 2.0.1 50 | - FIX: renamed uaParser, osParser, & deviceParser to uaParse, osParse, & deviceParse to address a bug with uaParser being recognized as the contruct function for the overall lib 51 | - FIX: updated the test lib so that device failures are properly formatted 52 | 53 | ## 2.0.0 54 | - Summary: 55 | * the `UAParser` class is now dynamic 56 | * properties are nested _(e.g. $result->family is now $result->ua->family)_ 57 | * a user agent string is now required when using `parse()`. the auto-magical "use the server provided UA" is no longer supported. 58 | * `uaParse()`, `osParse()`, and `deviceParse()` are public and can be used to just return those select bits for a given user agent string. 59 | * the `is*` boolean properties _(e.g. isMobile)_ have been dropped. they now exist as part of the `ua-classifier` project. 60 | - ADD: toString() converts the version bits and family into a simple string 61 | - ADD: toVersionString() converts the version bits into a simple string 62 | - ADD: toFullString() combines the UA and OS family and version bits 63 | - ADD: "convert" flag for uaparser-cli.php 64 | - ADD: "pull & save just regexes.yaml" flag for uaparser-cli.php 65 | - FIX: library is now a dynamic class 66 | - FIX: attributes are now nested & populated like the other ua-parser libraries (e.g. $result->family is now $result->ua->family) 67 | - FIX: uaParser(), osParser(), and deviceParser() are now public functions 68 | - FIX: saves regexes.yaml as JSON for better performance 69 | - FIX: removed the __DIR__ "fix" 70 | - FIX: Apache log parsing now returns results when UA or OS families are set to "Other" and the device is listed as a smartphone or generic feature phone 71 | - FIX: all tabs are now spaces 72 | - FIX: a UA is now run against all three parsers 73 | - FIX: renamed $debug var to $log to better reflect what it does 74 | - DEL: is* boolean attributes (e.g. isMobile) have been removed 75 | - DEL: will no longer auto-parse $_SERVER['HTTP_USER_AGENT'] if available 76 | - DEL: tests no longer run against pgts_browser_list.yaml 77 | - THX: thanks to @rjd22 for the dynamic class code/fix 78 | 79 | ## 1.5.0 80 | - ADD: command line interface is now in its own file (via @Synchro) 81 | - ADD: command line utility now supports parsing an Apache log file & recording the results 82 | - ADD: command line utility can now parse a supplied user-agent string and push out a simple list or JSON 83 | - ADD: test suite that uses the ua-parser project's test resources 84 | - FIX: numerous comment & spacing fixes (via @Synchro & @Krinkle) 85 | - FIX: remove PHP4 version of spyc (via @Synchro) 86 | - FIX: remove .svn dirs in spyc (via @lopezdonaque) 87 | - FIX: notes that the PHP 5.2 fix really was for 5.1 (via @Synchro) (knew this, i was lazy) 88 | - FIX: lib now returns an object no matter what. now matches other ua-parser libs (via @Krinkle) 89 | - FIX: checks that $_SERVER attr is set before including it. should be better for command line use. 90 | - FIX: family attr now properly set in an edge case 91 | - FIX: if regexes.yaml picks up bad slashes the PHP lib will account for it (e.g. GoogleTV regex) 92 | - THX: thanks to @Krinkle and @Synchro for the numerous fixes 93 | 94 | ## 1.4.5 95 | - FIX: an embarrassing debug print survived the last edit 96 | - THX: thanks to @memakeit for dropping the bug report 97 | 98 | ## 1.4.4 99 | - FIX: made sure that the regex file is only loaded once if running the library multiple times. performance boost. 100 | - FIX: added support for identifying various game devices as mobile devices 101 | - THX: thanks to @rjd22 for pointing out the perf issue 102 | 103 | ## 1.4.3 104 | - FIX: added support for patch & family attributes to sort of match the other libraries 105 | 106 | ## 1.4.2 107 | - FIX: notice if regexes.yaml is missing parens (e.g. match $1) for device & os names 108 | 109 | ## 1.4.1 110 | - FIX: notice when using UAParser from the command line 111 | 112 | ## 1.4.0 113 | - ADD: silent mode for the UA::get() method 114 | - ADD: nobackup mode for the UA::get() method 115 | - ADD: example of how to do a redirect with ua-parser-php 116 | - The following were changes to regexes.yaml: 117 | * ADD: support for Google Earth browser 118 | * ADD: another regex for Firefox Mobile 119 | * ADD: support for Firefox Alpha builds 120 | * ADD: support for Sogou Explorer 121 | * ADD: support for the Raven for Mac browser 122 | * ADD: support for WebKit Nightly builds (though slightly pointless) 123 | * FIX: better pattern matching for the Pale Moon browser 124 | 125 | ## 1.3.2 126 | - FIX: addressed false "tablet" classification for opera mobile & mini on android 127 | - The following were changes to regexes.yaml: 128 | * ADD: support for Tizen Browser (aka SLP Browser) from Samsung 129 | * FIX: support for a new look Polaris 8.0 user agent string 130 | * FIX: modified where the Epiphany Browser check happens 131 | 132 | ## 1.3.1 133 | - FIX: now doing some sanity cleaning on the user agent strings 134 | - FIX: added a smarter default if the user agent isn't recognized at all 135 | 136 | ## 1.3.0 137 | - FIX: now points to Tobie's ua-parser project for the latest greatest YAML file 138 | - FIX: YAML file is now standardized as regexes.yaml instead of user_agents_regex.yaml 139 | - FIX: minor NOTICE issues resolved for very select UAs 140 | 141 | ## 1.2.2 142 | - The following were changes to user_agents_regex.yaml: 143 | * ADD: support for UC Browser 144 | 145 | ## 1.2.1 146 | - The following were changes to user_agents_regex.yaml: 147 | * ADD: support for android 4 user agents that have a dash in them 148 | 149 | ## 1.2.0 150 | - FIX: should be compatible with PHP 5.2 151 | - FIX: addressed STRICT mode errors 152 | - FIX: addressed NOTICE for a missing variable 153 | - FIX: if isTablet is set to true then isMobile is set to false (mobile to me means phone) 154 | - THX: Thanks to Mike Bond of WVU Libraries for pointing out the 5.2 incompatibility 155 | 156 | ## 1.1.0 157 | - FIX: a number of fixes from bryan shelton 158 | - The following were changes to user_agents_regex.yaml: 159 | * ADD: support for Chrome Mobile 160 | 161 | ## 1.0.0 162 | - just because i don't expect to update this anytime soon and ppl report it's working 163 | 164 | ## 0.3.1 165 | - FIX: swapped nil for null in parse() 166 | - FIX: smarter/saner defaults 167 | - FIX: now using isset() for family_replacement 168 | - THX: thanks to bryan shelton for these fixes 169 | 170 | ## 0.3.0 171 | - ADD: can now supply a specific UA to be checked 172 | - ADD: if the UA contains 'tablet' isTablet is marked true 173 | - ADD: for certain mobile OSs they report a desktop browser. marking them mobile now. 174 | - FIX: tablet listing should now be better 175 | - FIX: the list of mobile browsers was updated 176 | - FIX: made sure that certain checks won't fail as "false" if a version number was a 0 177 | - FIX: for the device check, if it returns spider as a result it no longer marks it as mobile 178 | - FIX: added more mobile browsers to that specific check 179 | - The following were changes to user_agents_regex.yaml: 180 | * ADD: symphony, minimo, teleca, semc, up.browser, bunjaloo, jasmine, & brew browsers supported 181 | * ADD: windows mobile 6.5 os support 182 | * ADD: amoi, asus, bird, dell, docomo, huawei, i-mate, kyocera, lenovo, lg, microsoft kind, 183 | motorola, philips, samsung, softbank, & sony ericsson device checks 184 | * FIX: mobile firefox, opera mobile & mini, obigo, polaris, nokiabrowser, ie mobile, 185 | android, & mobile safari browser checks 186 | * FIX: iOS support 187 | * FIX: htc, android, palm/hp, kindle, ios, generic feature phones & spider device checks 188 | 189 | ## 0.2.0 190 | - ADD: added isMobile support 191 | - ADD: added isTablet support 192 | - ADD: added isComputer support 193 | - ADD: added isSpider support 194 | 195 | ## 0.1.0 196 | - The following were changes to user_agents_regex.yaml: 197 | * expanded support for Symbia & Nokia Devices, 198 | * cleaned up some slashies, 199 | * added Mobile Safari as the family replacement for iOS devices, 200 | * better support for longer HTC device names 201 | * added feature phones to the device check 202 | * added generic smartphones to the device check 203 | * added AvantGo to the ua check 204 | * tweaked a lot of the nokia checks 205 | * added kindle support to the device section 206 | * added a generic catch for android devices. 207 | * added support for blackberry devices 208 | * changed the blackberry family to 'blackberry webkit' when it's a webkit browser 209 | -------------------------------------------------------------------------------- /vendor/composer/ClassLoader.php: -------------------------------------------------------------------------------- 1 | 7 | * Jordi Boggiano 8 | * 9 | * For the full copyright and license information, please view the LICENSE 10 | * file that was distributed with this source code. 11 | */ 12 | 13 | namespace Composer\Autoload; 14 | 15 | /** 16 | * ClassLoader implements a PSR-0, PSR-4 and classmap class loader. 17 | * 18 | * $loader = new \Composer\Autoload\ClassLoader(); 19 | * 20 | * // register classes with namespaces 21 | * $loader->add('Symfony\Component', __DIR__.'/component'); 22 | * $loader->add('Symfony', __DIR__.'/framework'); 23 | * 24 | * // activate the autoloader 25 | * $loader->register(); 26 | * 27 | * // to enable searching the include path (eg. for PEAR packages) 28 | * $loader->setUseIncludePath(true); 29 | * 30 | * In this example, if you try to use a class in the Symfony\Component 31 | * namespace or one of its children (Symfony\Component\Console for instance), 32 | * the autoloader will first look for the class under the component/ 33 | * directory, and it will then fallback to the framework/ directory if not 34 | * found before giving up. 35 | * 36 | * This class is loosely based on the Symfony UniversalClassLoader. 37 | * 38 | * @author Fabien Potencier 39 | * @author Jordi Boggiano 40 | * @see http://www.php-fig.org/psr/psr-0/ 41 | * @see http://www.php-fig.org/psr/psr-4/ 42 | */ 43 | class ClassLoader 44 | { 45 | // PSR-4 46 | private $prefixLengthsPsr4 = array(); 47 | private $prefixDirsPsr4 = array(); 48 | private $fallbackDirsPsr4 = array(); 49 | 50 | // PSR-0 51 | private $prefixesPsr0 = array(); 52 | private $fallbackDirsPsr0 = array(); 53 | 54 | private $useIncludePath = false; 55 | private $classMap = array(); 56 | private $classMapAuthoritative = false; 57 | private $missingClasses = array(); 58 | private $apcuPrefix; 59 | 60 | public function getPrefixes() 61 | { 62 | if (!empty($this->prefixesPsr0)) { 63 | return call_user_func_array('array_merge', $this->prefixesPsr0); 64 | } 65 | 66 | return array(); 67 | } 68 | 69 | public function getPrefixesPsr4() 70 | { 71 | return $this->prefixDirsPsr4; 72 | } 73 | 74 | public function getFallbackDirs() 75 | { 76 | return $this->fallbackDirsPsr0; 77 | } 78 | 79 | public function getFallbackDirsPsr4() 80 | { 81 | return $this->fallbackDirsPsr4; 82 | } 83 | 84 | public function getClassMap() 85 | { 86 | return $this->classMap; 87 | } 88 | 89 | /** 90 | * @param array $classMap Class to filename map 91 | */ 92 | public function addClassMap(array $classMap) 93 | { 94 | if ($this->classMap) { 95 | $this->classMap = array_merge($this->classMap, $classMap); 96 | } else { 97 | $this->classMap = $classMap; 98 | } 99 | } 100 | 101 | /** 102 | * Registers a set of PSR-0 directories for a given prefix, either 103 | * appending or prepending to the ones previously set for this prefix. 104 | * 105 | * @param string $prefix The prefix 106 | * @param array|string $paths The PSR-0 root directories 107 | * @param bool $prepend Whether to prepend the directories 108 | */ 109 | public function add($prefix, $paths, $prepend = false) 110 | { 111 | if (!$prefix) { 112 | if ($prepend) { 113 | $this->fallbackDirsPsr0 = array_merge( 114 | (array) $paths, 115 | $this->fallbackDirsPsr0 116 | ); 117 | } else { 118 | $this->fallbackDirsPsr0 = array_merge( 119 | $this->fallbackDirsPsr0, 120 | (array) $paths 121 | ); 122 | } 123 | 124 | return; 125 | } 126 | 127 | $first = $prefix[0]; 128 | if (!isset($this->prefixesPsr0[$first][$prefix])) { 129 | $this->prefixesPsr0[$first][$prefix] = (array) $paths; 130 | 131 | return; 132 | } 133 | if ($prepend) { 134 | $this->prefixesPsr0[$first][$prefix] = array_merge( 135 | (array) $paths, 136 | $this->prefixesPsr0[$first][$prefix] 137 | ); 138 | } else { 139 | $this->prefixesPsr0[$first][$prefix] = array_merge( 140 | $this->prefixesPsr0[$first][$prefix], 141 | (array) $paths 142 | ); 143 | } 144 | } 145 | 146 | /** 147 | * Registers a set of PSR-4 directories for a given namespace, either 148 | * appending or prepending to the ones previously set for this namespace. 149 | * 150 | * @param string $prefix The prefix/namespace, with trailing '\\' 151 | * @param array|string $paths The PSR-4 base directories 152 | * @param bool $prepend Whether to prepend the directories 153 | * 154 | * @throws \InvalidArgumentException 155 | */ 156 | public function addPsr4($prefix, $paths, $prepend = false) 157 | { 158 | if (!$prefix) { 159 | // Register directories for the root namespace. 160 | if ($prepend) { 161 | $this->fallbackDirsPsr4 = array_merge( 162 | (array) $paths, 163 | $this->fallbackDirsPsr4 164 | ); 165 | } else { 166 | $this->fallbackDirsPsr4 = array_merge( 167 | $this->fallbackDirsPsr4, 168 | (array) $paths 169 | ); 170 | } 171 | } elseif (!isset($this->prefixDirsPsr4[$prefix])) { 172 | // Register directories for a new namespace. 173 | $length = strlen($prefix); 174 | if ('\\' !== $prefix[$length - 1]) { 175 | throw new \InvalidArgumentException("A non-empty PSR-4 prefix must end with a namespace separator."); 176 | } 177 | $this->prefixLengthsPsr4[$prefix[0]][$prefix] = $length; 178 | $this->prefixDirsPsr4[$prefix] = (array) $paths; 179 | } elseif ($prepend) { 180 | // Prepend directories for an already registered namespace. 181 | $this->prefixDirsPsr4[$prefix] = array_merge( 182 | (array) $paths, 183 | $this->prefixDirsPsr4[$prefix] 184 | ); 185 | } else { 186 | // Append directories for an already registered namespace. 187 | $this->prefixDirsPsr4[$prefix] = array_merge( 188 | $this->prefixDirsPsr4[$prefix], 189 | (array) $paths 190 | ); 191 | } 192 | } 193 | 194 | /** 195 | * Registers a set of PSR-0 directories for a given prefix, 196 | * replacing any others previously set for this prefix. 197 | * 198 | * @param string $prefix The prefix 199 | * @param array|string $paths The PSR-0 base directories 200 | */ 201 | public function set($prefix, $paths) 202 | { 203 | if (!$prefix) { 204 | $this->fallbackDirsPsr0 = (array) $paths; 205 | } else { 206 | $this->prefixesPsr0[$prefix[0]][$prefix] = (array) $paths; 207 | } 208 | } 209 | 210 | /** 211 | * Registers a set of PSR-4 directories for a given namespace, 212 | * replacing any others previously set for this namespace. 213 | * 214 | * @param string $prefix The prefix/namespace, with trailing '\\' 215 | * @param array|string $paths The PSR-4 base directories 216 | * 217 | * @throws \InvalidArgumentException 218 | */ 219 | public function setPsr4($prefix, $paths) 220 | { 221 | if (!$prefix) { 222 | $this->fallbackDirsPsr4 = (array) $paths; 223 | } else { 224 | $length = strlen($prefix); 225 | if ('\\' !== $prefix[$length - 1]) { 226 | throw new \InvalidArgumentException("A non-empty PSR-4 prefix must end with a namespace separator."); 227 | } 228 | $this->prefixLengthsPsr4[$prefix[0]][$prefix] = $length; 229 | $this->prefixDirsPsr4[$prefix] = (array) $paths; 230 | } 231 | } 232 | 233 | /** 234 | * Turns on searching the include path for class files. 235 | * 236 | * @param bool $useIncludePath 237 | */ 238 | public function setUseIncludePath($useIncludePath) 239 | { 240 | $this->useIncludePath = $useIncludePath; 241 | } 242 | 243 | /** 244 | * Can be used to check if the autoloader uses the include path to check 245 | * for classes. 246 | * 247 | * @return bool 248 | */ 249 | public function getUseIncludePath() 250 | { 251 | return $this->useIncludePath; 252 | } 253 | 254 | /** 255 | * Turns off searching the prefix and fallback directories for classes 256 | * that have not been registered with the class map. 257 | * 258 | * @param bool $classMapAuthoritative 259 | */ 260 | public function setClassMapAuthoritative($classMapAuthoritative) 261 | { 262 | $this->classMapAuthoritative = $classMapAuthoritative; 263 | } 264 | 265 | /** 266 | * Should class lookup fail if not found in the current class map? 267 | * 268 | * @return bool 269 | */ 270 | public function isClassMapAuthoritative() 271 | { 272 | return $this->classMapAuthoritative; 273 | } 274 | 275 | /** 276 | * APCu prefix to use to cache found/not-found classes, if the extension is enabled. 277 | * 278 | * @param string|null $apcuPrefix 279 | */ 280 | public function setApcuPrefix($apcuPrefix) 281 | { 282 | $this->apcuPrefix = function_exists('apcu_fetch') && filter_var(ini_get('apc.enabled'), FILTER_VALIDATE_BOOLEAN) ? $apcuPrefix : null; 283 | } 284 | 285 | /** 286 | * The APCu prefix in use, or null if APCu caching is not enabled. 287 | * 288 | * @return string|null 289 | */ 290 | public function getApcuPrefix() 291 | { 292 | return $this->apcuPrefix; 293 | } 294 | 295 | /** 296 | * Registers this instance as an autoloader. 297 | * 298 | * @param bool $prepend Whether to prepend the autoloader or not 299 | */ 300 | public function register($prepend = false) 301 | { 302 | spl_autoload_register(array($this, 'loadClass'), true, $prepend); 303 | } 304 | 305 | /** 306 | * Unregisters this instance as an autoloader. 307 | */ 308 | public function unregister() 309 | { 310 | spl_autoload_unregister(array($this, 'loadClass')); 311 | } 312 | 313 | /** 314 | * Loads the given class or interface. 315 | * 316 | * @param string $class The name of the class 317 | * @return bool|null True if loaded, null otherwise 318 | */ 319 | public function loadClass($class) 320 | { 321 | if ($file = $this->findFile($class)) { 322 | includeFile($file); 323 | 324 | return true; 325 | } 326 | } 327 | 328 | /** 329 | * Finds the path to the file where the class is defined. 330 | * 331 | * @param string $class The name of the class 332 | * 333 | * @return string|false The path if found, false otherwise 334 | */ 335 | public function findFile($class) 336 | { 337 | // class map lookup 338 | if (isset($this->classMap[$class])) { 339 | return $this->classMap[$class]; 340 | } 341 | if ($this->classMapAuthoritative || isset($this->missingClasses[$class])) { 342 | return false; 343 | } 344 | if (null !== $this->apcuPrefix) { 345 | $file = apcu_fetch($this->apcuPrefix.$class, $hit); 346 | if ($hit) { 347 | return $file; 348 | } 349 | } 350 | 351 | $file = $this->findFileWithExtension($class, '.php'); 352 | 353 | // Search for Hack files if we are running on HHVM 354 | if (false === $file && defined('HHVM_VERSION')) { 355 | $file = $this->findFileWithExtension($class, '.hh'); 356 | } 357 | 358 | if (null !== $this->apcuPrefix) { 359 | apcu_add($this->apcuPrefix.$class, $file); 360 | } 361 | 362 | if (false === $file) { 363 | // Remember that this class does not exist. 364 | $this->missingClasses[$class] = true; 365 | } 366 | 367 | return $file; 368 | } 369 | 370 | private function findFileWithExtension($class, $ext) 371 | { 372 | // PSR-4 lookup 373 | $logicalPathPsr4 = strtr($class, '\\', DIRECTORY_SEPARATOR) . $ext; 374 | 375 | $first = $class[0]; 376 | if (isset($this->prefixLengthsPsr4[$first])) { 377 | $subPath = $class; 378 | while (false !== $lastPos = strrpos($subPath, '\\')) { 379 | $subPath = substr($subPath, 0, $lastPos); 380 | $search = $subPath . '\\'; 381 | if (isset($this->prefixDirsPsr4[$search])) { 382 | $pathEnd = DIRECTORY_SEPARATOR . substr($logicalPathPsr4, $lastPos + 1); 383 | foreach ($this->prefixDirsPsr4[$search] as $dir) { 384 | if (file_exists($file = $dir . $pathEnd)) { 385 | return $file; 386 | } 387 | } 388 | } 389 | } 390 | } 391 | 392 | // PSR-4 fallback dirs 393 | foreach ($this->fallbackDirsPsr4 as $dir) { 394 | if (file_exists($file = $dir . DIRECTORY_SEPARATOR . $logicalPathPsr4)) { 395 | return $file; 396 | } 397 | } 398 | 399 | // PSR-0 lookup 400 | if (false !== $pos = strrpos($class, '\\')) { 401 | // namespaced class name 402 | $logicalPathPsr0 = substr($logicalPathPsr4, 0, $pos + 1) 403 | . strtr(substr($logicalPathPsr4, $pos + 1), '_', DIRECTORY_SEPARATOR); 404 | } else { 405 | // PEAR-like class name 406 | $logicalPathPsr0 = strtr($class, '_', DIRECTORY_SEPARATOR) . $ext; 407 | } 408 | 409 | if (isset($this->prefixesPsr0[$first])) { 410 | foreach ($this->prefixesPsr0[$first] as $prefix => $dirs) { 411 | if (0 === strpos($class, $prefix)) { 412 | foreach ($dirs as $dir) { 413 | if (file_exists($file = $dir . DIRECTORY_SEPARATOR . $logicalPathPsr0)) { 414 | return $file; 415 | } 416 | } 417 | } 418 | } 419 | } 420 | 421 | // PSR-0 fallback dirs 422 | foreach ($this->fallbackDirsPsr0 as $dir) { 423 | if (file_exists($file = $dir . DIRECTORY_SEPARATOR . $logicalPathPsr0)) { 424 | return $file; 425 | } 426 | } 427 | 428 | // PSR-0 include paths. 429 | if ($this->useIncludePath && $file = stream_resolve_include_path($logicalPathPsr0)) { 430 | return $file; 431 | } 432 | 433 | return false; 434 | } 435 | } 436 | 437 | /** 438 | * Scope isolated include. 439 | * 440 | * Prevents access to $this/self from included files. 441 | */ 442 | function includeFile($file) 443 | { 444 | include $file; 445 | } 446 | -------------------------------------------------------------------------------- /vendor/composer/ca-bundle/src/CaBundle.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * For the full copyright and license information, please view 9 | * the LICENSE file that was distributed with this source code. 10 | */ 11 | 12 | namespace Composer\CaBundle; 13 | 14 | use Psr\Log\LoggerInterface; 15 | use Symfony\Component\Process\PhpProcess; 16 | 17 | /** 18 | * @author Chris Smith 19 | * @author Jordi Boggiano 20 | */ 21 | class CaBundle 22 | { 23 | private static $caPath; 24 | private static $caFileValidity = array(); 25 | private static $useOpensslParse; 26 | 27 | /** 28 | * Returns the system CA bundle path, or a path to the bundled one 29 | * 30 | * This method was adapted from Sslurp. 31 | * https://github.com/EvanDotPro/Sslurp 32 | * 33 | * (c) Evan Coury 34 | * 35 | * For the full copyright and license information, please see below: 36 | * 37 | * Copyright (c) 2013, Evan Coury 38 | * All rights reserved. 39 | * 40 | * Redistribution and use in source and binary forms, with or without modification, 41 | * are permitted provided that the following conditions are met: 42 | * 43 | * * Redistributions of source code must retain the above copyright notice, 44 | * this list of conditions and the following disclaimer. 45 | * 46 | * * Redistributions in binary form must reproduce the above copyright notice, 47 | * this list of conditions and the following disclaimer in the documentation 48 | * and/or other materials provided with the distribution. 49 | * 50 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 51 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 52 | * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 53 | * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR 54 | * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 55 | * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 56 | * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON 57 | * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 58 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 59 | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 60 | * 61 | * @param LoggerInterface $logger optional logger for information about which CA files were loaded 62 | * @return string path to a CA bundle file or directory 63 | */ 64 | public static function getSystemCaRootBundlePath(LoggerInterface $logger = null) 65 | { 66 | if (self::$caPath !== null) { 67 | return self::$caPath; 68 | } 69 | $caBundlePaths = array(); 70 | 71 | 72 | // If SSL_CERT_FILE env variable points to a valid certificate/bundle, use that. 73 | // This mimics how OpenSSL uses the SSL_CERT_FILE env variable. 74 | $caBundlePaths[] = self::getEnvVariable('SSL_CERT_FILE'); 75 | 76 | // If SSL_CERT_DIR env variable points to a valid certificate/bundle, use that. 77 | // This mimics how OpenSSL uses the SSL_CERT_FILE env variable. 78 | $caBundlePaths[] = self::getEnvVariable('SSL_CERT_DIR'); 79 | 80 | $caBundlePaths[] = ini_get('openssl.cafile'); 81 | $caBundlePaths[] = ini_get('openssl.capath'); 82 | 83 | $otherLocations = array( 84 | '/etc/pki/tls/certs/ca-bundle.crt', // Fedora, RHEL, CentOS (ca-certificates package) 85 | '/etc/ssl/certs/ca-certificates.crt', // Debian, Ubuntu, Gentoo, Arch Linux (ca-certificates package) 86 | '/etc/ssl/ca-bundle.pem', // SUSE, openSUSE (ca-certificates package) 87 | '/usr/local/share/certs/ca-root-nss.crt', // FreeBSD (ca_root_nss_package) 88 | '/usr/ssl/certs/ca-bundle.crt', // Cygwin 89 | '/opt/local/share/curl/curl-ca-bundle.crt', // OS X macports, curl-ca-bundle package 90 | '/usr/local/share/curl/curl-ca-bundle.crt', // Default cURL CA bunde path (without --with-ca-bundle option) 91 | '/usr/share/ssl/certs/ca-bundle.crt', // Really old RedHat? 92 | '/etc/ssl/cert.pem', // OpenBSD 93 | '/usr/local/etc/ssl/cert.pem', // FreeBSD 10.x 94 | '/usr/local/etc/openssl/cert.pem', // OS X homebrew, openssl package 95 | '/usr/local/etc/openssl@1.1/cert.pem', // OS X homebrew, openssl@1.1 package 96 | ); 97 | 98 | foreach($otherLocations as $location) { 99 | $otherLocations[] = dirname($location); 100 | } 101 | 102 | $caBundlePaths = array_merge($caBundlePaths, $otherLocations); 103 | 104 | foreach ($caBundlePaths as $caBundle) { 105 | if (self::caFileUsable($caBundle, $logger)) { 106 | return self::$caPath = $caBundle; 107 | } 108 | 109 | if (self::caDirUsable($caBundle)) { 110 | return self::$caPath = $caBundle; 111 | } 112 | } 113 | 114 | return self::$caPath = static::getBundledCaBundlePath(); // Bundled CA file, last resort 115 | } 116 | 117 | /** 118 | * Returns the path to the bundled CA file 119 | * 120 | * In case you don't want to trust the user or the system, you can use this directly 121 | * 122 | * @return string path to a CA bundle file 123 | */ 124 | public static function getBundledCaBundlePath() 125 | { 126 | $caBundleFile = __DIR__.'/../res/cacert.pem'; 127 | 128 | // cURL does not understand 'phar://' paths 129 | // see https://github.com/composer/ca-bundle/issues/10 130 | if (0 === strpos($caBundleFile, 'phar://')) { 131 | file_put_contents( 132 | $tempCaBundleFile = tempnam(sys_get_temp_dir(), 'openssl-ca-bundle-'), 133 | file_get_contents($caBundleFile) 134 | ); 135 | 136 | register_shutdown_function(function() use ($tempCaBundleFile) { 137 | @unlink($tempCaBundleFile); 138 | }); 139 | 140 | $caBundleFile = $tempCaBundleFile; 141 | } 142 | 143 | return $caBundleFile; 144 | } 145 | 146 | /** 147 | * Validates a CA file using opensl_x509_parse only if it is safe to use 148 | * 149 | * @param string $filename 150 | * @param LoggerInterface $logger optional logger for information about which CA files were loaded 151 | * 152 | * @return bool 153 | */ 154 | public static function validateCaFile($filename, LoggerInterface $logger = null) 155 | { 156 | static $warned = false; 157 | 158 | if (isset(self::$caFileValidity[$filename])) { 159 | return self::$caFileValidity[$filename]; 160 | } 161 | 162 | $contents = file_get_contents($filename); 163 | 164 | // assume the CA is valid if php is vulnerable to 165 | // https://www.sektioneins.de/advisories/advisory-012013-php-openssl_x509_parse-memory-corruption-vulnerability.html 166 | if (!static::isOpensslParseSafe()) { 167 | if (!$warned && $logger) { 168 | $logger->warning(sprintf( 169 | 'Your version of PHP, %s, is affected by CVE-2013-6420 and cannot safely perform certificate validation, we strongly suggest you upgrade.', 170 | PHP_VERSION 171 | )); 172 | $warned = true; 173 | } 174 | 175 | $isValid = !empty($contents); 176 | } else { 177 | $isValid = (bool) openssl_x509_parse($contents); 178 | } 179 | 180 | if ($logger) { 181 | $logger->debug('Checked CA file '.realpath($filename).': '.($isValid ? 'valid' : 'invalid')); 182 | } 183 | 184 | return self::$caFileValidity[$filename] = $isValid; 185 | } 186 | 187 | /** 188 | * Test if it is safe to use the PHP function openssl_x509_parse(). 189 | * 190 | * This checks if OpenSSL extensions is vulnerable to remote code execution 191 | * via the exploit documented as CVE-2013-6420. 192 | * 193 | * @return bool 194 | */ 195 | public static function isOpensslParseSafe() 196 | { 197 | if (null !== self::$useOpensslParse) { 198 | return self::$useOpensslParse; 199 | } 200 | 201 | if (PHP_VERSION_ID >= 50600) { 202 | return self::$useOpensslParse = true; 203 | } 204 | 205 | // Vulnerable: 206 | // PHP 5.3.0 - PHP 5.3.27 207 | // PHP 5.4.0 - PHP 5.4.22 208 | // PHP 5.5.0 - PHP 5.5.6 209 | if ( 210 | (PHP_VERSION_ID < 50400 && PHP_VERSION_ID >= 50328) 211 | || (PHP_VERSION_ID < 50500 && PHP_VERSION_ID >= 50423) 212 | || (PHP_VERSION_ID < 50600 && PHP_VERSION_ID >= 50507) 213 | ) { 214 | // This version of PHP has the fix for CVE-2013-6420 applied. 215 | return self::$useOpensslParse = true; 216 | } 217 | 218 | if (defined('PHP_WINDOWS_VERSION_BUILD')) { 219 | // Windows is probably insecure in this case. 220 | return self::$useOpensslParse = false; 221 | } 222 | 223 | $compareDistroVersionPrefix = function ($prefix, $fixedVersion) { 224 | $regex = '{^'.preg_quote($prefix).'([0-9]+)$}'; 225 | 226 | if (preg_match($regex, PHP_VERSION, $m)) { 227 | return ((int) $m[1]) >= $fixedVersion; 228 | } 229 | 230 | return false; 231 | }; 232 | 233 | // Hard coded list of PHP distributions with the fix backported. 234 | if ( 235 | $compareDistroVersionPrefix('5.3.3-7+squeeze', 18) // Debian 6 (Squeeze) 236 | || $compareDistroVersionPrefix('5.4.4-14+deb7u', 7) // Debian 7 (Wheezy) 237 | || $compareDistroVersionPrefix('5.3.10-1ubuntu3.', 9) // Ubuntu 12.04 (Precise) 238 | ) { 239 | return self::$useOpensslParse = true; 240 | } 241 | 242 | // Symfony Process component is missing so we assume it is unsafe at this point 243 | if (!class_exists('Symfony\Component\Process\PhpProcess')) { 244 | return self::$useOpensslParse = false; 245 | } 246 | 247 | // This is where things get crazy, because distros backport security 248 | // fixes the chances are on NIX systems the fix has been applied but 249 | // it's not possible to verify that from the PHP version. 250 | // 251 | // To verify exec a new PHP process and run the issue testcase with 252 | // known safe input that replicates the bug. 253 | 254 | // Based on testcase in https://github.com/php/php-src/commit/c1224573c773b6845e83505f717fbf820fc18415 255 | // changes in https://github.com/php/php-src/commit/76a7fd893b7d6101300cc656058704a73254d593 256 | $cert = 'LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUVwRENDQTR5Z0F3SUJBZ0lKQUp6dThyNnU2ZUJjTUEwR0NTcUdTSWIzRFFFQkJRVUFNSUhETVFzd0NRWUQKVlFRR0V3SkVSVEVjTUJvR0ExVUVDQXdUVG05eVpISm9aV2x1TFZkbGMzUm1ZV3hsYmpFUU1BNEdBMVVFQnd3SApTOE9Ed3Jac2JqRVVNQklHQTFVRUNnd0xVMlZyZEdsdmJrVnBibk14SHpBZEJnTlZCQXNNRmsxaGJHbGphVzkxCmN5QkRaWEowSUZObFkzUnBiMjR4SVRBZkJnTlZCQU1NR0cxaGJHbGphVzkxY3k1elpXdDBhVzl1WldsdWN5NWsKWlRFcU1DZ0dDU3FHU0liM0RRRUpBUlliYzNSbFptRnVMbVZ6YzJWeVFITmxhM1JwYjI1bGFXNXpMbVJsTUhVWQpaREU1TnpBd01UQXhNREF3TURBd1dnQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBCkFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUEKQUFBQUFBQVhEVEUwTVRFeU9ERXhNemt6TlZvd2djTXhDekFKQmdOVkJBWVRBa1JGTVJ3d0dnWURWUVFJREJOTwpiM0prY21obGFXNHRWMlZ6ZEdaaGJHVnVNUkF3RGdZRFZRUUhEQWRMdzRQQ3RteHVNUlF3RWdZRFZRUUtEQXRUClpXdDBhVzl1UldsdWN6RWZNQjBHQTFVRUN3d1dUV0ZzYVdOcGIzVnpJRU5sY25RZ1UyVmpkR2x2YmpFaE1COEcKQTFVRUF3d1liV0ZzYVdOcGIzVnpMbk5sYTNScGIyNWxhVzV6TG1SbE1Tb3dLQVlKS29aSWh2Y05BUWtCRmh0egpkR1ZtWVc0dVpYTnpaWEpBYzJWcmRHbHZibVZwYm5NdVpHVXdnZ0VpTUEwR0NTcUdTSWIzRFFFQkFRVUFBNElCCkR3QXdnZ0VLQW9JQkFRRERBZjNobDdKWTBYY0ZuaXlFSnBTU0RxbjBPcUJyNlFQNjV1c0pQUnQvOFBhRG9xQnUKd0VZVC9OYSs2ZnNnUGpDMHVLOURaZ1dnMnRIV1dvYW5TYmxBTW96NVBINlorUzRTSFJaN2UyZERJalBqZGhqaAowbUxnMlVNTzV5cDBWNzk3R2dzOWxOdDZKUmZIODFNTjJvYlhXczROdHp0TE11RDZlZ3FwcjhkRGJyMzRhT3M4CnBrZHVpNVVhd1Raa3N5NXBMUEhxNWNNaEZHbTA2djY1Q0xvMFYyUGQ5K0tBb2tQclBjTjVLTEtlYno3bUxwazYKU01lRVhPS1A0aWRFcXh5UTdPN2ZCdUhNZWRzUWh1K3ByWTNzaTNCVXlLZlF0UDVDWm5YMmJwMHdLSHhYMTJEWAoxbmZGSXQ5RGJHdkhUY3lPdU4rblpMUEJtM3ZXeG50eUlJdlZBZ01CQUFHalFqQkFNQWtHQTFVZEV3UUNNQUF3CkVRWUpZSVpJQVliNFFnRUJCQVFEQWdlQU1Bc0dBMVVkRHdRRUF3SUZvREFUQmdOVkhTVUVEREFLQmdnckJnRUYKQlFjREFqQU5CZ2txaGtpRzl3MEJBUVVGQUFPQ0FRRUFHMGZaWVlDVGJkajFYWWMrMVNub2FQUit2SThDOENhRAo4KzBVWWhkbnlVNGdnYTBCQWNEclk5ZTk0ZUVBdTZacXljRjZGakxxWFhkQWJvcHBXb2NyNlQ2R0QxeDMzQ2tsClZBcnpHL0t4UW9oR0QySmVxa2hJTWxEb214SE83a2EzOStPYThpMnZXTFZ5alU4QVp2V01BcnVIYTRFRU55RzcKbFcyQWFnYUZLRkNyOVRuWFRmcmR4R1ZFYnY3S1ZRNmJkaGc1cDVTanBXSDErTXEwM3VSM1pYUEJZZHlWODMxOQpvMGxWajFLRkkyRENML2xpV2lzSlJvb2YrMWNSMzVDdGQwd1lCY3BCNlRac2xNY09QbDc2ZHdLd0pnZUpvMlFnClpzZm1jMnZDMS9xT2xOdU5xLzBUenprVkd2OEVUVDNDZ2FVK1VYZTRYT1Z2a2NjZWJKbjJkZz09Ci0tLS0tRU5EIENFUlRJRklDQVRFLS0tLS0K'; 257 | $script = <<<'EOT' 258 | 259 | error_reporting(-1); 260 | $info = openssl_x509_parse(base64_decode('%s')); 261 | var_dump(PHP_VERSION, $info['issuer']['emailAddress'], $info['validFrom_time_t']); 262 | 263 | EOT; 264 | $script = '<'."?php\n".sprintf($script, $cert); 265 | 266 | try { 267 | $process = new PhpProcess($script); 268 | $process->mustRun(); 269 | } catch (\Exception $e) { 270 | // In the case of any exceptions just accept it is not possible to 271 | // determine the safety of openssl_x509_parse and bail out. 272 | return self::$useOpensslParse = false; 273 | } 274 | 275 | $output = preg_split('{\r?\n}', trim($process->getOutput())); 276 | $errorOutput = trim($process->getErrorOutput()); 277 | 278 | if ( 279 | count($output) === 3 280 | && $output[0] === sprintf('string(%d) "%s"', strlen(PHP_VERSION), PHP_VERSION) 281 | && $output[1] === 'string(27) "stefan.esser@sektioneins.de"' 282 | && $output[2] === 'int(-1)' 283 | && preg_match('{openssl_x509_parse\(\): illegal (?:ASN1 data type for|length in) timestamp in - on line \d+}', $errorOutput) 284 | ) { 285 | // This PHP has the fix backported probably by a distro security team. 286 | return self::$useOpensslParse = true; 287 | } 288 | 289 | return self::$useOpensslParse = false; 290 | } 291 | 292 | /** 293 | * Resets the static caches 294 | */ 295 | public static function reset() 296 | { 297 | self::$caFileValidity = array(); 298 | self::$caPath = null; 299 | self::$useOpensslParse = null; 300 | } 301 | 302 | private static function getEnvVariable($name) 303 | { 304 | if (isset($_SERVER[$name])) { 305 | return (string) $_SERVER[$name]; 306 | } 307 | 308 | if (PHP_SAPI === 'cli' && ($value = getenv($name)) !== false && $value !== null) { 309 | return (string) $value; 310 | } 311 | 312 | return false; 313 | } 314 | 315 | private static function caFileUsable($certFile, LoggerInterface $logger = null) 316 | { 317 | return $certFile && @is_file($certFile) && @is_readable($certFile) && static::validateCaFile($certFile, $logger); 318 | } 319 | 320 | private static function caDirUsable($certDir) 321 | { 322 | return $certDir && @is_dir($certDir) && @is_readable($certDir) && glob($certDir . '/*'); 323 | } 324 | } 325 | --------------------------------------------------------------------------------