/src/YurunHttp/Cookie/CookieManager.php

https://github.com/Yurunsoft/YurunHttp · PHP · 317 lines · 190 code · 19 blank · 108 comment · 25 complexity · c76395ef334427e0715dda48981dcbb4 MD5 · raw file

  1. <?php
  2. namespace Yurun\Util\YurunHttp\Cookie;
  3. use Yurun\Util\YurunHttp\Http\Psr7\Uri;
  4. class CookieManager
  5. {
  6. /**
  7. * Cookie 列表
  8. *
  9. * @var \Yurun\Util\YurunHttp\Cookie\CookieItem[]
  10. */
  11. protected $cookieList;
  12. /**
  13. * 关联集合
  14. *
  15. * @var array
  16. */
  17. protected $relationMap;
  18. /**
  19. * 自增ID
  20. * 会比当前列表长度+1
  21. *
  22. * @var int
  23. */
  24. protected $autoIncrementId;
  25. /**
  26. * __construct
  27. * @param array $cookieList
  28. */
  29. public function __construct($cookieList = [])
  30. {
  31. $this->setCookieList($cookieList);
  32. }
  33. /**
  34. * 设置 Cookie 列表
  35. *
  36. * @param array $cookieList
  37. * @return void
  38. */
  39. public function setCookieList($cookieList)
  40. {
  41. $this->autoIncrementId = 1;
  42. $this->cookieList = [];
  43. $this->relationMap = [];
  44. foreach($cookieList as $item)
  45. {
  46. $item = CookieItem::newInstance($item);
  47. $this->insertCookie($item);
  48. }
  49. }
  50. /**
  51. * 获取 Cookie 列表
  52. *
  53. * @return array
  54. */
  55. public function getCookieList()
  56. {
  57. return $this->cookieList;
  58. }
  59. /**
  60. * 添加 Set-Cookie
  61. *
  62. * @param string $setCookie
  63. * @return \Yurun\Util\YurunHttp\Cookie\CookieItem
  64. */
  65. public function addSetCookie($setCookie)
  66. {
  67. $item = CookieItem::fromSetCookie($setCookie);
  68. if(($id = $this->findCookie($item)) > 0)
  69. {
  70. $this->updateCookie($id, $item);
  71. }
  72. else
  73. {
  74. $this->insertCookie($item);
  75. }
  76. return $item;
  77. }
  78. /**
  79. * 设置 Cookie
  80. *
  81. * @param string $name
  82. * @param string $value
  83. * @param integer $expires
  84. * @param string $path
  85. * @param string $domain
  86. * @param boolean $secure
  87. * @param boolean $httpOnly
  88. * @return \Yurun\Util\YurunHttp\Cookie\CookieItem
  89. */
  90. public function setCookie($name, $value, $expires = 0, $path = '/', $domain = '', $secure = false, $httpOnly = false)
  91. {
  92. $item = new CookieItem($name, $value, $expires, $path, $domain, $secure, $httpOnly);
  93. if(($id = $this->findCookie($item)) > 0)
  94. {
  95. $this->updateCookie($id, $item);
  96. }
  97. else
  98. {
  99. $this->insertCookie($item);
  100. }
  101. return $item;
  102. }
  103. /**
  104. * Cookie 数量
  105. *
  106. * @return int
  107. */
  108. public function count()
  109. {
  110. return count($this->cookieList);
  111. }
  112. /**
  113. * 获取请求所需 Cookie 关联数组
  114. *
  115. * @param \Psr\Http\Message\UriInterface $uri
  116. * @return array
  117. */
  118. public function getRequestCookies($uri)
  119. {
  120. if(defined('SWOOLE_VERSION') && SWOOLE_VERSION < 4.4)
  121. {
  122. // Fix bug: https://github.com/swoole/swoole-src/pull/2644
  123. $result = json_decode('[]', true);
  124. }
  125. else
  126. {
  127. $result = [];
  128. }
  129. $uriDomain = Uri::getDomain($uri);
  130. $uriPath = $uri->getPath();
  131. $cookieList = &$this->cookieList;
  132. foreach($this->relationMap as $relationDomain => $list1)
  133. {
  134. if('' === $relationDomain || $this->checkDomain($uriDomain, $relationDomain))
  135. {
  136. foreach($list1 as $path => $idList)
  137. {
  138. if($this->checkPath($uriPath, $path))
  139. {
  140. foreach($idList as $id)
  141. {
  142. $cookieItem = $cookieList[$id];
  143. if((0 === $cookieItem->expires || $cookieItem->expires > time()) && (!$cookieItem->secure || 'https' === $uri->getScheme() || 'wss' === $uri->getScheme()) )
  144. {
  145. $result[$cookieItem->name] = $cookieItem->value;
  146. }
  147. }
  148. }
  149. }
  150. }
  151. }
  152. return $result;
  153. }
  154. /**
  155. * 获取请求所需 Cookie 关联数组
  156. *
  157. * @param \Psr\Http\Message\UriInterface $uri
  158. * @return string
  159. */
  160. public function getRequestCookieString($uri)
  161. {
  162. $content = '';
  163. foreach($this->getRequestCookies($uri) as $name => $value)
  164. {
  165. $content .= "{$name}={$value}; ";
  166. }
  167. return $content;
  168. }
  169. /**
  170. * 获取 CookieItem
  171. *
  172. * @param string $name
  173. * @param string $domain
  174. * @param string $path
  175. * @return \Yurun\Util\YurunHttp\Cookie\CookieItem
  176. */
  177. public function getCookieItem($name, $domain = '', $path = '/')
  178. {
  179. if(isset($this->relationMap[$domain][$path][$name]))
  180. {
  181. $id = $this->relationMap[$domain][$path][$name];
  182. return $this->cookieList[$id];
  183. }
  184. return null;
  185. }
  186. /**
  187. * 检查 uri 域名和 cookie 域名
  188. *
  189. * @param string $uriDomain
  190. * @param string $cookieDomain
  191. * @return boolean
  192. */
  193. private function checkDomain($uriDomain, $cookieDomain)
  194. {
  195. return ($uriDomain === $cookieDomain)
  196. || (isset($cookieDomain[0]) && '.' === $cookieDomain[0] && substr($uriDomain, -strlen($cookieDomain) - 1) === '.' . $cookieDomain)
  197. ;
  198. }
  199. /**
  200. * 检查 uri 路径和 cookie 路径
  201. *
  202. * @param string $uriDomain
  203. * @param string $cookieDomain
  204. * @return boolean
  205. */
  206. private function checkPath($uriPath, $cookiePath)
  207. {
  208. $uriPath = rtrim($uriPath, '/');
  209. $cookiePath = rtrim($cookiePath, '/');
  210. if($uriPath === $cookiePath)
  211. {
  212. return true;
  213. }
  214. $uriPathDSCount = substr_count($uriPath, '/');
  215. $cookiePathDSCount = substr_count($cookiePath, '/');
  216. if('' === $uriPath)
  217. {
  218. $uriPath = '/';
  219. }
  220. if('' === $cookiePath)
  221. {
  222. $cookiePath = '/';
  223. }
  224. if($uriPathDSCount > $cookiePathDSCount)
  225. {
  226. if(version_compare(PHP_VERSION, '7.0', '>='))
  227. {
  228. $path = dirname($uriPath, $uriPathDSCount - $cookiePathDSCount);
  229. }
  230. else
  231. {
  232. $count = $uriPathDSCount - $cookiePathDSCount;
  233. $path = $uriPath;
  234. while($count--)
  235. {
  236. $path = dirname($path);
  237. }
  238. }
  239. if('\\' === DIRECTORY_SEPARATOR && false !== strpos($path, DIRECTORY_SEPARATOR))
  240. {
  241. $path = str_replace(DIRECTORY_SEPARATOR, '/', $path);
  242. }
  243. return $path === $cookiePath;
  244. }
  245. else
  246. {
  247. return false;
  248. }
  249. }
  250. /**
  251. * 更新 Cookie 数据
  252. *
  253. * @param int $id
  254. * @param \Yurun\Util\YurunHttp\Cookie\CookieItem $item
  255. * @return int
  256. */
  257. private function updateCookie($id, $item)
  258. {
  259. if(isset($this->cookieList[$id]))
  260. {
  261. $object = $this->cookieList[$id];
  262. }
  263. foreach($item as $k => $v)
  264. {
  265. $object->$k = $v;
  266. }
  267. }
  268. /**
  269. * 插入 Cookie 数据
  270. *
  271. * @param \Yurun\Util\YurunHttp\Cookie\CookieItem $item
  272. * @return int
  273. */
  274. private function insertCookie($item)
  275. {
  276. $id = $this->autoIncrementId++;
  277. $this->cookieList[$id] = $item;
  278. $this->relationMap[$item->domain][$item->path][$item->name] = $id;
  279. return $id;
  280. }
  281. /**
  282. * 查找 Cookie ID
  283. *
  284. * @param \Yurun\Util\YurunHttp\Cookie\CookieItem $item
  285. * @return int|null
  286. */
  287. private function findCookie($item)
  288. {
  289. if(isset($this->relationMap[$item->domain][$item->path][$item->name]))
  290. {
  291. return $this->relationMap[$item->domain][$item->path][$item->name];
  292. }
  293. else
  294. {
  295. return null;
  296. }
  297. }
  298. }