Fixes #4497 - FHIR search via POST (#4498)
[openemr.git] / src / Common / Http / HttpRestRequest.php
blobd3fd063124acd553669074b6fc3279be7066c40c
1 <?php
3 /**
4 * HttpRestRequest represents the current OpenEMR api request
5 * @package openemr
6 * @link http://www.open-emr.org
7 * @author Stephen Nielson <stephen@nielson.org>
8 * @copyright Copyright (c) 2021 Stephen Nielson <stephen@nielson.org>
9 * @license https://github.com/openemr/openemr/blob/master/LICENSE GNU General Public License 3
12 namespace OpenEMR\Common\Http;
14 use OpenEMR\Common\Logging\SystemLogger;
15 use OpenEMR\Common\System\System;
16 use OpenEMR\Common\Uuid\UuidRegistry;
18 class HttpRestRequest
21 /**
22 * @var \RestConfig
24 private $restConfig;
26 /**
27 * The Resource that is being requested in this http rest call.
28 * @var string
30 private $resource;
32 /**
33 * The FHIR operation that this request represents. FHIR operations are prefixed with a $ ie $export
34 * @var string
36 private $operation;
38 /**
39 * @var array
41 private $requestUser;
43 /**
44 * The binary string of the request user uuid
45 * @var string
47 private $requestUserUUID;
49 /**
50 * @var string
52 private $requestUserUUIDString;
54 /**
55 * @var 'patient'|'users'
57 private $requestUserRole;
59 /**
60 * @var array
62 private $accessTokenScopes;
64 /**
65 * @var string
67 private $requestSite;
69 /**
70 * @var string
72 private $clientId;
74 /**
75 * @var string
77 private $accessTokenId;
79 /**
80 * @var boolean
82 private $isLocalApi;
84 /**
85 * @var string
87 private $requestMethod;
89 /**
90 * The kind of REST api request this object represents
91 * @var string
93 private $apiType;
95 /**
96 * @var string
98 private $requestPath;
101 * @var string the URL for the api base full url
103 private $apiBaseFullUrl;
106 * @var string[] The request headers
108 private $headers;
111 * @var mixed[]
113 private $queryParams;
115 public function __construct($restConfig, $server)
117 $this->restConfig = $restConfig;
118 $this->requestSite = $restConfig::$SITE;
120 $this->setRequestMethod($server["REQUEST_METHOD"]);
121 $this->setRequestURI($server['REQUEST_URI'] ?? "");
122 $this->headers = $this->parseHeadersFromServer($server);
123 $queryParams = $_GET ?? [];
124 // remove the OpenEMR queryParams that our rewrite command injected so we don't mess stuff up.
125 if (isset($queryParams['_REWRITE_COMMAND'])) {
126 unset($queryParams['_REWRITE_COMMAND']);
128 $this->setQueryParams($queryParams);
131 public function setRequestMethod($requestMethod)
133 $this->requestMethod = $requestMethod;
136 public function setQueryParams($queryParams)
138 $this->queryParams = $queryParams;
141 public function getQueryParams()
143 return $this->queryParams;
146 public function getQueryParam($key)
148 return $this->queryParams[$key] ?? null;
152 * Return an array of HTTP request headers
153 * @return array|string[]
155 public function getHeaders()
157 return array_values($this->headers);
161 * Retrieve the value of the passed in request's HTTP header. Return's null if the value does not exist
162 * @param $headerName string the name of the header value to retrieve.
163 * @return mixed|string|null
165 public function getHeader($headerName)
167 return $this->headers[$headerName] ?? null;
171 * Checks if the current HTTP request has the passed in header
172 * @param $headerName The name of the header to check
173 * @return bool true if the header exists, false otherwise.
175 public function hasHeader($headerName)
177 return !empty($this->headers[$headerName]);
181 * @return \RestConfig
183 public function getRestConfig(): \RestConfig
185 return $this->restConfig;
189 * Return the Request URI (matches the $_SERVER['REQUEST_URI'])
190 * @return mixed|string
192 public function getRequestURI()
194 return $this->requestURI;
198 * Return the Request URI (matches the $_SERVER['REQUEST_URI'])
199 * @param mixed|string $requestURI
201 public function setRequestURI($requestURI): void
203 $this->requestURI = $requestURI;
207 * @return string
209 public function getResource(): ?string
211 return $this->resource;
215 * @param string $resource
217 public function setResource(?string $resource): void
219 $this->resource = $resource;
223 * Returns the operation name for this request if this request represents a FHIR operation.
224 * Operations are prefixed with a $
225 * @return string
227 public function getOperation(): ?string
229 return $this->operation;
233 * Sets the operation name for this request if this request represents a FHIR operation.
234 * Operations are prefixed with a $
235 * @param string $operation The operation name
237 public function setOperation(string $operation): void
239 $this->operation = $operation;
243 * @return array
245 public function getRequestUser(): array
247 return $this->requestUser;
251 * Returns the current user id if we have one
252 * @return int|null
254 public function getRequestUserId(): ?int
256 $user = $this->getRequestUser();
257 return $user['id'] ?? null;
261 * @param array $requestUser
263 public function setRequestUser($userUUIDString, array $requestUser): void
265 $this->requestUser = $requestUser;
267 // set up any other user context information
268 if (empty($requestUser)) {
269 $this->requestUserUUIDString = null;
270 $this->requestUserUUID = null;
271 } else {
272 $this->requestUserUUIDString = $userUUIDString ?? null;
273 $this->requestUserUUID = UuidRegistry::uuidToBytes($userUUIDString) ?? null;
278 * @return array
280 public function getAccessTokenScopes(): array
282 return $this->accessTokenScopes;
286 * @param array $scopes
288 public function setAccessTokenScopes(array $scopes): void
290 $this->accessTokenScopes = $scopes;
294 * @return string
296 public function getRequestSite(): ?string
298 return $this->requestSite;
302 * @param string $requestSite
304 public function setRequestSite(string $requestSite): void
306 $this->requestSite = $requestSite;
310 * @return string
312 public function getClientId(): ?string
314 return $this->clientId;
318 * @param string $clientId
320 public function setClientId(string $clientId): void
322 $this->clientId = $clientId;
326 * @return string
328 public function getAccessTokenId(): ?string
330 return $this->accessTokenId;
334 * @param string $accessTokenId
336 public function setAccessTokenId(string $accessTokenId): void
338 $this->accessTokenId = $accessTokenId;
342 * @return bool
344 public function isLocalApi(): bool
346 return $this->isLocalApi;
350 * @param bool $isLocalApi
352 public function setIsLocalApi(bool $isLocalApi): void
354 $this->isLocalApi = $isLocalApi;
358 * @return mixed
360 public function getRequestUserRole()
362 return $this->requestUserRole;
366 * @param string $requestUserRole either 'patients' or 'users'
368 public function setRequestUserRole($requestUserRole): void
370 if (!in_array($requestUserRole, ['patient', 'users', 'system'])) {
371 throw new \InvalidArgumentException("invalid user role found");
373 $this->requestUserRole = $requestUserRole;
376 public function getRequestUserUUID()
378 return $this->requestUserUUID;
381 public function getRequestUserUUIDString()
383 return $this->requestUserUUIDString;
386 public function getPatientUUIDString()
388 // we may change how this is set, it will depend on if a 'user' role type can still have
389 // patient/<resource>.* requests. IE patient/Patient.read
390 return $this->requestUserUUIDString;
394 * @return string
396 public function getApiType(): ?string
398 return $this->apiType;
402 * @param string $api
404 public function setApiType(string $apiType): void
406 if (!in_array($apiType, ['fhir', 'oemr', 'port'])) {
407 throw new \InvalidArgumentException("invalid api type found");
409 $this->apiType = $apiType;
413 * @return string
415 public function getRequestMethod(): ?string
417 return $this->requestMethod;
421 public function isPatientRequest()
423 return $this->requestUserRole === 'patient';
426 public function isFhir()
428 return $this->getApiType() === 'fhir';
432 * If this is a patient context request for write/modify of patient context resources
433 * @return bool
435 public function isPatientWriteRequest()
437 return $this->isFhir() && $this->isPatientRequest() && $this->getRequestMethod() != 'GET';
440 public function isFhirSearchRequest(): bool
442 if ($this->isFhir() && $this->getRequestMethod() == "POST") {
443 return str_ends_with($this->getRequestPath(), '_search') !== false;
445 return false;
448 public function setRequestPath(string $requestPath)
450 $this->requestPath = $requestPath;
453 public function getRequestPath(): ?string
455 return $this->requestPath;
459 * Returns the full URL to the api server
460 * @return string
462 public function getApiBaseFullUrl(): string
464 return $this->apiBaseFullUrl;
468 * Set the full URL to the api server that api requests are appended to.
469 * @param string $apiBaseFullUrl
471 public function setApiBaseFullUrl(string $apiBaseFullUrl): void
473 $this->apiBaseFullUrl = $apiBaseFullUrl;
477 * Given an array of server variables (typically the $_SERVER superglobal) parse out all of the HTTP_X headers
478 * and convert them into a hashmap of header -> header
479 * @param $server array of server variables typically the $_SERVER superglobal
480 * @return array hashmap of header -> header
482 private function parseHeadersFromServer($server)
484 $headers = array();
485 foreach ($server as $key => $value) {
486 $prefix = substr($key, 0, 5);
488 if ($prefix != 'HTTP_') {
489 continue;
492 $serverHeader = strtolower(substr($key, 5));
493 $uppercasedServerHeader = ucwords(str_replace('_', ' ', $serverHeader));
495 $header = str_replace(' ', '-', $uppercasedServerHeader);
496 $headers[$header] = $value;
498 return $headers;