├── .gitignore ├── README.md ├── composer.json ├── examples ├── multi_request.php ├── multi_request_2.php ├── request_with_cache.php └── simple.php └── src ├── Cache.php ├── GHttp.php ├── MethodNotFoundException.php └── MultiRequest.php /.gitignore: -------------------------------------------------------------------------------- 1 | .idea 2 | /vendor/ 3 | composer.lock 4 | examples/.cache -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # GHttp 2 | 基于GuzzleHttp的简单版Http客户端。 Simple Http client base on GuzzleHttp 3 | 4 | ## 安装 5 | 6 | ``` 7 | composer require jaeger/g-http 8 | ``` 9 | 10 | ## 用法 11 | 12 | #### 1. get / getJson 13 | ```php 14 | 15 | use Jaeger\GHttp; 16 | 17 | $rt = GHttp::get('https://www.baidu.com/s?wd=QueryList'); 18 | 19 | $rt = GHttp::get('https://www.baidu.com/s','wd=QueryList&wd2=teststr'); 20 | 21 | //or 22 | 23 | $rt = GHttp::get('https://www.baidu.com/s',[ 24 | 'wd' => 'QueryList', 25 | 'wd2' => 'teststr' 26 | ]); 27 | 28 | //opt 29 | 30 | $rt = GHttp::get('https://www.baidu.com/s',[ 31 | 'wd' => 'QueryList' 32 | ],[ 33 | 'headers' => [ 34 | 'referer' => 'https://baidu.com', 35 | 'User-Agent' => 'Mozilla/5.0 (Windows NTChrome/58.0.3029.110 Safari/537.36', 36 | 'Cookie' => 'cookie xxx' 37 | ] 38 | ]); 39 | 40 | $rt = GHttp::getJson('https://xxxx.com/json'); 41 | 42 | ``` 43 | 44 | #### 2.post / postRaw / postJson 45 | ```php 46 | $rt = GHttp::post('https://www.posttestserver.com/post.php',[ 47 | 'name' => 'QueryList', 48 | 'password' => 'ql' 49 | ]); 50 | 51 | $rt = GHttp::post('https://www.posttestserver.com/post.php','name=QueryList&password=ql'); 52 | 53 | 54 | $rt = GHttp::postRaw('http://httpbin.org/post','raw data'); 55 | $rt = GHttp::postRaw('http://httpbin.org/post',['aa' => 11,'bb' => 22]); 56 | 57 | 58 | $rt = GHttp::postJson('http://httpbin.org/post',['aa' => 11,'bb' => 22]); 59 | $rt = GHttp::postJson('http://httpbin.org/post','aa=11&bb=22'); 60 | 61 | ``` 62 | #### 3.download 63 | 64 | ```php 65 | GHttp::download('http://sw.bos.baidu.com/setup.exe','./path/to/xx.exe'); 66 | ``` 67 | ### 4. concurrent requests 68 | ```php 69 | use Jaeger\GHttp; 70 | 71 | $urls = [ 72 | 'http://httpbin.org/get?name=php', 73 | 'http://httpbin.org/get?name=go', 74 | 'http://httpbin.org/get?name=c#', 75 | 'http://httpbin.org/get?name=java' 76 | ]; 77 | 78 | GHttp::multiRequest($urls)->withHeaders([ 79 | 'X-Powered-By' => 'Jaeger' 80 | ])->withOptions([ 81 | 'timeout' => 10 82 | ])->concurrency(2)->success(function($response,$index){ 83 | print_r((String)$response->getBody()); 84 | print_r($index); 85 | })->error(function($reason,$index){ 86 | print_r($reason); 87 | })->get(); 88 | ``` 89 | 90 | ```php 91 | use Jaeger\GHttp; 92 | use GuzzleHttp\Psr7\Request; 93 | 94 | $requests = [ 95 | new Request('POST','http://httpbin.org/post',[ 96 | 'Content-Type' => 'application/x-www-form-urlencoded', 97 | 'User-Agent' => 'g-http' 98 | ],http_build_query([ 99 | 'name' => 'php' 100 | ])), 101 | new Request('POST','http://httpbin.org/post',[ 102 | 'Content-Type' => 'application/x-www-form-urlencoded', 103 | 'User-Agent' => 'g-http' 104 | ],http_build_query([ 105 | 'name' => 'go' 106 | ])), 107 | new Request('POST','http://httpbin.org/post',[ 108 | 'Content-Type' => 'application/x-www-form-urlencoded', 109 | 'User-Agent' => 'g-http' 110 | ],http_build_query([ 111 | 'name' => 'c#' 112 | ])) 113 | ]; 114 | 115 | GHttp::multiRequest($requests)->success(function($response,$index){ 116 | print_r((String)$response->getBody()); 117 | print_r($index); 118 | })->post(); 119 | ``` 120 | ### 5. Request with cache 121 | 122 | Base on Symfony-Cache: https://symfony.com/doc/current/components/cache.html 123 | 124 | - Use filesystem cache 125 | ```php 126 | use Jaeger\GHttp; 127 | 128 | $rt = GHttp::get('http://httpbin.org/get',[ 129 | 'wd' => 'QueryList' 130 | ],[ 131 | 'cache' => __DIR__, 132 | 'cache_ttl' => 120 //seconds 133 | ]); 134 | 135 | ``` 136 | 137 | - Use predis cache 138 | 139 | Install predis: 140 | ``` 141 | composer require predis/predis 142 | ``` 143 | 144 | Usage: 145 | ```php 146 | use Jaeger\GHttp; 147 | use Symfony\Component\Cache\Adapter\RedisAdapter; 148 | 149 | $cache = new RedisAdapter( 150 | 151 | // the object that stores a valid connection to your Redis system 152 | $redis = RedisAdapter::createConnection( 153 | 'redis://localhost' 154 | ), 155 | 156 | // the string prefixed to the keys of the items stored in this cache 157 | $namespace = 'cache', 158 | 159 | // the default lifetime (in seconds) for cache items that do not define their 160 | // own lifetime, with a value 0 causing items to be stored indefinitely (i.e. 161 | // until RedisAdapter::clear() is invoked or the server(s) are purged) 162 | $defaultLifetime = 0 163 | ); 164 | 165 | $rt = GHttp::get('http://httpbin.org/get',[ 166 | 'wd' => 'QueryList' 167 | ],[ 168 | 'cache' => $cache, 169 | 'cache_ttl' => 120 170 | ]); 171 | 172 | print_r($rt); 173 | ``` -------------------------------------------------------------------------------- /composer.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "jaeger/g-http", 3 | "description": "Simple Http client base on GuzzleHttp", 4 | "license": "MIT", 5 | "authors": [ 6 | { 7 | "name": "Jaeger", 8 | "email": "JaegerCode@gmail.com" 9 | } 10 | ], 11 | "require": { 12 | "PHP":">=8.1", 13 | "guzzlehttp/guzzle": "^6.0 || ^7.0", 14 | "symfony/cache": "^6.4 || ^7.0" 15 | }, 16 | "autoload":{ 17 | "psr-4":{ 18 | "Jaeger\\":"src" 19 | } 20 | }, 21 | "require-dev": { 22 | "predis/predis": "^2.2" 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /examples/multi_request.php: -------------------------------------------------------------------------------- 1 | 5 | * Date: 18/12/10 6 | * Time: 下午4:04 7 | */ 8 | require __DIR__.'/../vendor/autoload.php'; 9 | use Jaeger\GHttp; 10 | 11 | $urls = [ 12 | 'http://httpbin.org/get?name=php', 13 | 'http://httpbin.org/get?name=go', 14 | 'http://httpbin.org/get?name=c#', 15 | 'http://httpbin.org/get?name=java' 16 | ]; 17 | 18 | GHttp::multiRequest($urls)->withHeaders([ 19 | 'X-Powered-By' => 'Jaeger' 20 | ])->withOptions([ 21 | 'timeout' => 10 22 | ])->concurrency(2)->success(function($response,$index){ 23 | print_r((String)$response->getBody()); 24 | print_r($index); 25 | })->error(function($reason,$index){ 26 | print_r($reason); 27 | })->get(); -------------------------------------------------------------------------------- /examples/multi_request_2.php: -------------------------------------------------------------------------------- 1 | 5 | * Date: 18/12/10 6 | * Time: 下午6:51 7 | */ 8 | 9 | require __DIR__.'/../vendor/autoload.php'; 10 | use Jaeger\GHttp; 11 | use GuzzleHttp\Psr7\Request; 12 | 13 | $requests = [ 14 | new Request('POST','http://httpbin.org/post',[ 15 | 'Content-Type' => 'application/x-www-form-urlencoded', 16 | 'User-Agent' => 'g-http' 17 | ],http_build_query([ 18 | 'name' => 'php' 19 | ])), 20 | new Request('POST','http://httpbin.org/post',[ 21 | 'Content-Type' => 'application/x-www-form-urlencoded', 22 | 'User-Agent' => 'g-http' 23 | ],http_build_query([ 24 | 'name' => 'go' 25 | ])), 26 | new Request('POST','http://httpbin.org/post',[ 27 | 'Content-Type' => 'application/x-www-form-urlencoded', 28 | 'User-Agent' => 'g-http' 29 | ],http_build_query([ 30 | 'name' => 'c#' 31 | ])) 32 | ]; 33 | 34 | GHttp::multiRequest($requests)->success(function($response,$index){ 35 | print_r((String)$response->getBody()); 36 | print_r($index); 37 | })->post(); -------------------------------------------------------------------------------- /examples/request_with_cache.php: -------------------------------------------------------------------------------- 1 | 5 | * Date: 18/12/11 6 | * Time: 下午6:48 7 | */ 8 | 9 | require __DIR__.'/../vendor/autoload.php'; 10 | use Jaeger\GHttp; 11 | 12 | use Symfony\Component\Cache\Adapter\RedisAdapter; 13 | 14 | $rt = GHttp::get('http://httpbin.org/get',[ 15 | 'wd' => 'QueryList' 16 | ],[ 17 | 'cache' => __DIR__.DIRECTORY_SEPARATOR.'.cache', 18 | 'cache_ttl' => 120 19 | ]); 20 | 21 | print_r($rt); 22 | 23 | 24 | 25 | $cache = new RedisAdapter( 26 | 27 | // the object that stores a valid connection to your Redis system 28 | $redis = RedisAdapter::createConnection( 29 | 'redis://localhost' 30 | ), 31 | 32 | // the string prefixed to the keys of the items stored in this cache 33 | $namespace = 'cache', 34 | 35 | // the default lifetime (in seconds) for cache items that do not define their 36 | // own lifetime, with a value 0 causing items to be stored indefinitely (i.e. 37 | // until RedisAdapter::clear() is invoked or the server(s) are purged) 38 | $defaultLifetime = 0 39 | ); 40 | 41 | $rt = GHttp::get('http://httpbin.org/get',[ 42 | 'wd' => 'QueryList' 43 | ],[ 44 | 'cache' => $cache, 45 | 'cache_ttl' => 120 46 | ]); 47 | 48 | print_r($rt); -------------------------------------------------------------------------------- /examples/simple.php: -------------------------------------------------------------------------------- 1 | 5 | * Date: 18/12/11 6 | * Time: 下午6:48 7 | */ 8 | 9 | require __DIR__.'/../vendor/autoload.php'; 10 | use Jaeger\GHttp; 11 | 12 | $rt = GHttp::get('http://httpbin.org/get',[ 13 | 'wd' => 'QueryList' 14 | ],[ 15 | 'headers' => [ 16 | 'referer' => 'https://baidu.com', 17 | 'User-Agent' => 'Mozilla/5.0 (Windows NTChrome/58.0.3029.110 Safari/537.36', 18 | 'Cookie' => 'cookie xxx' 19 | ], 20 | ]); 21 | 22 | print_r($rt); 23 | -------------------------------------------------------------------------------- /src/Cache.php: -------------------------------------------------------------------------------- 1 | 5 | * Date: 18/12/11 6 | * Time: 下午6:39 7 | */ 8 | 9 | namespace Jaeger; 10 | 11 | 12 | use Symfony\Component\Cache\Adapter\FilesystemAdapter; 13 | use Symfony\Contracts\Cache\CacheInterface; 14 | use Symfony\Contracts\Cache\ItemInterface; 15 | 16 | class Cache extends GHttp 17 | { 18 | public static function remember($name, $arguments) 19 | { 20 | $cachePool = null; 21 | $cacheConfig = self::initCacheConfig($arguments); 22 | 23 | if (empty($cacheConfig['cache'])) { 24 | return self::$name(...$arguments); 25 | } 26 | if (is_string($cacheConfig['cache'])) { 27 | $cachePool = new FilesystemAdapter( 28 | 29 | // a string used as the subdirectory of the root cache directory, where cache 30 | // items will be stored 31 | $namespace = '', 32 | 33 | // the default lifetime (in seconds) for cache items that do not define their 34 | // own lifetime, with a value 0 causing items to be stored indefinitely (i.e. 35 | // until the files are deleted) 36 | $defaultLifetime = 0, 37 | 38 | // the main cache directory (the application needs read-write permissions on it) 39 | // if none is specified, a directory is created inside the system temporary directory 40 | $directory = $cacheConfig['cache'] 41 | ); 42 | }else if ($cacheConfig['cache'] instanceof CacheInterface) { 43 | $cachePool = $cacheConfig['cache']; 44 | } 45 | 46 | $cacheKey = self::getCacheKey($name,$arguments); 47 | $self = self::class; 48 | $data = $cachePool->get($cacheKey, function (ItemInterface $item) use($self, $name, $arguments, $cacheConfig): string { 49 | $item->expiresAfter($cacheConfig['cache_ttl']); 50 | return $self::$name(...$arguments); 51 | }); 52 | return $data; 53 | } 54 | 55 | protected static function initCacheConfig($arguments) 56 | { 57 | $cacheConfig = [ 58 | 'cache' => null, 59 | 'cache_ttl' => null 60 | ]; 61 | if(!empty($arguments[2])) { 62 | $cacheConfig = array_merge([ 63 | 'cache' => null, 64 | 'cache_ttl' => null 65 | ],$arguments[2]); 66 | } 67 | return $cacheConfig; 68 | } 69 | 70 | protected static function getCacheKey($name, $arguments) 71 | { 72 | return md5($name.'_'.json_encode($arguments)); 73 | } 74 | } -------------------------------------------------------------------------------- /src/GHttp.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * @Version V1.0 9 | */ 10 | 11 | namespace Jaeger; 12 | 13 | use GuzzleHttp\Client; 14 | 15 | /** 16 | * Class GHttp 17 | * @package Jaeger 18 | * 19 | * @method static string get($url,$args = null,$otherArgs = []) 20 | * @method static mixed getJson($url, $args = null, $otherArgs = []) 21 | * @method static string post($url,$args = null,$otherArgs = []) 22 | * @method static string postRaw($url, $raw = null, $otherArgs = []) 23 | * @method static string postJson($url, $args = null, $otherArgs = []) 24 | */ 25 | class GHttp 26 | { 27 | private static $client = null; 28 | 29 | public static function __callStatic($name, $arguments) 30 | { 31 | $protectedName = '_'.$name; 32 | if(method_exists(self::class,$protectedName)){ 33 | return Cache::remember($protectedName, $arguments); 34 | } 35 | throw new MethodNotFoundException('Call undefined method '.self::class.':'.$name.'()'); 36 | } 37 | 38 | public static function getClient(array $config = []) 39 | { 40 | if(self::$client == null){ 41 | self::$client = new Client($config); 42 | } 43 | return self::$client; 44 | } 45 | 46 | /** 47 | * @param $url 48 | * @param array $args 49 | * @param array $otherArgs 50 | * @return string 51 | */ 52 | protected static function _get($url,$args = null,$otherArgs = []) 53 | { 54 | is_string($args) && parse_str($args,$args); 55 | $args = array_merge([ 56 | 'verify' => false, 57 | 'query' => $args, 58 | 'headers' => [ 59 | 'referer' => $url, 60 | 'User-Agent' => 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.110 Safari/537.36' 61 | ] 62 | ],$otherArgs); 63 | $client = self::getClient(); 64 | $response = $client->request('GET', $url,$args); 65 | return (string)$response->getBody(); 66 | } 67 | 68 | protected static function _getJson($url, $args = null, $otherArgs = []) 69 | { 70 | $data = self::get($url, $args , $otherArgs); 71 | return json_decode($data,JSON_UNESCAPED_UNICODE); 72 | } 73 | 74 | /** 75 | * @param $url 76 | * @param array $args 77 | * @param array $otherArgs 78 | * @return string 79 | */ 80 | protected static function _post($url,$args = null,$otherArgs = []) 81 | { 82 | is_string($args) && parse_str($args,$args); 83 | $args = array_merge([ 84 | 'verify' => false, 85 | 'form_params' => $args, 86 | 'headers' => [ 87 | 'referer' => $url, 88 | 'User-Agent' => 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.110 Safari/537.36' 89 | ] 90 | ],$otherArgs); 91 | $client = self::getClient(); 92 | $response = $client->request('Post', $url,$args); 93 | return (string)$response->getBody(); 94 | } 95 | 96 | /** 97 | * @param $url 98 | * @param null $raw 99 | * @param array $otherArgs 100 | * @return string 101 | */ 102 | protected static function _postRaw($url, $raw = null, $otherArgs = []) 103 | { 104 | is_array($raw) && $raw = json_encode($raw); 105 | $args = array_merge([ 106 | 'verify' => false, 107 | 'body' => $raw, 108 | 'headers' => [ 109 | 'referer' => $url, 110 | 'User-Agent' => 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.110 Safari/537.36' 111 | ] 112 | ],$otherArgs); 113 | $client = self::getClient(); 114 | $response = $client->request('Post', $url,$args); 115 | return (string)$response->getBody(); 116 | } 117 | 118 | /** 119 | * @param $url 120 | * @param null $args 121 | * @param array $otherArgs 122 | * @return string 123 | */ 124 | protected static function _postJson($url, $args = null, $otherArgs = []) 125 | { 126 | is_string($args) && parse_str($args,$args); 127 | $args = array_merge([ 128 | 'verify' => false, 129 | 'json' => $args, 130 | 'headers' => [ 131 | 'referer' => $url, 132 | 'User-Agent' => 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.110 Safari/537.36' 133 | ] 134 | ],$otherArgs); 135 | $client = self::getClient(); 136 | $response = $client->request('Post', $url,$args); 137 | return (string)$response->getBody(); 138 | } 139 | 140 | /** 141 | * @param $url 142 | * @param $filePath 143 | * @param null $args 144 | * @param array $otherArgs 145 | * @return string 146 | */ 147 | public static function download($url,$filePath,$args = null,$otherArgs = []) 148 | { 149 | $otherArgs = array_merge($otherArgs,[ 150 | 'sink' => $filePath, 151 | ]); 152 | return self::get($url,$args,$otherArgs); 153 | } 154 | 155 | /** 156 | * @param $urls 157 | * @return MultiRequest 158 | */ 159 | public static function multiRequest($urls) 160 | { 161 | $client = self::getClient(); 162 | return MultiRequest::newRequest($client)->urls($urls); 163 | } 164 | } -------------------------------------------------------------------------------- /src/MethodNotFoundException.php: -------------------------------------------------------------------------------- 1 | 5 | * Date: 18/12/12 6 | * Time: 上午10:56 7 | */ 8 | 9 | namespace Jaeger; 10 | use Exception; 11 | use Throwable; 12 | 13 | class MethodNotFoundException extends Exception 14 | { 15 | public function __construct($message = "", $code = 0, Throwable $previous = null) 16 | { 17 | parent::__construct($message, $code, $previous); 18 | } 19 | } -------------------------------------------------------------------------------- /src/MultiRequest.php: -------------------------------------------------------------------------------- 1 | 5 | * Date: 18/12/10 6 | * Time: 下午6:04 7 | */ 8 | 9 | namespace Jaeger; 10 | use GuzzleHttp\Client; 11 | use Closure; 12 | use GuzzleHttp\Pool; 13 | use GuzzleHttp\Psr7\Request; 14 | 15 | class MultiRequest 16 | { 17 | protected $client; 18 | protected $headers = []; 19 | protected $options = []; 20 | protected $successCallback; 21 | protected $errorCallback; 22 | protected $urls = []; 23 | protected $method; 24 | protected $concurrency = 5; 25 | 26 | public function __construct(Client $client) 27 | { 28 | $this->client = $client; 29 | $this->headers = [ 30 | 'User-Agent' => 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.110 Safari/537.36' 31 | ]; 32 | } 33 | 34 | public static function newRequest(Client $client) 35 | { 36 | $request = new self($client); 37 | return $request; 38 | } 39 | 40 | public function withHeaders($headers) 41 | { 42 | $this->headers = array_merge($this->headers,$headers); 43 | return $this; 44 | } 45 | 46 | public function withOptions($options) 47 | { 48 | $this->options = $options; 49 | return $this; 50 | } 51 | 52 | public function concurrency($concurrency) 53 | { 54 | $this->concurrency = $concurrency; 55 | return $this; 56 | } 57 | 58 | public function success(Closure $success) 59 | { 60 | $this->successCallback = $success; 61 | return $this; 62 | } 63 | 64 | public function error(Closure $error) 65 | { 66 | $this->errorCallback = $error; 67 | return $this; 68 | } 69 | 70 | public function urls(array $urls) 71 | { 72 | $this->urls = $urls; 73 | return $this; 74 | } 75 | 76 | public function get() 77 | { 78 | $this->method = 'GET'; 79 | $this->send(); 80 | } 81 | 82 | public function post() 83 | { 84 | $this->method = 'POST'; 85 | $this->send(); 86 | } 87 | 88 | protected function send() 89 | { 90 | $client = $this->client; 91 | 92 | $requests = function ($urls) use($client){ 93 | foreach ($urls as $url) { 94 | if (is_string($url)) { 95 | yield new Request($this->method,$url,$this->headers); 96 | } else { 97 | yield $url; 98 | } 99 | } 100 | }; 101 | 102 | $pool = new Pool($client, $requests($this->urls), [ 103 | 'concurrency' => $this->concurrency, 104 | 'fulfilled' => $this->successCallback, 105 | 'rejected' => $this->errorCallback, 106 | 'options' => $this->options 107 | ]); 108 | 109 | $promise = $pool->promise(); 110 | $promise->wait(); 111 | } 112 | 113 | } --------------------------------------------------------------------------------