Fix some missing updates (#1373)
[openemr.git] / portal / patient / fwk / libs / verysimple / HTTP / RequestUtil.php
bloba0d9866a5922678864c42513c23c7af581819a91
1 <?php
2 /** @package verysimple::HTTP */
4 /**
5 * import supporting libraries
6 */
8 /**
9 * Static utility class for processing form post/request data
11 * Contains various methods for retrieving user input from forms
13 * @package verysimple::HTTP
14 * @author VerySimple Inc.
15 * @copyright 1997-2011 VerySimple, Inc. http://www.verysimple.com
16 * @license http://www.gnu.org/licenses/lgpl.html LGPL
17 * @version 1.4
19 class RequestUtil
22 /** @var bool set to true and all non-ascii characters in request variables will be html encoded */
23 static $ENCODE_NON_ASCII = false;
25 /** @var bool set to false to skip is_uploaded_file. This allows for simulated file uploads during unit testing */
26 static $VALIDATE_FILE_UPLOAD = true;
28 /** @var body contents, only read once in case GetBody is called multiple times */
29 private static $bodyCache = '';
31 /** @var true if the request body has already been read */
32 private static $bodyCacheIsReady = false;
34 /**
36 * @var bool
37 * @deprecated use $VALIDATE_FILE_UPLOAD instead
39 static $TestMode = false;
41 /**
42 * Returns the remote host IP address, attempting to locate originating
43 * IP of the requester in the case of proxy/load balanced requests.
45 * @see http://en.wikipedia.org/wiki/X-Forwarded-For
46 * @return string
48 static function GetRemoteHost()
50 if (array_key_exists('HTTP_X_CLUSTER_CLIENT_IP', $_SERVER)) {
51 return $_SERVER ['HTTP_X_CLUSTER_CLIENT_IP'];
54 if (array_key_exists('HTTP_X_FORWARDED_FOR', $_SERVER)) {
55 return $_SERVER ['HTTP_X_FORWARDED_FOR'];
58 if (array_key_exists('X_FORWARDED_FOR', $_SERVER)) {
59 return $_SERVER ['X_FORWARDED_FOR'];
62 if (array_key_exists('REMOTE_ADDR', $_SERVER)) {
63 return $_SERVER ['REMOTE_ADDR'];
66 return "0.0.0.0";
69 /**
70 * Returns true if the current session is running in SSL
72 static function IsSSL()
74 return isset($_SERVER ['HTTPS']) && $_SERVER ['HTTPS'] != "" && $_SERVER ['HTTPS'] != "off";
77 /**
78 * In the case of URL re-writing, sometimes querystrings appended to a URL can get
79 * lost.
80 * This function examines the original request URI and updates $_REQUEST
81 * superglobal to ensure that it contains all of values in the qeurtystring
83 public static function NormalizeUrlRewrite()
85 $uri = array ();
86 if (isset($_SERVER ["REQUEST_URI"])) {
87 $uri = parse_url($_SERVER ["REQUEST_URI"]);
88 } elseif (isset($_SERVER ["QUERY_STRING"])) {
89 $uri ['query'] = $_SERVER ["QUERY_STRING"];
92 if (isset($uri ['query'])) {
93 $parts = explode("&", $uri ['query']);
94 foreach ($parts as $part) {
95 $keyval = explode("=", $part, 2);
96 $_REQUEST [$keyval [0]] = isset($keyval [1]) ? urldecode($keyval [1]) : "";
102 * Returns the root url of the server without any subdirectories
104 * @return string URL path with trailing slash
106 public static function GetServerRootUrl()
108 $url = self::GetCurrentURL(false);
109 $parts = explode('/', $url);
110 if (count($parts) < 2) {
111 throw new Exception('RequestUtil is unable to determine the server root');
114 return $parts [0] . '//' . $parts [2] . '/';
118 * Returns the base url of the currently executing script.
119 * For example
120 * the script http://localhost/myapp/index.php would return http://localhost/myapp/
122 * @return string URL path with trailing slash
124 public static function GetBaseURL()
126 $url = self::GetCurrentURL(false);
127 $slash = strripos($url, "/");
128 return substr($url, 0, $slash + 1);
132 * Returns the parts of the url as deliminated by forward slashes for example /this/that/other
133 * will be returned as an array [this,that,other]
135 * @param
136 * string root folder for the app (ex. 'myapp' or 'myapp/subdir1')
137 * @return array
139 public static function GetUrlParts($appRoot = '')
141 $urlqs = explode("?", self::GetCurrentURL(), 2);
142 $url = $urlqs [0];
144 // if a root folder was provided, then we need to strip that out as well
145 if ($appRoot) {
146 $url = str_replace($appRoot . '/', '', $url);
149 $parts = explode("/", $url);
150 // we only want the parts starting with #3 (after http://server/)
152 array_shift($parts);
153 array_shift($parts);
154 array_shift($parts);
156 // if there is no action specified then we don't want to return an array with an empty string
157 while (count($parts) && $parts [0] == '') {
158 array_shift($parts);
161 return $parts;
165 * Returns the request method (GET, POST, PUT, DELETE).
166 * This is detected based
167 * on the HTTP request method, a special URL parameter, or a request header
168 * with the name 'X-HTTP-Method-Override'
170 * For clients or servers that don't support PUT/DELETE requests, the emulated
171 * param can be used or the override header
173 * @param
174 * string name of the querystring parameter that has the overridden request method
176 public static function GetMethod($emulateHttpParamName = '_method')
178 if (array_key_exists($emulateHttpParamName, $_REQUEST)) {
179 return $_REQUEST [$emulateHttpParamName];
182 $headers = self::GetRequestHeaders();
184 // this is used by backbone
185 if (array_key_exists('X-HTTP-Method-Override', $headers)) {
186 return $headers ['X-HTTP-Method-Override'];
189 return array_key_exists('REQUEST_METHOD', $_SERVER) ? $_SERVER ['REQUEST_METHOD'] : '';
193 * Return all request headers using the best method available for the server environment
195 * @return array
197 public static function GetRequestHeaders()
199 if (function_exists('getallheaders')) {
200 return getallheaders();
203 $headers = array ();
204 foreach ($_SERVER as $k => $v) {
205 if (substr($k, 0, 5) == "HTTP_") {
206 $k = str_replace('_', ' ', substr($k, 5));
207 $k = str_replace(' ', '-', ucwords(strtolower($k)));
208 $headers [$k] = $v;
212 return $headers;
216 * Returns the body/payload of a request.
217 * this is cached so that this method
218 * may be called multiple times.
220 * Note: if this is a PUT request and the body is not returning data, then
221 * you must look in other code an libraries that may read from php://input,
222 * which can only be read one time for PUT requests
224 * @return string
226 public static function GetBody()
228 if (! self::$bodyCacheIsReady) {
229 self::$bodyCache = @file_get_contents('php://input');
230 self::$bodyCacheIsReady = true;
233 return self::$bodyCache;
237 * Used primarily for unit testing.
238 * Set the contents of the request body
240 * @param string $contents
242 public static function SetBody($contents)
244 self::$bodyCache = $contents;
245 self::$bodyCacheIsReady = true;
249 * Return the HTTP headers sent along with the request.
250 * This will attempt
251 * to use apache_request_headers if available in the environment, otherwise
252 * will manually build the headers using $_SERVER superglobal
254 * @return array
256 public static function GetHeaders()
258 $headers = false;
260 if (function_exists('apache_request_headers')) {
261 $headers = apache_request_headers();
264 if ($headers === false) {
265 // apache_request_headers is not supported in this environment
267 $headers = array ();
268 foreach ($_SERVER as $key => $value) {
269 if (substr($key, 0, 5) != 'HTTP_') {
270 continue;
273 $header = str_replace(' ', '-', ucwords(str_replace('_', ' ', strtolower(substr($key, 5)))));
274 $headers [$header] = $value;
278 return $headers;
282 * Returns the full URL of the PHP page that is currently executing
284 * @param bool $include_querystring
285 * (optional) Specify true/false to include querystring. Default is true.
286 * @param bool $append_post_vars
287 * true to append post variables to the querystring as GET parameters Default is false
288 * @return string URL
290 public static function GetCurrentURL($include_querystring = true, $append_post_vars = false)
292 if (!empty($_SERVER['HTTP_X_FORWARDED_PROTO'])) {
293 $server_protocol = $_SERVER['HTTP_X_FORWARDED_PROTO'];
294 } else {
295 $server_protocol = isset($_SERVER ["SERVER_PROTOCOL"]) ? $_SERVER ["SERVER_PROTOCOL"] : "";
298 $http_host = isset($_SERVER ["HTTP_HOST"]) ? $_SERVER ["HTTP_HOST"] : "";
299 $server_port = isset($_SERVER ["SERVER_PORT"]) ? $_SERVER ["SERVER_PORT"] : "";
301 $protocol = substr($server_protocol, 0, strpos($server_protocol, "/")) . (self::IsSSL() ? "S" : "");
302 $port = "";
304 $domainport = explode(":", $http_host);
305 $domain = $domainport [0];
308 $port = (isset($domainport [1])) ? $domainport [1] : $server_port;
310 // ports 80 and 443 are generally not included in the url
311 $port = ($port == "" || $port == "80" || $port == "443") ? "" : (":" . $port);
313 if (isset($_SERVER ['REQUEST_URI'])) {
314 // REQUEST_URI is more accurate but isn't always defined on windows
315 // in particular for the format http://www.domain.com/?var=val
316 $pq = explode("?", $_SERVER ['REQUEST_URI'], 2);
317 $path = $pq [0];
318 $qs = isset($pq [1]) ? "?" . $pq [1] : "";
319 } else {
320 // otherwise use SCRIPT_NAME & QUERY_STRING
321 $path = isset($_SERVER ['SCRIPT_NAME']) ? $_SERVER ['SCRIPT_NAME'] : "";
322 $qs = isset($_SERVER ['QUERY_STRING']) ? "?" . $_SERVER ['QUERY_STRING'] : "";
325 // if we also want the post variables appended we can get them as a querystring from php://input
326 if ($append_post_vars && isset($_POST)) {
327 $post = self::GetBody();
328 $qs .= $qs ? "&$post" : "?$post";
331 $url = strtolower($protocol) . "://" . $domain . $port . $path . ($include_querystring ? $qs : "");
333 return $url;
337 * Returns a form upload as a FileUpload object.
338 * This function throws an exeption on fail
339 * with details, so it is recommended to use try/catch when calling this function
341 * @param string $fieldname
342 * name of the html form field
343 * @param bool $b64encode
344 * true to base64encode file data (default false)
345 * @param bool $ignore_empty
346 * true to not throw exception if form fields doesn't contain a file (default false)
347 * @param int $max_kb
348 * maximum size allowed for upload (default unlimited)
349 * @param array $ok_types
350 * if array is provided, only files with those Extensions will be allowed (default all)
351 * @return FileUpload object (or null if $ignore_empty = true and there is no file data)
353 public static function GetFileUpload($fieldname, $ignore_empty = false, $max_kb = 0, $ok_types = null)
355 // make sure there is actually a file upload
356 if (! isset($_FILES [$fieldname])) {
357 // this means the form field wasn't present which is generally an error
358 // however if ignore is specified, then return empty string
359 if ($ignore_empty) {
360 return null;
363 throw new Exception("\$_FILES['" . $fieldname . "'] is empty. Did you forget to add enctype='multipart/form-data' to your form code?");
366 // make sure a file was actually uploaded, otherwise return null
367 if ($_FILES [$fieldname] ['error'] == 4) {
368 return;
371 // get the upload ref
372 $upload = $_FILES [$fieldname];
374 // make sure there were no errors during upload, but ignore case where
375 if ($upload ['error']) {
376 $error_codes [0] = "The file uploaded with success.";
377 $error_codes [1] = "The uploaded file exceeds the upload_max_filesize directive in php.ini.";
378 $error_codes [2] = "The uploaded file exceeds the MAX_FILE_SIZE directive that was specified in the html form.";
379 $error_codes [3] = "The uploaded file was only partially uploaded.";
380 $error_codes [4] = "No file was uploaded.";
381 throw new Exception("Error uploading file: " . $error_codes [$upload ['error']]);
384 // backwards compatibility
385 if (self::$TestMode) {
386 self::$VALIDATE_FILE_UPLOAD = false;
389 // make sure this is a legit file request
390 if (self::$VALIDATE_FILE_UPLOAD && is_uploaded_file($upload ['tmp_name']) == false) {
391 throw new Exception("Unable to access this upload: " . $fieldname);
394 // get the filename and Extension
395 $tmp_path = $upload ['tmp_name'];
396 $info = pathinfo($upload ['name']);
398 require_once("FileUpload.php");
399 $fupload = new FileUpload();
400 $fupload->Name = $info ['basename'];
401 $fupload->Size = $upload ['size'];
402 $fupload->Type = $upload ['type'];
403 $fupload->Extension = strtolower($info ['extension']);
405 if ($ok_types && ! in_array($fupload->Extension, $ok_types)) {
406 throw new Exception("The file '" . htmlentities($fupload->Name) . "' is not a type that is allowed. Allowed file types are: " . (implode(", ", $ok_types)) . ".");
409 if ($max_kb && ($fupload->Size / 1024) > $max_kb) {
410 throw new Exception("The file '" . htmlentities($fupload->Name) . "' is to large. Maximum allowed size is " . number_format($max_kb / 1024, 2) . "Mb");
413 // open the file and read the entire contents
414 $fh = fopen($tmp_path, "r");
415 $fupload->Data = fread($fh, filesize($tmp_path));
416 fclose($fh);
418 return $fupload;
422 * Returns a form upload as an xml document with the file data base64 encoded.
423 * suitable for storing in a clob or blob
425 * @param string $fieldname
426 * name of the html form field
427 * @param bool $b64encode
428 * true to base64encode file data (default true)
429 * @param bool $ignore_empty
430 * true to not throw exception if form fields doesn't contain a file (default false)
431 * @param int $max_kb
432 * maximum size allowed for upload (default unlimited)
433 * @param array $ok_types
434 * if array is provided, only files with those Extensions will be allowed (default all)
435 * @return string or null
437 public static function GetFile($fieldname, $b64encode = true, $ignore_empty = false, $max_kb = 0, $ok_types = null)
439 $fupload = self::GetFileUpload($fieldname, $ignore_empty, $max_kb, $ok_types);
440 return ($fupload) ? $fupload->ToXML($b64encode) : null;
444 * Sets a value as if it was sent from the browser - primarily used for unit testing
446 * @param string $key
447 * @param variant $val
449 public static function Set($key, $val)
451 $_REQUEST [$key] = $val;
455 * Clears all browser input - primarily used for unit testing
457 public static function ClearAll()
459 $_REQUEST = array ();
460 $_FILES = array ();
462 self::$bodyCache = "";
463 self::$bodyCacheIsReady = false;
467 * Returns a form parameter as a string, handles null values.
468 * Note that if
469 * $ENCODE_NON_ASCII = true then the value will be passed through VerySimpleStringUtil::EncodeToHTML
470 * before being returned.
472 * If the form field is a multi-value type (checkbox, etc) then an array may be returned
474 * @param string $fieldname
475 * @param string $default
476 * value returned if $_REQUEST[$fieldname] is blank or null (default = empty string)
477 * @param bool $escape
478 * if true htmlspecialchars($val) is returned (default = false)
479 * @param bool $ignorecase
480 * if true then request fieldname will not be case sensitive (default = false)
481 * @return string | array
483 public static function Get($fieldname, $default = "", $escape = false, $ignorecase = false)
485 $val = null;
487 if ($ignorecase) {
488 $_REQUEST_LOWER = array_change_key_case($_REQUEST, CASE_LOWER);
489 $val = (isset($_REQUEST_LOWER [strtolower($fieldname)]) && $_REQUEST_LOWER [strtolower($fieldname)] != "") ? $_REQUEST_LOWER [strtolower($fieldname)] : $default;
490 } else {
491 $val = (isset($_REQUEST [$fieldname]) && $_REQUEST [$fieldname] != "") ? $_REQUEST [$fieldname] : $default;
494 if ($escape) {
495 $val = htmlspecialchars($val, ENT_COMPAT, null, false);
498 if (self::$ENCODE_NON_ASCII) {
499 require_once("verysimple/String/VerySimpleStringUtil.php");
501 if (is_array($val)) {
502 foreach ($val as $k => $v) {
503 $val [$k] = VerySimpleStringUtil::EncodeToHTML($v);
505 } else {
506 $val = VerySimpleStringUtil::EncodeToHTML($val);
510 return $val;
514 * Returns true if the given form field has non-ascii characters
516 * @param string $fieldname
517 * @return bool
519 public static function HasNonAsciiChars($fieldname)
521 require_once("verysimple/String/VerySimpleStringUtil.php");
523 $val = isset($_REQUEST [$fieldname]) ? $_REQUEST [$fieldname] : '';
524 return VerySimpleStringUtil::EncodeToHTML($val) != $val;
528 * Returns a form parameter and persists it in the session.
529 * If the form parameter was not passed
530 * again, then it returns the session value. if the session value doesn't exist, then it returns
531 * the default setting
533 * @param string $fieldname
534 * @param string $default
535 * @return string
537 public static function GetPersisted($fieldname, $default = "", $escape = false)
539 if (isset($_REQUEST [$fieldname])) {
540 $_SESSION ["_PERSISTED_" . $fieldname] = self::Get($fieldname, $default, $escape);
543 if (! isset($_SESSION ["_PERSISTED_" . $fieldname])) {
544 $_SESSION ["_PERSISTED_" . $fieldname] = $default;
547 return $_SESSION ["_PERSISTED_" . $fieldname];
551 * Returns a form parameter as a date formatted for mysql YYYY-MM-DD,
552 * expects some type of date format.
553 * if default value is not provided,
554 * will return today. if default value is empty string "" will return
555 * empty string.
557 * @param string $fieldname
558 * @param string $default
559 * default value = today
560 * @param bool $includetime
561 * whether to include the time in addition to date
562 * @return string
564 public static function GetAsDate($fieldname, $default = "date('Y-m-d')", $includetime = false)
566 $returnVal = self::Get($fieldname, $default);
568 if ($returnVal == "date('Y-m-d')") {
569 return date('Y-m-d');
570 } elseif ($returnVal == "date('Y-m-d H:i:s')") {
571 return date('Y-m-d H:i:s');
572 } elseif ($returnVal == "") {
573 return "";
574 } else {
575 if ($includetime) {
576 if (self::Get($fieldname . "Hour")) {
577 $hour = self::Get($fieldname . "Hour", date("H"));
578 $minute = self::Get($fieldname . "Minute", date("i"));
579 $ampm = self::Get($fieldname . "AMPM", "AM");
581 if ($ampm == "PM") {
582 $hour = ($hour * 1) + 12;
585 $returnVal .= " " . $hour . ":" . $minute . ":" . "00";
588 return date("Y-m-d H:i:s", strtotime($returnVal));
589 } else {
590 return date("Y-m-d", strtotime($returnVal));
596 * Returns a form parameter as a date formatted for mysql YYYY-MM-DD HH:MM:SS,
597 * expects some type of date format.
598 * if default value is not provided,
599 * will return now. if default value is empty string "" will return
600 * empty string.
602 * @param string $fieldname
603 * @param string $default
604 * default value = today
605 * @return string
607 public static function GetAsDateTime($fieldname, $default = "date('Y-m-d H:i:s')")
609 return self::GetAsDate($fieldname, $default, true);
613 * Returns a form parameter minus currency symbols
615 * @param string $fieldname
616 * @return string
618 public static function GetCurrency($fieldname)
620 return str_replace(array (
621 ',',
623 ), '', self::Get($fieldname));