/src/NetglueSSL/Service/UriResolver.php

https://bitbucket.org/netglue/zf2-require-ssl-module · PHP · 270 lines · 161 code · 28 blank · 81 comment · 29 complexity · 84a555d39744b47c3727647c596bb1a1 MD5 · raw file

  1. <?php
  2. /**
  3. * URI Resolver Service mostly helps us to figure out the corresponding http/s uri for a given request
  4. * and helps determine whether we should redirect or not
  5. *
  6. * @author George Steel <george@net-glue.co.uk>
  7. * @copyright Copyright (c) 2013 Net Glue Ltd (http://netglue.co)
  8. * @license http://opensource.org/licenses/MIT
  9. */
  10. namespace NetglueSSL\Service;
  11. use NetglueSSL\Service\Options;
  12. use Zend\Uri\Http as HttpUri;
  13. use Zend\Uri\UriFactory;
  14. use Zend\Uri\Excpetion\ExceptionInterface as UriException;
  15. use Zend\Http\Request as HttpRequest;
  16. class UriResolver {
  17. /**
  18. * Options
  19. * @var Options
  20. */
  21. protected $options;
  22. /**
  23. * Require options
  24. * @param Options $options
  25. * @return void
  26. */
  27. public function __construct(Options $options) {
  28. $this->options = $options;
  29. }
  30. /**
  31. * Return options
  32. * @return Options
  33. */
  34. public function getOptions() {
  35. return $this->options;
  36. }
  37. /**
  38. * Return the SSL Uri for the given URI
  39. * @param mixed $uri
  40. * @return HttpUri
  41. */
  42. public function getSslUri($uri) {
  43. if($this->isSSL($uri)) {
  44. return $this->getUri($uri);
  45. }
  46. $uri = $this->requireUri($uri);
  47. $path = $uri->getPath();
  48. $host = $this->options->getSslHostname() ? $this->options->getSslHostname() : $uri->getHost();
  49. $scheme = 'https';
  50. // Strip any HTTP path prefix
  51. if($this->options->getHttpPathPrefix()) {
  52. $prefix = $this->options->getHttpPathPrefix();
  53. if(strpos($path, $prefix) === 0) {
  54. $path = substr($path, strlen($prefix));
  55. }
  56. }
  57. // Prepend the the https path prefix
  58. if($this->options->getSslPathPrefix()) {
  59. $path = $this->options->getSslPathPrefix().$path;
  60. }
  61. $port = $this->options->getSslPort();
  62. $result = clone($uri);
  63. $result->setHost($host)
  64. ->setScheme($scheme)
  65. ->setPath($path)
  66. ->setPort($port);
  67. $result->normalize();
  68. return $result;
  69. }
  70. /**
  71. * Return the standard HTTP Uri that corresponds to the given SSL Uri
  72. * @param mixed $uri
  73. * @return HttpUri
  74. */
  75. public function getHttpUri($uri) {
  76. if($this->isHttp($uri)) {
  77. return $this->getUri($uri);
  78. }
  79. $uri = $this->requireUri($uri);
  80. $path = $uri->getPath();
  81. $host = $this->options->getHttpHostname() ? $this->options->getHttpHostname() : $uri->getHost();
  82. $scheme = 'http';
  83. // Strip any SSL path prefix
  84. if($this->options->getSslPathPrefix()) {
  85. $prefix = $this->options->getSslPathPrefix();
  86. if(strpos($path, $prefix) === 0) {
  87. $path = substr($path, strlen($prefix));
  88. }
  89. }
  90. // Prepend the the http path prefix if any
  91. if($this->options->getHttpPathPrefix()) {
  92. $path = $this->options->getHttpPathPrefix().$path;
  93. }
  94. $port = $this->options->getHttpPort();
  95. $result = clone($uri);
  96. $result->setHost($host)
  97. ->setScheme($scheme)
  98. ->setPath($path)
  99. ->setPort($port);
  100. $result->normalize();
  101. return $result;
  102. }
  103. /**
  104. * Helper to return a Zend\Uri\Http instance from various arguments
  105. * @param mixed $uri
  106. * @return HttpUri|false
  107. */
  108. public function getUri($uri) {
  109. if($uri instanceof HttpRequest) {
  110. return $uri->getUri();
  111. }
  112. if(is_string($uri)) {
  113. return UriFactory::factory($uri);
  114. }
  115. if($uri instanceof HttpUri) {
  116. return $uri;
  117. }
  118. return false;
  119. }
  120. /**
  121. * Require that the given uri can be resolved to an HttpUri instance
  122. * @param mixed $uri
  123. * @return HttpUri
  124. * @throws InvalidArgumentException if we cannot retrieve a uri instance
  125. * @see getUri()
  126. */
  127. public function requireUri($uri) {
  128. // Catch exceptions thrown by the uri constructor or factory
  129. $e = NULL;
  130. try {
  131. $instance = $this->getUri($uri);
  132. } catch(UriException $e) {
  133. $instance = false;
  134. }
  135. if(false === $instance) {
  136. throw new \InvalidArgumentException(
  137. sprintf(
  138. 'Expected a string, an instanceof Zend\Uri\Http or something else able to return a Uri instance got %s',
  139. is_object($uri) ? get_class($uri) : gettype($uri)
  140. ),
  141. NULL,
  142. $e
  143. );
  144. }
  145. return $instance;
  146. }
  147. /**
  148. * Whether the given uri represents an encrypted connection
  149. * @param mixed $uri
  150. * @return bool
  151. */
  152. public function isSSL($uri) {
  153. $uri = $this->requireUri($uri);
  154. return $uri->getScheme() === 'https';
  155. }
  156. /**
  157. * Whether the given uri represents a standard http connection
  158. * @param mixed $uri
  159. * @return bool
  160. */
  161. public function isHttp($uri) {
  162. return !$this->isSSL($uri);
  163. }
  164. /**
  165. * Return the redirect uri for the given controller in the context of the given uri
  166. * @param mixed $uri
  167. * @param string $controller
  168. * @return HttpUri|NULL If a uri is returned, it is expected that a redirect should occur
  169. */
  170. public function getControllerRedirectUri($uri, $controller) {
  171. if(!is_string($controller) || empty($controller)) {
  172. return;
  173. }
  174. if($this->isSSL($uri)) {
  175. $search = $this->options->getHttpControllers();
  176. if(in_array($controller, $search)) {
  177. return $this->getHttpUri($uri);
  178. }
  179. } else {
  180. $search = $this->options->getSslControllers();
  181. if(in_array($controller, $search)) {
  182. return $this->getSslUri($uri);
  183. }
  184. }
  185. }
  186. /**
  187. * Return the redirect uri for the given route name in the context of the given uri
  188. * @param mixed $uri
  189. * @param string $route
  190. * @return HttpUri|NULL If a uri is returned, it is expected that a redirect should occur
  191. */
  192. public function getRouteRedirectUri($uri, $route) {
  193. if(!is_string($route) || empty($route)) {
  194. return;
  195. }
  196. if($this->isSSL($uri)) {
  197. $search = $this->options->getHttpRoutes();
  198. if(in_array($route, $search)) {
  199. return $this->getHttpUri($uri);
  200. }
  201. } else {
  202. $search = $this->options->getSslRoutes();
  203. if(in_array($route, $search)) {
  204. return $this->getSslUri($uri);
  205. }
  206. }
  207. }
  208. /**
  209. * Return the redirect Uri for the given uri
  210. * @param mixed $uri
  211. * @return HttpUri|NULL If a uri is returned, it is expected that a redirect should occur
  212. */
  213. public function getUriRedirectUri($uri) {
  214. $uri = $this->requireUri($uri);
  215. if($this->isSSL($uri)) {
  216. $search = $this->options->getHttpUris();
  217. if($this->isUriMatch($uri->getPath(), $search)) {
  218. return $this->getHttpUri($uri);
  219. }
  220. } else {
  221. $search = $this->options->getSslUris();
  222. if($this->isUriMatch($uri->getPath(), $search)) {
  223. return $this->getSslUri($uri);
  224. }
  225. }
  226. }
  227. /**
  228. * Whether the given path matches against any of the configured uri patterns
  229. * @param string $path
  230. * @param array $patterns
  231. * @return bool
  232. */
  233. protected function isUriMatch($path, array $patterns) {
  234. foreach($patterns as $pattern) {
  235. $pattern = '/^'.preg_quote($pattern, '/').'/';
  236. if(preg_match($pattern, $path)) {
  237. return true;
  238. }
  239. }
  240. return false;
  241. }
  242. }